1b1cc990516dca340836425ab52affc9.png

关于不平衡数据的处理,相关文献数不胜数,几乎大同小异,其中本人比较推荐 @机器之心 与 @刘芷宁的两篇文章。

机器之心:机器学习中如何处理不平衡数据?​zhuanlan.zhihu.com
646595d19122ad97f84390450578e94c.png
刘芷宁:极端类别不平衡数据下的分类问题S02:问题概述,模型选择及人生经验​zhuanlan.zhihu.com
92e875dccc8a61c9c52e391816cb55a3.png

在此基础上,本文试图回答以下三个工作中遇到的问题,以供参考。

1. 重采样与代价敏感学习作用在数据集上的表现如何
2. 先划分训练-测试集还是先进行重采样
3. 面对不平衡数据,如何显著提升模型的表现

一、重采样与代价敏感学习

重采样,顾名思义即重新进行采样,它通过减少多数类样本或者增加少数类样本的方式,来直接改变原始数据的分布,强制数据从不平衡转为平衡。其中,SMOTE算法合成数据也是一种特殊的过采样方法;代价敏感学习的核心思想是基于成本的分类,它赋予少数类更高的权重,使得分错少数类的代价更高,从而在追求整体代价最小的目标下,学习器就必定偏向于尽可能将少数类划分正确。

本文基于仿真数据,对重采样与代价敏感学习两类方法进行可视化实验分析。为此我们考虑一个两变量二分类问题,假设我们有两个类:C0 与C1,其中 C0 的点遵循均值为[1.4, 0]、协方差矩阵为[[0.3, 0], [0, 0.3]]的二维高斯分布;C1 的点遵循均值为[0, 0]、协方差矩阵为[[0.5, 0], [0.5, 1]]的二维高斯分布。并假设数据集中1/6的点来自C0,其余5/6来自C1。下图是包含120个点的数据集按照上述假设的理论分布情况:

b2d372607b1aa04168af88479fb45259.png
图1. 二维数据分布
import numpy as np
np.random.seed(2)
mean = [0, 0]
cov = [[0.5, 0], [0.5, 1]] 
mean2 = [1.4, 0]
cov2 = [[0.3, 0], [0, 0.3]] 
import matplotlib.pyplot as plt
x, y = np.random.multivariate_normal(mean, cov,100).T
x2, y2 = np.random.multivariate_normal(mean2, cov2,20).T
plt.plot(x, y, 'x')
plt.plot(x2, y2, 'x')
plt.axis('equal')
# plt.show()

欠采样

欠采样是重采样的方法之一。对上述仿真数据,直接使用sklearn中初始化的LR(clf = LogisticRegression())进行拟合,下面三幅图分别是原数据、多数类欠采样至60个样本与多数类欠采样至20个样本时的分类结果。

6bb2a5d8bc7c6f7e0e014f116b297f58.png
图2. 原始数据分类结果

3ff05bdbcb5a867135e388142ef33100.png
图3. 降采样至3:1分类结果

478cc832b805d30b6fb3fb7e0ccb343f.png
图4. 降采样至1:1分类结果

类加权

代价敏感学习最常见的实现方式便是对各类别赋予不同的权重。下面利用sklearn中LR模型的class_weight参数来进行相关实验(clf = LogisticRegression(class_weight={0:x, 1:y})),结果如下所示。

a1bf92a503762f8e56e8e896c1bb70a6.png
图5. class_weight={0:0.5, 1:0.5}分类结果,与图2近乎一致

f8d0920e22c7f3a3b829f36d4a5a2a80.png
图6. class_weight={0:0.6, 1:0.4}分类结果

3631a85caf7f6de81a02fda704afbc7f.png
图7. class_weight={0:0.7, 1:0.3}分类结果

edc4e8cd42a24617c05e9a2a4ba555e2.png
图8. class_weight={0:0.833, 1:0.166}分类结果

76a9d02a89be93c4a1d848eba98ba6ad.png
图9. class_weight=banlanced分类结果,与图8近乎一致

e2066ae4357db1c7a841b2ed667e243f.png
图10. class_weight={0:0.96, 1:0.04}分类结果

对于上述实验结果,总结如下:

  1. 随着欠采样程度的加剧,少数类被分对的个数越来越多,分割超平面(图中直线)发生明显变动,但欠采样具有随机性,因此分割超平面的变动一般不会有明显规律;同样地,类加权的处理方法在类别权重改变时,分割超平面也随之变动,但是这种变动不同于欠采样,具有一定的规律:随着少数类权重的增加,分割超平面逐步远离少数类的重心;
  2. 以欠采样方式学得的分类器在未来实际测试数据上得到的准确率甚至比在原数据集上训练的分类器准确率还低,这是因为欠采样只是暂时地在训练集上抹去了一部分样本,而实际上分类器未来要预测的还是与原数据分布一致的实例。同样,类加权的处理方法随着少数类的权重逐渐增大,分类准确率也随之下降。但是不平衡学习问题几乎不以准确率作为评价指标,取而代之的往往是少数类的查全率、模型的排序能力等;
  3. 如图10所示,只要将少数类的权重调得足够大,类加权的处理方法具备使少数类在训练集上的召回率达到100%的潜力,这一点,欠采样是几乎做不到的;但是反过来看,类加权的处理方法是不是更容易学到噪声的特征了呢(导致过拟合);
  4. 类的真实比例对于分类新的点非常重要,而这一信息在重新采样数据集时被丢失了。而代价敏感学习不会破坏原始数据的整体分布,因此它也不会丢失类别比例这样的信息;
  5. 欠采样的比例即使固定,多次实验,结果也未必相同,因为采样具有随机性;但是,类加权的方法只要类别权重固定,结果就不会发生变化。这说明,类加权相较于欠采样,更加稳定;
  6. 欠采样即便看似有诸多的劣势,但它依然是处理不平衡数据最常用的方法之一。它最大的好处是在处理了类别不平衡的同时,还能减少训练样本,加速模型训练(一天训练5次和一天只能训练一次,明显前者更有潜力获得更好的调参结果)。有人肯定会说,机器学习最重要的是样本量,怎么还能删样本?这样的观点好像总是对的,但是,要知道多数类往往提供的信息都很冗余,这就好比在癌症检测场景中,正常人的各项体征都很近似,导致X变量的分布很集中,重叠度很高。只有癌症患者体征(X)才会差异明显。因此,并不是样本越多越好,而是有价值的样本越多才越好,在癌症这样的场景中,无疑患癌样本(少数类)才最有价值;
  7. 当我们审视通过代价敏感学习的方法学得的分类器时,我们应清楚地认识到,该分类器是使当前整体样本“代价”最小的分类器,而不是“准确性”最高。如果事实就是少数类比多数类重要100倍,那么在学得的分类器看来,分错99个多数类样本的代价,也没有分错1个少数类的代价高(宁可错杀一百,不可放过一个,如癌症诊断)。

既然每类方法各有优劣,那“我该选择什么方法处理不平衡数据呢?”,下面就以上两类方法,给出一种通用的处理思路:

不论是做机器学习的科研还是企业应用,其中一个重要套路是综合多种方法,来取得一个较优的结果。既然任何一类处理不平衡数据的方法都有其优势与不足,因此,何不同时使用重采样与代价敏感学习呢?这样既可以综合两类方法的优势,还可避免单一方法的不足与偏执。如,先进行一定程度的欠采样,将不平衡性从20:1降至5:1,再进行类加权的代价敏感学习。这里,我给的数据只是随便举例,具体降采样多少(参数1),类加权的权重如何(参数2),都可以作为包裹在学习器外的超参数,然后通过诸如网格搜索的方法来寻找二者最优的一组参数值,使得模型效果最理想。

二、先划分数据集还是先采样

首先要明确,训练集的作用是为了学得正负样本的分割超平面,但是数据不平衡,会干扰模型的学习,因此,我们才在训练集上使用“重采样”这样的技术手段;而测试集的本质作用是利用历史样本来检验学得的模型的泛化能力,因此测试集必须要代表未来真实的样本分布,不然就丧失了测试集本身应有的作用。

So,答案显而易见,应该先划分训练测试集,再在训练集上进行重采样,以解决类别不平衡数据怎么"学"的问题。

三、如何显著地提升模型的表现

考虑一个二分类任务场景,类别标记为C0 和 C1,通过统计发现C0与C1的比例为1:5,该任务暂时只发现两个有效特征X1,X2,下图是包含 120 个点的数据集的分布情况,可见当前数据的可分离性相当差。某公司员工老王经过几番折腾,使用了很多不平衡数据处理方法及其他特征工程技术,也没有取得好的成绩。

e1d856c2724cd41754075ab7671545b7.png
图11. 只有X1与X2两个特征时,数据分布表现为混在一起很难分开

一天,公司来了一位牛鼻的工程师小王,他开始接手该项目,通过努力,他发现了另外一个有效特征X3,且该特征与X1,X2很不相关,此时,数据集的分布如下所示:

15e1429ff6cdfeff2af5798256c63780.png
图12. 角度1

350e371a877ad745ea18d8e024d135c5.png
图13. 角度2

由于X3的发现,使得数据的可分离性大大增加,此时很容易通过一个超平面将C0与C1分开。于是乎,小王随便整整,也获得了一个超棒的模型。

下图是在可分离性好的情况下不平衡数据分类结果的一个具体示例(下图展示的数据与上述三维数据无关),易知此时分类器的各项评价指标都会非常棒:

a6ffc38232703753948337d3e75fa183.png
图14. clf = LogisticRegression()

可以说,只要数据的可分离性好,不管是平衡的还是不平衡的,也不论不平衡性多强,都很容易获得好的结果,甚至不管使用什么方法来处理不平衡数据,结果都会很近似。因此,在实际的数据挖掘任务中,特征发现工程(特征提取/变量挖掘)才是重中之重。

**题外话**:很多同志总认为模型效果不好,肯定是“技术上”或者“方法上”没有尽善尽美。其实我认为最关键的还是对任务的理解不到位(脱离业务的数据毫无意义),没有形成独到的洞见,“想不到”可用的有效变量。我曾经也奉行“技术至上”的信条,也实践过很多处理不平衡数据的方法,但是最终的结果都差不多。所谓条条大路通罗马,不要太纠结什么独到的妙方,只要你上道并保证方向不错就好,何必太在意走哪条道呢。但是,对新方法保持一种好奇心并尝试去探索实践也是很重要的,指不定哪天会突发奇效呢?

四、总结:

  1. 处理不平衡数据的方法很多,要真正了解某个方法,需要在数据集上做一些可视化的实验;
  2. 每种方法都有自己的优势与不足,为了取得一个较优的结果,可以尝试一种通用的处理策略:综合使用几种熟悉且可靠的方法,并将这些方法的参数作为包裹在学习器之外的超参数;
  3. 如果要使用重采样的方法,请务必先划分数据集,再在训练集上进行重采样,不然你的测试结果告诉你的都是错误的结论;
  4. 在实际数据挖掘任务中,获得好的模型的王道还是努力理解业务,发掘有效的独立变量。

附:一种通用的处理不平衡数据算法的实现

Treers/MetaCost​github.com
16cf08c29b48700fbae5bbb7012ba131.png

更多推荐