Python 学习中的不平衡

Python 学习中的不平衡,python,scikit-learn,Python,Scikit Learn,我在Python程序中使用scikit learn来执行一些机器学习操作。问题是我的数据集存在严重的不平衡问题 有人熟悉scikit learn或python中的不平衡解决方案吗?在Java中有SMOTE mechanizm。python中有类似的东西吗?SMOTE在scikit learn中不是内置的,但仍然有在线可用的实现 编辑:与SMOTE实现的讨论 链接到,似乎不再可用。代码被保留 下面@nos给出的较新答案也很好。在Scikit learn中,有一些不平衡校正技术,这些技术根据您使用的

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


有人熟悉scikit learn或python中的不平衡解决方案吗?在Java中有SMOTE mechanizm。python中有类似的东西吗?

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

编辑:与SMOTE实现的讨论 链接到,似乎不再可用。代码被保留


下面@nos给出的较新答案也很好。

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

其中一些参数,如or,具有
class\u-weight
参数。如果在
'auto'
上设置此参数来实例化一个
SVC
,它将根据其频率的倒数按比例加权每个类示例


不幸的是,没有一个预处理器工具可以达到这个目的。

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


这里有一个新的

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

  • 抽样不足的多数群体
  • 对少数民族阶级的过度抽样
  • 结合过采样和欠采样
  • 创建整体平衡集

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

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

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

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

注意:不要在完整数据集上使用SMOTE,这一点至关重要。您必须仅在训练集上使用SMOTE(拆分后)。然后在您的val/测试集上进行验证,并查看您的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))

您可以尝试过采样/欠采样来平衡数据集。当然,这是一种通用的机器学习方法,并不特定于Python和scikit学习。事实上,这个问题在这里可能是离题的。也许这更适合统计数据。我知道这个话题很老,但我只是补充一点建议。对于不平衡数据集,除了过采样/欠采样和使用class_权重参数外,您还可以降低阈值以对案例进行分类。预测概率(而不是类)并尝试使用小于0.5的阈值。当然,这不会提高分类器的性能,这只是精度和召回率之间的折衷。斯特吉奥斯,你如何准确地调整阈值?任何对python代码的引用都可以做到这一点吗?仅从代码来看,它包含
TODO
s。这个实现正确吗?代码正确,我刚刚测试过。
TODO
是一个特例,它忽略了如下内容:
T=T[np.random.choice(range(len(T)),N)]
。但是保持这条线
N=100
!我曾尝试在极不平衡的数据中使用class weight='auto',但我没有看到性能上的太大差异,这正常吗?@KubiK888您是否使用相同的X进行测试和验证?您使用的测量方法是什么?不,测试集和训练集是完全分开的。现在此参数称为
class\u weight='balanced'
。这是应该遵循的答案,请相信此参数,而不是标记为正确的参数。著名的图书馆,收到了大量的反馈和良好的维护。@Noki:记录在案,我接受的答案比这个早了三年多。它也比第一次承诺使用scikit learn contrib/Inbalanced learn早了大约一年半。我想这就是OP接受它的原因。但我同意,这是2020年最有用的答案。@Junuxx是的,你是对的。那时候是你帮忙的!看起来你在分割之前对整个数据集应用了smote。嘿,谢谢你的反馈erick。我没有在整个数据集上使用smote,但我更新了变量以包含“train”,所以没有混淆。