有关不平衡学习与SMOTE算法

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

因为最近的任务中运用到了Smote算法,但是我找了网上好多帖子都没有解决问题,因此去阅读了imblearn库的User guide。然后在这边写下所得到的知识以及掌握了的算法,可以供大家学习与参考。还有感觉在网上查到的帖子很多SMOTE算法都只是用于二分类任务的,但是尝试之后发现是可以用于多分类任务的,但是所带的特征要对应。

一、有关上采样和Smote算法?

**

1、上采样

**
按照我的理解来讲就是,因为在我的不平衡数据集中,有一类样本比较少,有一类样本多,就想办法把少类的样本增多就可。最简单的做法就是通过随机抽样和替换当前可用样本来生成新样本。

from sklearn.datasets import make_classification
from collections import Counter
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
                           n_redundant=0, n_repeated=0, n_classes=3,
                           n_clusters_per_class=1,
                           weights=[0.01, 0.05, 0.94],
                           class_sep=0.8, random_state=0)
from imblearn.over_sampling import RandomOverSampler
ros = RandomOverSampler(random_state=0)
print("采样之前的样本个数为:")
print(sorted(Counter(y).items()))
X_resampled, y_resampled = ros.fit_resample(X, y)
print("采样之后的样本个数为:")
print(sorted(Counter(y_resampled).items()))

采样之前的样本个数为:
[(0, 64), (1, 262), (2, 4674)]
采样之后的样本个数为:
[(0, 4674), (1, 4674), (2, 4674)]

这是从官网截取下来的代码,这里可以看到,总共是需要一个X,一个y。这时候我们就会在想X,和y到底是什么。然后我就试着输出了一下。
在这里插入图片描述
X就是一个二维列表,应该是样本的特征,而y就是样本具体的值了,这个生成的数据集中共有三类,包括2、1、0。但是可以看出2是多数类,0比较少。而上采样的做法就是生成了很多0类和1类使之与多数的2类样本个数一样。
在这里插入图片描述
此外,值得一提的是,在imblearn库所提供的RandomOverSampling也支持对于异构数据进行采样(例如,包含一些字符串)

import numpy as np
X_hetero = np.array([['xxx', 1, 1.0], ['yyy', 2, 2.0], ['zzz', 3, 3.0]],
                    dtype=object)
y_hetero = np.array([0, 0, 1])
X_resampled, y_resampled = ros.fit_resample(X_hetero, y_hetero)
print(X_resampled)
print(y_resampled)

输出的结果为:

[['xxx' 1 1.0]
 ['yyy' 2 2.0]
 ['zzz' 3 3.0]
 ['zzz' 3 3.0]]
[0 0 1 1]

这给我们的启示就是,在使用RandomOverSampling的时候其实X是不必进行编码的,可以是异构数据。y与之对应的就是我们数据集中类型id,可以依据类型id所做复制。这给我们带来了很大的方便啊啊啊!!因为我之前所输入的X想了好久还进行了编码处理。

2、SMOTE算法

SMOTE算法是现在非常流行的一种上采样的方法。使用RandomOverSampling方法是复制,而SMOTE 和 ADASYN 通过插值生成新样本。因为现在暂时只是在使用SMOTE算法,所以就先不介绍ADASYN算法惹,之后用到再进行补充。下面用的也是生成的数据,然后生成的是三类,控制了样本比例。值得注意的是,如果是多分类任务,想要得到的目标样本数量要使用字典,要不然就会报错。

from sklearn.datasets import make_classification
from collections import Counter
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
                            n_redundant=0, n_repeated=0, n_classes=3,
                            n_clusters_per_class=1,
                           weights=[0.01, 0.05, 0.94],
                            class_sep=0.8, random_state=0)
print("采样之前的样本数为:")
print(Counter(y))
from imblearn.over_sampling import SMOTE
sampling_strategy={0:3000,1:3000,2:4674}
oversampler=SMOTE(sampling_strategy=sampling_strategy,random_state=0,k_neighbors=2,n_jobs=1)

X_resampled, y_resampled = oversampler.fit_resample(X, y)
print("采样后的样本数为:")
print(Counter(y_resampled))

采样之前的样本数为:
Counter({2: 4674, 1: 262, 0: 64})
采样后的样本数为:
Counter({2: 4674, 1: 3000, 0: 3000})

其中 sampling_strategy可以选择以下几种,这是我在其他帖子中看到的:

‘majority’:resample only the majority class; 仅仅重新采样多数类
‘not minority’:resample all classes but the minority class; 重采样所有类别除了少数类
‘not majority’:resample all classes but the majority class; 重采样所有类别除了多数类
‘all’:resample all classes; 重采样所有类别
‘auto’:equivalent to ‘not minority’。 等价于not minority

二、如果是使用真实的数据集(类似文本分类任务?)

我尝试了一下,就是如果是特征值是字符串的话,只有RandomOverSampling可以,SMOTE算法要报错。具体的错误如下。所以我浅浅地认为好像是不行的,但是我如果把SMOTE换成ROS就是可以的。所以我们在处理文本数据的时候应该是要做预处理的。

在这里插入图片描述
预处理我用的是from sklearn.preprocessing import LabelEncoder,来进行标签的编码,应该只是很简单的处理。

for col in ["ID"]:
    le = LabelEncoder()
    le.fit(df[col])
    row = le.transform(df[col])
    df[col] = row + index
    index = max(row) + 1

总结

以上就是今天要讲的内容,本文仅仅简单介绍了RandomOverSampling和SMOTE算法的使用,我也正在探索当中,所以如果哪里有错误,欢迎大家批评指正!!!我们一起交流一起进步!!!之后如果学到更多的,我会继续跟进的!!

参考

https://www.jianshu.com/p/3eac447b7261

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>