机器学习超详细实践攻略(11):三板斧干掉样本不均衡问题之1——过(欠)采样

封面图

想象一下,假如今天是你作为数据分析师入职的第一天,老板交给你一个数据分析任务:通过公司已经有的信用卡用户和交易信息,预测用户未来是否会逾期还款。

这个问题看似简单,实则隐藏了一个非常大的坑:据粗略估计,全国的信用卡平均不良率只有不到1%,也就是说,银行贷出100万,可能只有1万没有办法正常收回,这样,如果你拿到一个信用卡还款数据集,很大可能是这个数据集里有99%的正样本,1%的负样本,在预测的时候可能模型对于负样本的特征表现并不敏感。

同样的,这样的场景还有:检测某平台所有交易订单中的欺诈订单(毕竟大多数用户都是正常交易的老实人)、检测银行中的洗钱交易、预测大型企业客户的流失等等。

我们常说的类别不平衡问题,就是数据集中存在某一类样本,其数量远多于或远少于其他类样本,从而导致一些机器学习模型失效的问题。

对于这种情况,在机器学习界,只要祭出三板斧,就可以解决绝大部分的数据不平衡问题,让你的模型所向披靡,预测能力取得一个质的飞跃。这三板斧分别是:过采样(欠采样)、对不同类样本设置不同的惩罚权重、集成学习中的bagging方法。下面,我们首先学习第一大绝招:过采样(欠采样)的原理和实现。

无论是过采样还是欠采样,无非就是两种思路:一是补,给样本量少的那个类别增加样本量;二是删,删掉一部分样本量多的类别。最终达到每个类别的样本数量平衡的目的。

一、过采样(over-sampling)

又称上采样。过采样继承了“补”的思路,通过增加分类中少数类样本的数量来实现样本均衡。过采样最直接的方法就是将少数类的样本多复制几份。但是这种方法的缺点是:如果样本特征太少,这些重复的样本就可能导致过拟合的问题。一般情况下,我们不是简单复制几份,而是在复制的同时加一些随机噪声、干扰数据等,防止模型过拟合。

另一种解决方法就是通过特定的算法合成新的样本。

其实这些算法执行流程并没有那么难理解,算法实现起来也并不是很难。以典型的过采样算法smote算法为例,算法流程如下:

假设有两个class:class1 和 class2 ,其中class1样本数少。
步骤1:从class1中随机选择一个点C,找到该点的K个邻居
步骤2:从K个邻居中随机选择一个点C_ne
步骤3:连接C与C1,在C与C_ne的连线上生成新的点C_new
步骤4:重复1-4 M步骤,可构造M个点

在Python中,处理样本不均衡问题我们需要用到一个包:imbalanced-learn。

首先,安装这个包:pip install imbalanced-learn

我们先用 https://zhuanlan.zhihu.com/p/95412564 中讲的生成数据集的方法生成一个正负样本量不均衡的数据集。

from sklearn import datasets
# 生成
X,Y = datasets.make_classification(n_samples = 20,
                                    n_features = 4,
                                    n_classes = 2,
                                    weights = [0.3,0.7])

print(X)
print(Y)

输出结果如下:

[[ 1.21706083 1.12986 1.2998324 1.15376352] [ 1.17533636 -1.29561194 -0.28954016 1.00276647] [ 1.50145008 -0.06476093 0.65946499 1.35525496] [-0.69105133 -1.72583842 -1.4398602 -0.70573952] [ 0.52003318 -0.53992062 -0.10653626 0.44523502] [-1.2449438 1.44815687 0.35575841 -1.05861377] [-0.69626765 0.51388754 0.00736094 -0.60588014] [ 0.28817084 2.14562256 1.52336461 0.36087658] [-0.60796446 -0.04013406 -0.30997876 -0.55186576] [-1.50124558 2.42594496 0.86890189 -1.24482048] [ 0.4807009 -0.150123 0.12738589 0.42785389] [ 1.61349955 -1.76329405 -0.38756462 1.37731124] [ 1.52055699 1.23124411 1.50722703 1.43305357] [ 0.18461106 -0.67446852 -0.35030985 0.13551482] [ 1.10954433 1.00010374 1.16562311 1.05044065] [ 0.96242505 2.41142144 2.01037078 0.98324786] [-0.93460516 -1.2828331 -1.2668987 -0.90538419] [ 0.74531935 1.24987676 1.15714557 0.73260898] [ 0.65228896 -0.50904671 -0.02477175 0.56632109] [-0.06905236 -0.20338623 -0.16389815 -0.07196445]]
[1 1 1 0 1 0 1 1 0 0 1 1 1 0 1 1 0 1 1 1]

可以看到生成的标签中,0标签和1标签的比例是3:7。

我们以SMOTE算法作为过采样算法对不均衡样本进行处理:


from imblearn.over_sampling import SMOTE # 导入过采样处理库SMOTE

# 使用SMOTE方法进行过采样处理

smote = SMOTE() # 建立SMOTE模型对象

X_new, Y_new = smote.fit_sample(X, Y) # 输入数据并作过采样处理

print('Y_new:',Y_new)

print('Y_new长度:',len(Y_new))

输出如下:

Y_new: [1 1 1 0 1 0 1 1 0 0 1 1 1 0 1 1 0 1 1 1 0 0 0 0 0 0 0 0]
Y_new长度: 28

可以看到,算法补充了8个0样本,使得0、1类别的比例变成了1:1

除此之外,还有这些过采样函数可以调用:

  • over_sampling.ADASYN()
  • over_sampling.KMeansSMOTE()
  • over_sampling.RandomOverSampler()
  • over_sampling.SMOTE()
  • over_sampling.SMOTENC()
  • over_sampling.SVMSMOTE()

二、欠采样

又称下采样(under-sampling),这是继承了“删”的思路,通过删掉一部分多类样本的数量来实现样本均衡,最直接的方法是随机去掉一些多数类样本来减小多数类的规模。这样做的缺点也很明显,可能删得太过分,把数量多的类别的样本中一些重要的信息也删除掉。

当然,为了避免这种情况,我们也可以采用一些成熟的欠采样算法,我们以RandomUnderSampler为例。


from imblearn.under_sampling import RandomUnderSampler # 导入欠采样处理库Random UnderSampler

# 使用RandomUnderSampler方法进行欠采样处理

RandomUnderSampler = RandomUnderSampler() # 建立RandomUnderSampler模型对象

X_new, Y_new = RandomUnderSampler.fit_sample(X,Y) # 输入数据并进行欠采样处理

print('Y_new:',Y_new)

print('Y_new长度:',len(Y_new))

输出如下:

Y_new: [0 0 0 0 0 0 1 1 1 1 1 1]
Y_new长度: 12

可以看到,算法舍弃了8个1样本,使得0、1类别得比例变成1:1。

不管是欠采样还是过采样,如果想自己决定采样数量,可以添加这个参数:sampling_strategy = {类别:个数}:每个类别得采样个数(在0.6版本以前是ratio参数)。

还有这些欠采样函数可以调用:

  • under_sampling.CondensedNearestNeighbour()
  • under_sampling.EditedNearestNeighbours()
  • under_sampling.RepeatedEditedNearestNeighbours()
  • under_sampling.AllKNN()
  • under_sampling.InstanceHardnessThreshold()
  • under_sampling.NearMiss()
  • under_sampling.NeighbourhoodCleaningRule()
  • under_sampling.OneSidedSelection()
  • under_sampling.RandomUnderSampler()
  • under_sampling.TomekLinks()

总体上,过采样和欠采样更适合大数据分布不均衡的情况,尤其是过采样方法,应用极为广泛。

三、扩展阅读

imbalanced-learn文档链接:https://imbalanced-learn.readthedocs.io/en/stable/api.html

四、本系列相关文章

你可能感兴趣的:(机器学习超详细实践攻略(11):三板斧干掉样本不均衡问题之1——过(欠)采样)