参考自:https://www.svds.com/learning-imbalanced-classes/
引言
如果您刚从机器学习课程中学习,那么您所使用的大多数数据集都相当容易。除其他事项外,在构建分类器时,样本类是平衡的,这意味着每个类的实例数量大致相同。教师通常使用清理过的数据集,以专注于讲授特定的算法或技术而不受其他问题的干扰。通常你会在两个维度中显示如下的例子,用不同颜色(或形状)的点代表类:
分类算法的目标是试图学习一个能区分两者的分隔符(分类器)。有很多种方法,基于各种数学、统计或几何假设:
但当我们开始观察一个真实的,未清洗过的数据,首先意识到的就是许多噪声和数据的不均衡性。真实数据的点图通常看起来像下面这样:
主要的问题是这些类是不平衡的:红色的点数量远远小于蓝色点数量。
对不平衡类的研究通常认为不平衡是指少数类占比少于10%到20%。事实上,数据集可能比这更不平衡。—这里是一些例子:
1、 每年大约有2%的信用卡账户被欺诈[1]。(大多数欺诈检测域严重不平衡)
2、 对疾病进行医学筛查通常是在没有这种情况的大量人群中进行的,用它来检测少数人(例如,美国的艾滋病毒流行率为0.4%)。
![](/qrcode.jpg)
3、磁盘驱动器故障大约每年1%次。
5、工厂生产缺陷率通常在0.1%左右。
这些领域中有许多是不均衡的问题,它们就是我称之为“大海捞针”的问题,机器学习分类器用来对大量负(无兴趣)的样本进行分类,以找到少数正的(有意义的,值得警惕的)案例。
当遇到这样的问题时,使用标准的算法会很难解决这些问题。传统的算法往往偏向多数类,因为他们的损失函数尝试优化大量如错误率之类的参数,而没有考虑数据的分布情况[2]。在最坏的情况下,少数的样本被视为大多数类的离群值并被忽略。学习算法只生成一个简单的分类器,将每个样本分为多数类。
这似乎是一种病态行为,但实际上它不是。事实上,如果你的目标是最大限度地提高简单的精度(或者等价地,最小化错误率),这是一个完全可以接受的解决方案。但是如果我们假设稀有类的例子更重要,那么我们必须更加小心并更复杂地处理这个问题。
如果你处理这些问题,并想就如何解决这些问题提出实际建议,请继续读下去。
【注意】:这篇文章的重点是提供关于如何解决这些问题的真知灼见和具体建议。然而,这不是一个通过代码逐行进行编码的教程。我有用Jupyter Notebooks(链接接在文末)通过实验来尝试这些想法,但这篇文章将解释一些基本的理念和原则。
处理不平衡数据
对不平衡数据的学习是近二十年来机器学习领域的研究热点。这是许多论文、讲习班、特别会议和学位论文的主题(最近的调查有大约220篇参考文献)。尽管研究者们已经尝试了大量的技术,但结果各异,答案却很少。第一次面对这个问题的数据科学家经常问,当我的数据不平衡时,我该怎么办?这与通常所问的“哪个学习算法最好”的答案的缘由一样,没有明确的答案。没有明确的答案是因为:这取决于数据。
也就是说,这里有一个行之有效的方法的大致轮廓。下面这些方法大体上按付出的effort的顺序列出:
•什么也不做。有时候你很幸运,什么也不需要做。您可以在所谓的自然(或分层)分布上进行训练,有时都不需要修改就可以运行。
•平衡训练集的一些方式:
◦过采样少数类。
◦降采样多数类。
◦合成新的少数类。
•抛弃少数类的一些样本,切换到异常检测框架。
•在算法层上或在此之后:
◦调整类权重(误判成本)。
◦调整判定的阈值。
◦修改现有的算法使得对稀有类更敏感。
•构造一种全新的算法来使得在不平衡数据上表现良好。
题外话:评价的注意事项
首先,快速浏览。在讨论如何利用不平衡数据对分类器进行训练之前,我们必须讨论如何正确地评估一个分类器。这再怎么强调都不为过。只有度量正确的事物,你才能取得进步。
1、不要使用准确性(或错误率)来评估分类器!它有两个重要的问题。准确性天然的用0.50做阈值在类之间进行判决,当类不平衡时这通常是错误的。第二,分类准确度是基于对分类错误数的简单计数,当然您应该知道的不止于此。你应该知道哪些类是混淆的,在哪里(最高分数,底部结束,整个?)如果您不理解这些要点,阅读分类器评估的基础知识的第2部分可能会有帮助。您应该使用ROC曲线、精准率-召回率曲线、提升曲线或gain(增益)曲线来可视化分类器的性能。
2、不要试图从分类器(通过score[3]或预测函数)获取硬分类(标签)。相反,通过proba或predict_proba获取概率估计是可取的。
3、当你得到概率估计时,不要盲目地使用0.50做为决策阈值来划分类。查看性能曲线,并决定使用什么阈值(请参阅下一节了解更多信息)。在早期的论文中有许多错误,因为研究人员天真地使用0.5作为划分阈值。
4、无论你为训练做了哪些工作,总是要基于自然(分层)分布来测试你的分类器的工作情况。参考:sklearn.cross_validation.stratifiedkfold。
5、你可能没有得到概率估计,但如果你需要的话,使用校准(见sklearn.calibration.CalibratedClassifierCV)。
上面第一个子弹形的二维图形总比单个数字的内容更丰富,但是如果你需要一个单一数据的度量,其中的一个在精度方面更好:
1、ROC曲线下面积(AUC)是一个很好的一般统计量。它等于随机正例在随机反例之上的概率。
2、F1得分是精度和召回率的调和平均数。它通常用在文本处理中,聚合度量被探寻的时候。
3、Cohen’s Kappa值是一个评估统计数字,计算预期会有多少同意数。
过采样和采样
最简单的方法需要修改处理步骤,只需调整样本集直到它们平衡为止。随机过采样复制了少数实例以增加其数量。随机欠采样降低了采样的多数类数量。一些数据科学家(初衷)认为过采样较优越,因为它产生了更多的数据,而欠采样将数据扔掉。但是要考虑,复制数据并不是没有代价,因为它会导致重复的数据,这使得变量看起来比它们的方差要低。其积极的结果是,它重复了错误的数目:如果分类器在原始的少数数据集上产生假阴性错误,并且该数据集被复制五次,分类器将在新集上产生六个错误。相反,欠采样可以使独立的变量看起来要比他们自身有更高的方差。
因此,机器学习论文表明使用过采样,欠采样,利用自然分布得到的是一种混合的结果。
大多数机器学习包可以进行简单的抽样调整。像R包里面在这方面采用了一些特定的不平衡数据集抽样技术,并且scikit-learn.cross_validation拥有基本的采样算法。
华勒斯等人的贝叶斯论证
可能最好的理论论证和实践建议都在这篇论文《Class Imbalance, Redux, by Wallace, Small, Brodley and Trikalinos[4]》中提出。他们对多数类欠采样的观点进行了争论。他们的论点是数学方面的并且是透彻的,但在这里,我只提出一个他们用来提出自己观点的例子。
他们认为两个类在一些解释变量的分布的尾部必须区分开来。假设你有两个类,有一个独立的变量,x。每个类都由一个标准差为1的高斯函数生成。类1的平均数是1,类2的平均数是2。我们将武断地称类2为多数阶级。他们看起来像这样:
给定一个x值,您将使用什么阈值来确定它来自哪个类?显而易见的是,两者之间最好的分隔线在它们的中点,x=1.5,显示为竖线:如果一个新的x低于1.5,它很可能是第1类,否则,它很可能就是第2类。当从例子中学习时,我们希望1.5处的判别截断值是我们所能得到的,如果类是平均分布的,这大概是我们应该得到的。x轴上的点显示每个分布产生的样本。
但是我们已经说过类1是少数类,所以我们假设有10个样本,50个来自2类的样本。我们很可能会学习到像这样的移动分离线:
我们可以通过欠采样大数类与少数类相匹配的方式使结果做得更好。问题是我们所学的分离线具有很高的可变性(因为样品比较小),如图所示(十个样品显示,产生十条垂直线):
因此,最后一步是使用bagging来组合这些分类器。整个过程如下所示:
这种技术尚未在Scikit-learn中实现,虽然名为blagging.py(balanced bagging)可实现BaggingClassifier,然而它将自身的原始样本转向了聚合。
基于邻居的方法
过度和欠采样随机选取的样本来调整比例。其他方法仔细检查样本空间,并根据它们的邻域决定该做什么。
例如,Tomek links是链接自己的近邻相对类的实例对。换句话说,它们是相互对立的两个非常接近的样本对。
Tomek算法寻找这样的配对,并消除大多数这样的样本对。其目的是厘清少数类与多数类的边界,使少数类区域更加鲜明。上面的图显示了一个用Tomek链接消除的简单例子。R包unbalanced实现了Tomek链接消除算法,并实现了大量具体的不平衡数据集抽样技术。Scikit-learn没有构建这样的内置模块,但也有一些独立的软件包(例如,TomekLink)。
合成新样本:SMOTE和后裔
另一个研究方向不仅仅涉及样本的重采样,更包含的是新样本的合成。该方法最著名的例子是Chawla的SMOTE(合成少数类的过采样技术)系统。这个想法是通过在现有的样本中插入新的少数类样本。这个过程大致如下。假设我们有一组多数和少数的样本,和以前一样:
SMOTE通常情况下是成功的,并导致许多变体,扩展和适应不同的概念学习算法。SMOTE和变量在R的unbalanced包,Python的UnbalancedDataset包中均可获取到。
意识到SMOTE潜在的局限性也很重要。因为它通过在稀少的样本之间进行插值操作来实现,所以它只能在可用的样本中生成样本实例,而不是在外部。在形式上,SMOTE只能在基于现有的少数样本的凸包上进行填充,而不能在外部区域创建新的样本。
调整类权重
许多机器学习工具包都有方法来调整类的“重要性”。例如Scikit-learn,有许多分类器,有一个可选的class_weight参数可以设置高于某个值。这里有一个例子,直接从Scikit-learn文档中获取,显示增加十倍的少数类的权重的影响。实体黑线显示分离的边界,当使用默认设置(两个类权重相等),而虚线为少数类的class_weight参数被改为十倍后的边界。
正如您所看到的,少数类的重要性得到提高(其错误被认为比其他类的错误更为代价高),同时对分离的超平面进行了调整以减少损失。
应该注意的是,调整类的重要性通常只对类错误的代价(假阴性,如果少数类是正数)有影响。相应的可以调整分离面来减少这些代价。当然,如果分类器在训练集错误里没有错误,那么就不会出现调整,因而改变类权重可能会没有效果。
其他方法
这篇文章从相对简单、易上手的方法里面集中讨论了如何从不平衡数据中学习分类器。其中大部分内容涉及在应用标准学习算法之前或之后调整数据。值得简单提一下其他一些方法。
新算法
学习不平衡类仍然是机器学习领域中一个正在进行的研究领域,每年都有新的算法被引入。在结束之前,我会提到一些最近的先进算法的进展。
2014年Goh和Rudin发表了一篇论文《Box Drawings for Learning with Imbalanced Data[5]》,介绍了从倾斜的样本数据中学习的两种算法。这些算法试图在少数类样本集群的基础上构造“盒子”(实际上是轴并行的超矩形):
他们的目标是建立一个简明、易懂的少数类样本的表达方式。他们的方程式惩罚了盒子的数量,该惩罚是以一种正则化的形式进行服务。
它们引入两种算法,其中一种(精确框)使用混合整数编程来提供精确但相当昂贵的解决方案;另一种(快速框)使用更快的聚类方法生成初始框,随后将其细化。实验结果表明,这两种算法在大量测试数据集上都能很好地发挥作用。
早些时候我提到,解决不平衡问题的一种方法是抛弃少数类的样本,把它当作单一类(或异常检测)处理。最近一项异常检测技术的效果出奇地好。Liu,Ting和Zhou介绍了一种叫做隔离森林[6]的方法,它试图通过学习随机森林然后测量需要将每个特定的数据点分离出来的分隔面的平均数找出异常数据。生成的数字可以用来计算每个数据点的异常分数,也可以被解释为该样本可能属于的少数类。事实上,作者用高度不平衡的数据测试了他们的系统,并报告了很好的结果。这篇论文由Ting和Albrecht[7] follow-up,后续的文章中,Liu和wells[8]介绍了一个类似近邻合奏的想法,它能够克服隔离森林的一些缺点。
购买或创建更多数据
最后一点是,这篇博文关注的是不平衡类的情况,在默认假设下,你得到了不平衡的数据,而你只需要处理不平衡。在某些情况下,如在Kaggle的竞争,给你一个固定的数据集,你不能要求更多。
但是你可能会遇到一个相关的,更难的问题:在这个稀有类里你没有足够的样本。以上的技术都不可行。你怎么办?
在一些现实世界域中,您可以购买或构造稀有类的样本。这是机器学习中一个正在进行的研究领域。如果数据稀少,只需要有人来可靠的标记这些数据,一个常用的方法是通过众包服务Mechanical Turk。人类标签的可靠性可能是一个问题,但在机器学习中已经完成了将人类标签与可靠性优化相结合的工作。最后,Claudia Perlich在她的谈话All The Data and Still Not Enough中给出数据稀少或数据根本不存在的问题,可以巧妙的使用替代变量转换问题的例子,基本上是使用代理变量与latent variables使看似不可能的问题变得可能。与此相关的策略是使用迁移学习来学习一个问题,并用很少的样本将结果转换到另一个问题,如下所述。
资源与进一步阅读
1. Several Jupyter notebooks are available illustrating aspects of imbalanced learning.
o A notebook illustrating sampled Gaussians, above, is at Gaussians.ipynb
.
o A simple implementation of Wallace’s method is available at blagging.py
. It is a simple fork of the existing bagging implementation of sklearn, specifically ./sklearn/ensemble/bagging.py
.
o A notebook using this method is available at ImbalancedClasses.ipynb
. It loads up several domains and compares blagging with other methods under different distributions.
2. Source code for Box Drawings in MATLAB is available from: http://web.mit.edu/rudin/www/code/BoxDrawingsCode.zip
3. Source code for Isolation Forests in R is available at: https://sourceforge.net/projects/iforest/
Thanks to Chloe Mawer for her Jupyter Notebook design work.
【备注】
1. Natalie Hockham makes this point in her talk Machine learning with imbalanced data sets, which focuses on imbalance in the context of credit card fraud detection.
2. By definition there are fewer instances of the rare class, but the problem comes about because the cost of missing them (a false negative) is much higher.
3. The details in courier are specific to Python’s Scikit-learn.
4. “Class Imbalance, Redux”. Wallace, Small, Brodley and Trikalinos. IEEE Conf on Data Mining. 2011.
5. Box Drawings for Learning with Imbalanced Data.” Siong Thye Goh and Cynthia Rudin. KDD-2014, August 24–27, 2014, New York, NY, USA.
6. “Isolation-Based Anomaly Detection”. Liu, Ting and Zhou. ACM Transactions on Knowledge Discovery from Data, Vol. 6, No. 1. 2012.
7. “Efficient Anomaly Detection by Isolation Using Nearest Neighbour Ensemble.” Bandaragoda, Ting, Albrecht, Liu and Wells. ICDM-2014