为什么从多数类中删除具有 NA 值的行会提高模型性能

数据挖掘 Python 熊猫 阶级失衡 缺失数据 打击
2021-09-15 15:52:44

我有一个不平衡的数据集,如下所示:

df['y'].value_counts(normalize=True) * 100
No     92.769441
Yes     7.230559
Name: y, dtype: float64

该数据集由 13194 行和 37 个特征组成。

我已经尝试过无数次尝试通过过采样和欠采样来平衡数据、用于异常值检测的一类 SVM、使用不同的分数、超参数调整等来提高模型的性能。其中一些方法略微提高了性能,但不如就像我想的那样:

应用 RandomUnderSampling:


from imblearn.under_sampling import RandomUnderSampler
rus = RandomUnderSampler(random_state=42)
X_train_rus, y_train_rus = rus.fit_resample(X_train, y_train)

# Define and fit AdaBoost classifier using undersampled data 
ada_rus = AdaBoostClassifier(n_estimators=100, random_state=42)
ada_rus.fit(X_train_rus,y_train_rus)
y_pred_rus = ada_rus.predict(X_test) 

evaluate_model(y_test, y_pred_rus)

在此处输入图像描述

使用 SMOTE 等过采样技术:


# SMOTE
from imblearn.over_sampling import SMOTE

# upsample minority class using SMOTE
sm = SMOTE(random_state=42)
X_train_sm, y_train_sm = sm.fit_sample(X_train, y_train)

# Define and fit AdaBoost classifier using upsample data 
ada_sm = AdaBoostClassifier(n_estimators=100, random_state=42)
ada_sm.fit(X_train_sm,y_train_sm)
y_pred_sm = ada_sm.predict(X_test) 

# compare predicted outcome through AdaBoost upsampled data with real outcome
evaluate_model(y_test, y_pred_sm)

在此处输入图像描述

然后我决定尝试从大多数类的样本中删除缺少数据的行,正如我在一篇文章中看到的那样。我通过增加 pandas dropna 函数中的阈值(thresh)参数逐渐做到了这一点,每次删除更多行时,性能都会提高。最后,我从多数类中删除了所有缺少数据的行,如下所示:

df_majority_droppedRows = df.query("y == 'No'").dropna()
df_minority = df.query("y == 'Yes'")
dfWithDroppedRows = pd.concat([df_majority_droppedRows, df_minority])
print(dfWithDroppedRows.shape)
(1632, 37)

这将我的行数显着减少到 1632 并改变了目标变量中的分布,使得以前的少数类(“是”)现在是多数类:

Yes    58.455882
No     41.544118
Name: y, dtype: float64

测试模型,我发现它表现最好,具有高召回率和精度值。

在此处输入图像描述

所以我的问题是,

  1. 为什么这种方法优于其他过采样和欠采样技术?

  2. 以前的少数类现在是多数类是否可以接受,或者这会导致过度拟合吗?

  3. 为大多数类样本构建一个依赖输入且没有缺失数据的模型是否现实?

编辑

针对@Ben Reiniger 评论中的问题:

  • 我通过使用 KNNImputer 处理数字数据和 SimpleImputer 处理分类数据来处理数据中的缺失值,如下所示:

def preprocess (X):
    # define categorical and numeric transformers
    numeric_transformer = Pipeline(steps=[
        ('knnImputer', KNNImputer(n_neighbors=2, weights="uniform")),
        ('scaler', StandardScaler())])

    categorical_transformer = Pipeline(steps=[
        ('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
        ('onehot', OneHotEncoder(handle_unknown='ignore'))])

    preprocessor = ColumnTransformer(transformers=[
        ('cat', categorical_transformer, selector(dtype_include=['object'])),
        ('num', numeric_transformer, selector(dtype_include=['float64','int64']))
    ])

    X = pd.DataFrame(preprocessor.fit_transform(X))
    return X 
  • 删除行后,我定义了矩阵和目标的特征,预处理然后拆分数据,如下所示:
# make feature matrix and target matrix
X = dfWithDroppedRows.drop(columns=['y'])
y = dfWithDroppedRows['y']

# encode target variable 
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
y = le.fit_transform(y)

# preprocess feature matrix
X=preprocess(X)

# Split data into training and testing data
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, test_size=0.2, random_state=42)
  • 最后,为了计算缺失值在两个类中是否相同分布(最初),我运行了以下
np.count_nonzero(df.query("y == 'No'").isna()) / df.query("y == 'No'").size
0.2791467938526762
np.count_nonzero(df.query("y == 'Yes'").isna()) / df.query("y == 'Yes'").size
0.24488639582979205

所以多数类有大约 28% 的缺失数据,少数类有大约 25% 的缺失数据。

1个回答

您的数据中有两个问题的组合:

  • 不平衡
  • 缺失值

在您的实验中,对于数据的真实分布是(或应该是)存在混淆:“真实数据”是 97% 否,或者“真实数据”是在删除缺失值之后,在这种情况下它几乎是平衡的。根据您要解决的问题来决定这一点非常重要:“在生产中”,模型是否必须为每个实例生成预测,即使它有缺失值?如果是,则真实分布为 97% 否(原始问题)。如果否,则模型仅预测“完整”实例,即许多实例由于缺失值而被丢弃(这种情况在“否”时更常见)。

这是一个关键点,因为无论您以何种方式训练模型,都应该在反映数据真实分布的测试集上对其进行评估。

我会假设你的真正目标是预测每个实例,即你不想忽略实例,即使它们有缺失值。不过,我将尝试解决这两个选项:

  • 选项 A:真实数据为 97% 否。
  • 选项 B:真实数据是 58%。
  1. 为什么这种方法优于其他过采样和欠采样技术?

这两种方法是在两个非常不同的测试集上进行评估的,因此它们之间的性能根本没有可比性。

  • 如果重采样实验对原始数据重采样)进行了正确评估,那么它们为您提供了选项 A 中性能的可靠估计。
  • 如果重采样实验是(错误地)对重采样数据进行评估,那么差异肯定是由于缺失值造成的,因为输入非常大比例的数据会导致大量噪声。在这种情况下,重采样实验对于选项 A(测试集中的错误分布)和 B(测试集中的缺失值)均无效。
  1. 以前的少数类现在是多数类是否可以接受,或者这会导致过度拟合吗?

这取决于您要解决的问题:

  • 对于原始问题“选项A”,不可以修改测试集中的分布。
  • 对于新问题“选项 B”,多数类是“是”。97%“否”的原始数据是无关紧要的。
  1. 为大多数类样本构建一个依赖输入且没有缺失数据的模型是否现实?

这是关于指定您要解决的确切问题,由您决定:)