这篇文章翻译至http://www.svds.com/learning-imbalanced-classes/,作者简洁明了地阐述了非平衡数据及解决这类问题的常用方法。其实一些朴素的方法我们自己也能想到,并且也实际使用过一些,比如重采样、调整权值等。然而,我们并没有去做一些归纳。感谢作者帮我们归纳了一些思想朴素但又实际有用的方法。
什么是非平衡数据?
如果你刚开始一门机器学习课程,可能大部分数据集都相当的简单。此外,当你构建分类器时,样本的类别是平衡的,这意味着每个类别有大致相同的样本数。教师通常都采用清理过的数据集作为示例,以让教学专注于具体的算法或技术而不是其他问题。通常,你看到的是如下图所示的二维数据,图中一个点代表一个样本,不同的颜色代表不同的类别:
分类算法的目标是试图学习一条分割线(分类器)来区分这两类点。基于多种数学、统计或者几何假设,有很多方法来达到这个目的。
但是当你面对真实的世界,你注意到的第一问题就是,没有清理的数据存在许多噪声且类别不平衡。真实数据的散点图更像是这样:
主要问题是类别的不平衡:红色点的数量严重少于蓝色的。
研究不平衡类通常认为不平衡意味着少数类只占比10~20%。实际上,一些数据集远比这更不平衡。例如:
1. 每年大约有2%的信用卡账户被欺骗。(大多数欺诈检测领域严重不平衡。)
2. 状态医疗甄别通常在大量不存在此状态的人口中检测极少数有此状态的人(比如美国的HIV携带者仅占0.4%)。
3. 磁盘驱动器故障每年约1%。
4. 网络广告的转化率估计在10-3到10-6之间。
5. 工厂生产故障率通常约0.1%。
这些领域许多问题是不平衡的,我称他们为海底捞针问题,机器学习分类器从大量负类(不感兴趣的)中找到少数正类(感兴趣,或故障)。
当你遇到这样的问题,用标准算法去解决一定会很困难。传统算法往往偏向于多数类,因为他们的损失函数在没考虑数据分布的情况下优化如错误率等量。最坏的情况是,小类别样本会被认为是大类别的异常值而被忽略。学习算法简单的生成一个平凡分类器,将每个样本都分类为大类别。
这种看似病态行为但事实上并不是。事实上,如果你的目标是最大化简单精度(或者等价,最小化错误率),这是一个完全可以接受的解决方案。但是如果我们假设稀有类样本对于分类更重要,那么我们就应更小心、更精细的处理这个问题。
如果你遇到这样的问题,并想要解决他们的实用建议,继续读下去吧。
注意:这篇文章的目的是洞察和关于如何解决这类问题的实际建议。而不是一个教你逐行写代码的编码教程。我用Jupyter Notebooks来实践这些想法,但这篇文章将解释一些基本思想和原则。
处理非平衡数据
非平衡数据学习在机器学习研究中已经活跃了20多年。它作为许多论文、研习班、特别会议和学位论文的主题(最近一项调查大约有220引用)。试用了大量的技术,得到了不同的结果和一些清晰的答案。数据科学家第一次遇到这类问题通常要问,数据非平衡我该怎么做?同样的问题没有确切的答案,一般化问题哪种机器学习算法最好?没有确切的答案:看什么样的数据。
这里有一个实用方法的粗糙大纲。大概排列如下:
什么都不做。有时你比较幸运什么都不用做。你可以在所谓的自然分布的数据上训练,有时它并不需要任何修改。
通过某种方法使训练集平衡:
对稀有类别过采样
对大类别欠采样
对稀有类别合成新数据
扔掉稀有类别样本,转换为一个异常检测框架。
在算法层面,或之后:
调整类权值(误分类cost)
调整决策阈值
修改现有算法让其对稀有类更敏感
构建一个对不平衡数据表现良好的全新算法
题外话:评估注意事项
首先,快速浏览。在谈论怎样训练一个针对不平衡数据的分类器之前,我们需要讨论怎样正确的评估它。这无论怎么强调都不为过。只有当你测量正确的指标,你才会取得进展。
1. 不要用精确度(或错误率)去评估你的分类器。有两个严重的问题。第一,精确度简单的以0.5为阈值来处理二分类,但当数据非平衡时这通常是错的。第二,分类精确度是基于误差的一个简单计数,你应该知道得更多。你应该知道哪些类、在哪儿被混淆。如果你不明白这些点,阅读The Basics of Classifier Evaluation, Part 2可能会有用。你可以用一个ROC曲线,或者一个PR曲线来可视化你的分类器性能。
图 1 ROC曲线
图 2 PR曲线
2. 不要用score和predict从分类器获取硬分类(标签),而应该用proba和predict_proba获取概率估计。
3. 当你获得概率估计后,不要盲目的以0.5为阈值来划分类别。观察性能曲线,来确定将要采样的阈值。早期的论文有许多错误发生就是因为研究人员简单的以0.5截断。
4. 不管你训练什么,总是在自然分布上测试。见
sklearn.cross_validation.StratifiedKFold
5. 你可能不需要概率估计来分类,但是当你需要时,使用校准。见
sklearn.calibration.CalibratedClassifierCV
前面第一幅二维图比单个数字信息更大,但当你需要单个数字指标,其中一个比精确度更可取:
1. The Area Under the ROC curve (AUC) 。
2. F1 Score。
过采样和欠采样
最简单的方法需要处理步骤变化不大,只包括简单的调整样本集直到它们平衡。过采样通过随机重复少类别的样本来增加它的数量。欠采样随机对多类别样本降采样。一些数据科学家(天真的)认为过采样更优越,因为它获得更多的数据,而欠采样扔掉了。但是记住,复制数据不是没有效果—重复的数据使变量具有更低的变化。积极的结果是重复了误差的数量:如果一个分类器使原来假阴的少类别数据再重复5次,那么它将在新数据集上计算6次误差。相反,欠采样可以使独立变量看起来具有更高的方差。
因此,机器学习文献展示了自然分布下过采样和欠采样混合的结果。
大多数机器学习包可以执行简单的采样调整。R包unbalanced针对非平衡数据集实现了一系列的采样方法。scikit-learn.cross_validation包含了基本的采样算法。
Wallace等的贝叶斯参数
可能最好的理论依据和实践建议来至于论文《Class Imbalance, Redux》,作者是Wallace, Small, Brodley and Trikalinos4。他们赞成欠采样。他们以数学的切底的理论为依据,但在这里我只能介绍一个他们用到的例子来表达他们的观点。
他们认为,两个类别必须是在一些解释变量分布的尾部可分的。假设你有两个类别用一个因变量,x,每个类是一个标准差为1的高斯分布。类别1的均值是1,类别2的均值是2。我们任意的假定类别2为多类别。他们应该是这样:
给定一个x值,你会用什么阈值来确定它来自哪个类?可以清楚的知道两者之间的最佳分割线是它们的中点,x=1.5,显示为垂直的线:如果一个新的样本x落在1.5左边,它可能是类别1,相反是类别2。当从样本中学习时,我们希望判别截至1.5是我们会得到的,如果类平衡,这大概是我们应该得到的。X轴上的点显示不同分布生成的样本。
但我们类别1是少类别,所以假设其有10个样本,类别2有50个样本。很可能我们学习到一个平移过的分割线,如下:
我们可以通过下采样多类别去匹配少类别使结果更好。问题是我们学习到的分割线将有很高的可变性(因为样本更少),如下所示(10次样本导致10条不同的竖线):
因此最终的步骤是利用bagging去联合这些分类器。主要过程如下:
这个技术在Scikit-learn中没有实现,但是文件blagging.py实现类一个BlaggingClassifier,即平衡引导样本先验聚合。
基于近邻的方法
过采样和欠采样随机选择样本来修正他们的比例。其他方法认真检查样本空间,并决定基于他们的近邻做什么。例如,Tomek链接是对对立类的实例,它们是自己的最近邻。换句话说,它们是对非常相似的对立实例。
Tomek算法查找这样的对并删掉其中多类别的实例。这个想法是净化多类别与少类别之间的边界,使少类别区域更明显。上图显示了Tomek链接删除的一个简单例子。R包unbalanced实现了Tomek链接删除,作为针对非平衡数据集的一个采样技术。Scikit-learn没有内建的模块实现此方法,但有一些独立的包(如,TomekLink)。
合成新的样本:SMOTE及其衍生
另一个研究方向不涉及对样本重采样,而是合成新的样本。这种方法最著名的例子是Chawla的SMOTE(Synthetic Minority Oversampling Technique)系统。这个想法是在现有样本间插值来产生新的少类别样本。过程基本如下。假设我们有一组多类别和少类别的样本,如下:
SMOTE通常是成功的,并产生了许多变体,扩展,和适应不同概念的学习算法。SMOTE及其变体在R包和python包UnbalancedDataset中都有。
注意SMOTE的大量限制很重要。因为它通过在稀有样本间插值来操作,它只能在可用样本体内产生样本,而不是外面。通常,SMOTE只能填充现有少类别样本的凸包,但是不创造其新的外部区域。
调整类权重
许多机器学习工具包都有调整某类重要性的方法。例如,Scikit-learn有许多分类器可以设置一个可选的参数class_weight,使其高于1。这里有个直接从Scikit-learn文档获得的例子,显示了增加10倍少类别权重的影响。黑色实线显示默认设置的分割边界(每个类别权重相等),虚线是将少类别参数class_weight设为10后的分割边界。
正如你所看到的,少类别获得更多重要性(他的误差被认为比其他类更贵)和调整分割超平面来减少损失。
应该注意的是,修正类重要性通常只对类误差代价有影响(假阴性,如果少数类是积极的)。它将相应地调整一个分界面来减少这些。当然,如果训练集上的分类器没有错误没有调整可能发生错误,所以改变类权重可能没有效果。
以后
这篇文章专注与以简单易用的方法从非平衡数据中学习分类器。他们中大部分涉及修正数据之前或之后应用标准的学习算法。简要提及其他一些方法是有价值的。
新算法
学习非平衡类别是机器学习正在进行的研究领域,每年都有新的算法提出来。在结束之前,我将提到一些最近算法的进步与前景。
2014年Goh和Rudin发表类一篇文章《 Box Drawings for Learning with Imbalanced Data》,介绍了两种从具有稀有样本的数据中学习的算法。这些算法试图围绕少类别样本集群构建“盒子”。
他们的目标是开发一种简洁明了的表示少数类的方法。他们的等式惩罚盒子数量和规则化项。
他们介绍了两个算法,其中一个使用整数规划提供一个精确的但相当昂贵的解决方案。另一个使用快速聚类的方法来产生一个初始化盒子。实验结果表明,两种算法在大量的测试数据集上表现都很好。
我早期提出解决非平衡问题的一个方法是丢弃少类别样本,把它作为一个单类问题(或异常检测)。最近的一个异常检测技术对于这个目的效果好得惊人。Liu,Ting和Zhou推出了一个称为隔离森林的技术,试图通过学习随机森林识别异常数据,然后测量的平均数量决定分裂需要隔离每个特定的数据点。由此产生的数量可以用来计算每个数据点的异常分数,也可以解释为例子属于少数类的可能性。实际上,作者使用高度不平衡数据测试他们的系统,并得到很好的结果。后续论文由Bandaragoda, Ting, Albrecht, Liu and Wells提出了最近邻集合作为一个类似的想法,能够克服隔离森林的一些缺点。
购买或者产生更多的数据
最后需要注意一点,这篇博文焦距在非平衡类情况,假设你得到的是非平衡数据,并且只需要解决非平衡。在某些情况下,比如Kaggle比赛,给你一组固定的数据,你不能要求更多。
但是你可能面临一个相关的困难的问题:你只是没有足够的稀有类的样本。上面的技术都不可能工作,你该怎么做?
现实世界某些领域你可以购买或者构造稀有类样本。这是机器学习正在进行的一个研究领域。如果稀有类数据仅仅需要可靠的人工标签,通常的方法是采用众包,比如Mechanical Turk。人工标签的可靠性可能是一个问题,但是机器学习已经完成结合人工标签增加可靠性。最后,Claudia Perlich在 All The Data and Still Not Enough 中举例,怎样利用替代变量或问题巧妙的解决数据稀有或不存在的问题,本质上使用代理或潜在的变量使看似不可能的问题变为可能。与此相关的是使用转移学习策略去学习一个问题,并把结果转移到另一个稀有数据的问题上,就像这里所描述的那样。
评论和问题?
在这里,我试图将我大多数实用知识提炼出来。我知道有很多不足,我会重视你的反馈。我漏掉什么重要的吗?本博客欢迎任何评论和问题。
资源和进一步阅读
1. 几种Jupyter notebooks说明了非平衡学习的各方面。
◎采样的高斯:Gaussians.ipynb
◎Wallance方法:blagging.py
2. MATLAB代码:http://web.mit.edu/rudin/www/code/BoxDrawingsCode.zip