对NaN值使用SMOTE

时间:2019-08-12 06:22:27

标签: missing-data smote imbalanced-data

有没有一种方法可以将SMOTE与NaN一起使用?

这是在NaN值存在的情况下尝试使用SMOTE的虚拟程序

# Imports
from collections import Counter
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.preprocessing import Imputer
from imblearn.over_sampling import SMOTE
from imblearn.pipeline import make_pipeline
from imblearn.combine import SMOTEENN

# Load data
bc = load_breast_cancer()
X, y = bc.data, bc.target

# Initial number of samples per class
print('Number of samples for both classes: {} and {}.'.format(*Counter(y).values()))

# SMOTEd class distribution
print('Dataset has %s missing values.' % np.isnan(X).sum())
_, y_resampled = SMOTE().fit_sample(X, y)
print('Number of samples for both classes: {} and {}.'.format(*Counter(y_resampled).values()))

# Generate artificial missing values
X[X > 1.0] = np.nan
print('Dataset has %s missing values.' % np.isnan(X).sum())
#_, y_resampled = make_pipeline(Imputer(), SMOTE()).fit_sample(X, y)


sm = SMOTE(ratio = 'auto',k_neighbors = 5, n_jobs = -1)
smote_enn = SMOTEENN(smote = sm)

x_train_res, y_train_res = smote_enn.fit_sample(X, y)

print('Number of samples for both classes: {} and {}.'.format(*Counter(y_resampled).values()))

我得到以下输出/错误:

Number of samples for both classes: 212 and 357.
Dataset has 0 missing values.
Number of samples for both classes: 357 and 357.
Dataset has 6051 missing values.

ValueError: Input contains NaN, infinity or a value too large for dtype('float64').

2 个答案:

答案 0 :(得分:0)

通常不,SMOTE正在准备数据集以进行进一步的模型拟合。

常规模型(例如随机森林等)不适用于label变量中的NA,因为您实际上在这里预测什么?对于NA的预测变量也是如此,其中大多数算法要么不起作用,要么只是忽略NA的情况。

因此,错误很大程度上是设计使然,因为您不能也不应该在算法的训练数据集中缺少值,并且从逻辑上讲,您不希望“平衡”具有缺失值的案例,而只想通过有效标签。

如果您认为丢失的标签仍然代表应该平衡的有效信息(例如,您实际上想对NA类进行过采样,因为您认为该类未提供足够的信息),那么它应该不是丢失的值,而应该是定义的值称为“未知”或其他值,表示具有“ NA”特征的已知类,但是我真的没有看到任何有意义的研究问题。

更新1:

另一种方法是首先估算缺失值,这样您实际上就可以通过三个步骤来拟合模型:

  1. 输入缺失值(使用MICE或类似方法)
  2. SMOTE以平衡训练集
  3. 适合的算法/模型

答案 1 :(得分:0)

您已经包含了答案。注意,使用fit_resample代替fit_sample。您应按以下方式使用make_pipeline

# Imports
import numpy as np
from collections import Counter
from sklearn.datasets import load_breast_cancer
from sklearn.impute import SimpleImputer
from imblearn.over_sampling import SMOTE
from imblearn.pipeline import make_pipeline
from imblearn.combine import SMOTEENN

# Load data
bc = load_breast_cancer()
X, y = bc.data, bc.target
X[X > 1.0] = np.nan

# Over-sampling 
smote = SMOTE(ratio='auto',k_neighbors=5, n_jobs=-1)
smote_enn = make_pipeline(SimpleImputer(), SMOTEENN(smote=smote))
_, y_res = smote_enn.fit_resample(X, y)

# Class distribution
print('Number of samples for both classes: {} and {}.'.format(*Counter(y_res).values()))

还要检查您的学习失衡版本。