scikit-learn 中的不平衡

Posted

技术标签:

【中文标题】scikit-learn 中的不平衡【英文标题】:Imbalance in scikit-learn 【发布时间】:2013-02-10 12:42:36 【问题描述】:

我在我的 Python 程序中使用 scikit-learn 来执行一些机器学习操作。问题是我的数据集存在严重的不平衡问题。

是否有人熟悉 scikit-learn 或 python 中不平衡的解决方案?在 Java 中有 SMOTE 机制。 python中有没有并行的东西?

【问题讨论】:

您可以尝试过采样/欠采样来平衡数据集。当然,这是一种通用的机器学习方法,并不特定于 Python 和 scikit-learn。事实上,这个问题在这里可能是题外话。也许它更适合统计数据。他们甚至有一个unbalanced-classes tag。 我知道这个话题很老,但我只是添加一条建议。对于不平衡的数据集,除了过采样/欠采样和使用 class_weight 参数外,您还可以降低阈值来对案例进行分类。预测概率(而不是类别)并尝试使用小于 0.5 的阈值。当然,这并不会提高分类器的性能,只是在精度和召回率之间进行权衡。 Stergios,你究竟如何调整阈值?对执行此操作的 python 代码有任何引用吗? 【参考方案1】:

这里有一个新的

https://github.com/scikit-learn-contrib/imbalanced-learn

它包含以下类别的许多算法,包括 SMOTE

对多数类进行欠采样。 过采样少数类。 结合过采样和欠采样。 创建整体平衡集。

【讨论】:

这是应该遵循的答案,相信这个而不是标记为正确的那个。知名图书馆,收到很多反馈和良好的维护。 @Noki:作为记录,我接受的答案比这个答案早了三年多。它还比第一次提交 scikit-learn-contrib/imbalanced-learn 早了大约一年半。我认为这就是OP接受它的原因。但我同意,这是 2020 年最有帮助的答案。 @Junuxx 是的,你是对的。那时你是帮助的人!【参考方案2】:

在 Scikit learn 中有一些不平衡校正技术,这些技术会根据您使用的学习算法而有所不同。

其中一些,例如Svm 或logistic regression,具有class_weight 参数。如果您使用在'balanced' 上设置的此参数来实例化SVC,它将按与其频率的倒数成比例地加权每个类示例。

很遗憾,没有用于此目的的预处理器工具。

【讨论】:

我曾尝试在我极度不平衡的数据中使用 class weight = 'auto',但我没有发现性能有太大差异,这正常吗? @KubiK888 您是否使用相同的 X 进行测试和验证?您使用什么测量方法? 不,测试集和训练集是完全分开的。 现在这个参数叫做class_weight='balanced'【参考方案3】:

我在这里找到了另一个库,它实现了欠采样和多种过采样技术,包括多个 SMOTE 实现和另一个使用 SVM 的库:

A Python Package to Tackle the Curse of Imbalanced Datasets in Machine Learning

【讨论】:

【参考方案4】:

SMOTE 不是 scikit-learn 中的内置程序,但仍然有在线可用的实现。

编辑:我最初在 GMane 上与 SMOTE 实现的讨论 链接到,似乎不再可用。代码保留here。

@nos 下面的较新答案也相当不错。

【讨论】:

只看代码,它包含TODOs。这个实现是否正确? 代码是正确的,我刚测试过。 TODO 是一个特例,它遗漏了如下内容:T = T[np.random.choice(range(len(T)), N)]。但请保持N = 100【参考方案5】:

由于其他人已经列出了非常流行的不平衡学习库的链接,我将概述如何正确使用它以及一些链接。

https://imbalanced-learn.org/en/stable/generated/imblearn.under_sampling.RandomUnderSampler.html

https://imbalanced-learn.org/en/stable/generated/imblearn.over_sampling.RandomOverSampler.html

https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.over_sampling.SMOTE.html

https://imbalanced-learn.readthedocs.io/en/stable/auto_examples/over-sampling/plot_comparison_over_sampling.html#sphx-glr-auto-examples-over-sampling-plot-comparison-over-sampling-py

https://imbalanced-learn.org/en/stable/combine.html

不平衡学习中一些常见的过采样和欠采样技术是 imblearn.over_sampling.RandomOverSampler、imblearn.under_sampling.RandomUnderSampler 和 imblearn.SMOTE。对于这些库,有一个很好的参数允许用户更改采样率。

例如,在 SMOTE 中,要更改比率,您需要输入一个字典,并且所有值都必须大于或等于最大类(因为 SMOTE 是一种过采样技术)。我发现 SMOTE 更适合模型性能的原因可能是因为使用 RandomOverSampler 您正在复制行,这意味着模型可以开始记忆数据而不是泛化到新数据。 SMOTE 使用 K-Nearest-Neighbors 算法生成与采样数据“相似”的数据点。

盲目使用 SMOTE 将比率设置为其默认值(甚至是类平衡)并不是一个好习惯,因为模型可能会过度拟合一个或多个少数类(即使 SMOTE 使用最近邻进行“相似”观察) )。与调整 ML 模型的超参数类似,您将调整 SMOTE 算法的超参数,例如比率和/或 knn。下面是一个如何正确使用 SMOTE 的工作示例。

注意:不要对完整数据集使用 SMOTE,这一点至关重要。您必须仅在训练集上使用 SMOTE(拆分后)。然后在您的验证集/测试集上进行验证,看看您的 SMOTE 模型是否优于其他模型。如果你不这样做,就会出现数据泄露,你的模型本质上就是作弊。

from collections import Counter
from sklearn.preprocessing import MinMaxScaler
from imblearn.pipeline import Pipeline
from imblearn.over_sampling import SMOTE
import numpy as np
from xgboost import XGBClassifier
import warnings

warnings.filterwarnings(action='ignore', category=DeprecationWarning)
sm = SMOTE(random_state=0, n_jobs=8, ratio='class1':100, 'class2':100, 'class3':80, 'class4':60, 'class5':90)

### Train test split
X_train, X_val, y_train, y_val = train_test_split(X, y)

### Scale the data before applying SMOTE
scaler = MinMaxScaler().fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_val_scaled = scaler.transform(X_val)

### Resample X_train_scaled
X_train_resampled, y_train_resampled = sm.fit_sample(X_train_scaled, y_train)

print('Original dataset shape:', Counter(y_train))
print('Resampled dataset shape:', Counter(y_train_resampled))

### Train a model
xgbc_smote = XGBClassifier(n_jobs=8).fit(X_train_smote, y_train_smote,
                                         eval_set = [(X_val_scaled, y_val)],
                                         early_stopping_rounds=10)

### Evaluate the model
print('\ntrain\n')
print(accuracy_score(xgbc_smote.predict(np.array(X_train_scaled)), y_train))
print(f1_score(xgbc_smote.predict(np.array(X_train_scaled)), y_train))

print('\nval\n')
print(accuracy_score(xgbc_smote.predict(np.array(X_val_scaled)), y_val))
print(f1_score(xgbc_smote.predict(np.array(X_val_scaled)), y_val))

【讨论】:

看起来您在拆分之前对整个数据集应用了 smote。 嘿,感谢埃里克的反馈。我没有在整个数据集上使用应用 smote,但我更新了变量以包含“train”,所以没有混淆。

以上是关于scikit-learn 中的不平衡的主要内容,如果未能解决你的问题,请参考以下文章

需要帮助将 scikit-learn 应用于这个不平衡的文本分类任务

在 scikit-learn 中处理不平衡测试集的最佳方法

如何使用 scikit-learn 和 matplotlib 为不平衡数据集绘制 SVC 分类?

F1 小于 Scikit-learn 中的精度和召回率

sample_weight 与 scikit-learn 中的 class_weight 相比如何?

scikit-learn:随机森林 class_weight 和 sample_weight 参数