不平衡数据集:SMOTE 前后的训练/测试拆分

数据挖掘 Python 分类 阶级失衡 过拟合 打击
2021-09-27 09:08:02

这个问题我之前的问题相似但不同我有一个与银行客户流失相关的二元分类任务。该数据集包含 10,000 个实例和 11 个特征。目标变量不平衡(80% 仍然是客户(0),20% 流失(1))。

最初,我采用了这种方法:我首先将数据集拆分为训练集和测试集,同时在两组中保留目标变量的 80-20 比率。我在训练集中保留了 8,000 个实例,在测试集中保留了 2,000 个。预处理后,我用 SMOTEENN 解决了​​训练集中的类不平衡问题:

from imblearn.combine import SMOTEENN

smt = SMOTEENN(random_state=random_state)
X_train, y_train = smt.fit_sample(X_train, y_train)

现在,我的训练集有 4774 个 1 和 4182 个 0。我知道继续构建 ML 模型。我使用 scikit-learn 的 GridSearchCV 和 cv = KFold(n_splits=5, shuffle=True, random_state=random_state) 并根据召回分数进行优化。例如,对于随机森林分类器:

cv = KFold(n_splits=5, shuffle=True, random_state=random_state)
scoring_metric='recall'

rf = RandomForestClassifier(random_state=random_state)
param_grid = {
    'n_estimators': [100],
    'criterion': ['entropy', 'gini'],
    'bootstrap': [True, False],
    'max_depth': [6],
    'max_features': ['auto', 'sqrt'],
    'min_samples_leaf': [2, 3, 5],
    'min_samples_split': [2, 3, 5]
}

rf_clf = GridSearchCV(estimator=rf,
                      param_grid=param_grid,
                      scoring=scoring_metric,
                      cv=cv,
                      verbose=False,
                      n_jobs=-1)

best_rf_clf = rf_clf.fit(X_train, y_train)

y_pred = cross_val_predict(best_rf_clf.best_estimator_,X_train, y_train,cv=cv)
print('Train: ', np.round(recall_score(y_train, y_pred), 3))

y_pred = best_rf_clf.best_estimator_.fit(X_train, y_train).predict(X_test)
print(' Test: ', np.round(recall_score(y_test, y_pred), 3))

我在训练集上的召回 CV 分数是0.902,而在测试中的分数是0.794

但是,当在完整数据集上应用 SMOTEENN 然后拆分为训练集和测试集时,我在训练集上得到的召回 CV 分数等于0.913,而对于测试集则为0.898

我们如何解释这两种方法之间的差异?与第二种方法(SMOTEENN 然后拆分)相比,是什么导致第一种方法(拆分然后 SMOTEENN)中的两组之间存在这种差距?我的猜测是,与第一种方法(1607 1s、393 0s)相比,第二种方法会导致更平衡的测试集(1220 1s、1036 0s)。谢谢!

2个回答

从本质上讲,应用 SMOTE 使模型的工作更容易:SMOTE 生成的人工实例往往具有彼此相同的属性,因此模型更容易捕获它们的模式。然而,这些实例很少是少数类的良好代表性样本,因此模型过度拟合的风险更高。

当然,如果 SMOTE 也应用于测试集,模型似乎表现更好。这相当于将一个困难的问题改为一个更容易的问题,以便更好地回答问题。

重采样方法很少能很好地解决不平衡问题。重要的是要理解不平衡数据只是一个问题,因为训练集中的少数类没有足够的代表性和/或特征对于标签来说不够好。理想的场景是解决这两个问题,然后模型可以在不平衡的情况下表现得非常好。

您必须在拆分为训练和测试之后应用 SMOTE ,而不是之前之前做 SMOTE 是虚假的,违背了拥有单独测试集的目的。

在非常粗略的层面上,SMOTE 本质上复制了一些样本(这是一种简化,但它会给你一个合理的直觉)。如果将每个样本复制十次,然后拆分为训练和测试,那么每个样本大约会出现 5 个副本出现在训练集中,大约 5 个副本出现在测试集中。实际上,测试集或多或少与训练集相同。一个只记住训练集(并对其进行大量过度拟合)的分类器在测试集上也会做得很好——但它在实践中会表现得非常糟糕。

因此,在拆分为训练/测试之前复制样本可以有效地评估您在训练集上的分类器,我们知道这是对其性能的有偏见的衡量。在拆分之前执行 SMOTE 将具有类似的不良属性。