XDRush

ML/DL中样本不均衡问题处理方式

1 背景说明

机器学习或者深度学习中常常会遇到数据的类别不平衡(class imbalance),也叫数据偏斜(class skew)。以常见的二分类问题为例,我们希望预测病人是否得了某种罕见疾病。但在历史数据中,阳性的比例可能很低(如百分之0.1)。在这种情况下,学习出好的分类器是很难的,而且在这种情况下得到结论往往也是很具迷惑性的。再比如在CTR预估中,WAP上的CTR通常在千分之几,APP上CTR也就百分之一二,意味着PV远远要大于Click。

以上面提到的场景来说,如果我们的分类器总是预测一个人未患病,即预测为反例,那么我们依然有高达99.9%的预测准确率。然而这种结果是没有意义的,那么有效在数据不平衡的情况下评估分类器呢?

当然,本文最终希望解决的问题是:在数据偏斜的情况下,如何得到一个不错的分类器?如果可能,是否可以找到一个较为简单的解决方法,而规避复杂的模型、数据处理,降低我们的工作量。

2 数据不平衡情况下模型的评估

对于平衡的数据,我们一般都用准确率(accuracy),也就是(1-误分率)作为一般的评估标准。这种标准的默认假设前提是:“数据是平衡的,正例与反例的重要性一样,二分类器的阈值是0.5。”在这种情况下,用准确率来对分类器进行评估是合理的。

而当数据不平衡时,准确率就非常具有迷惑性,而且意义不大。下面给出几种主流的评估方法:

  • ROC是一种常见的替代方法,全名receiver operating curve,计算ROC曲线下的面积是一种主流方法
  • Precision-recall curve和ROC有相似的地方,但定义不同,计算此曲线下的面积也是一种方法
  • Precision@n是另一种方法,是指将分类阈值设定得到恰好n个正例时分类器的precision
  • Average precision也叫做平均精度,主要描述了precision的一般表现,在异常检测中有时候会用
  • 直接使用Precision也是一种想法,但此时的假设是分类器的阈值是0.5,因此意义不大

至于哪种方法更好,一般来看我们在极端数据不平衡中更在意“少数的类别”,因此ROC不像precision-recall curve那样更具有吸引力。在这种情况下,Precision-recall curve不失为一种好的评估标准。还有一种做法是,仅分析ROC曲线左边的一小部分,从这个角度看和precision-recall curve有很高的相似性。

同理,因为我们更在意罕见的正例,因此precision尤为重要,因此average precision (macro)也是常见的评估标准。此处特意要提醒两点:(1)没有特殊情况,不要用准确率(accuracy),一般都没什么帮助。(2)如果使用precision,请注意调整分类阈值,precision@n更有意义。

3 如何处理数据不均衡问题

对于数据不平衡的研究已经有很多年了,下面结合我的了解举几个简单的例子:

  • 对数据进行采用的过程中通过相似性同时生成并插样“少数类别数据”,叫做SMOTE算法
  • 对数据先进行聚类,再将大的簇进行随机欠采样或者小的簇进行数据生成
  • 把监督学习变为无监督学习,舍弃掉标签把问题转化为一个无监督问题,如异常检测
  • 先对多数类别进行随机的欠采样,并结合boosting算法进行集成学习

上面提到的算法比较偏理论,实际应用中的最简单的算法无外乎三种:

  • 对较多的那个类别进行欠采样(under-sampling),舍弃一部分数据,使其与较少类别的数据相当;
  • 对较少的类别进行过采样(over-sampling),重复使用一部分数据,使其与较多类别的数据相当;
  • 阈值调整(threshold moving),将原本默认为0.5的阈值调整到 较少类别/(较少类别+较多类别)即可;

当然很明显我们可以看出,第一种和第二种方法都会明显的改变数据分布,我们的训练数据假设不再是真实数据的无偏表述。在第一种方法中,我们浪费了很多数据。而第二类方法中有无中生有或者重复使用了数据,会导致过拟合的发生。

因此欠采样的逻辑中往往会结合集成学习来有效的使用数据,假设正例数据n,而反例数据m个。我们可以通过欠采样,随机无重复的生成(k=n/m)个反例子集,并将每个子集都与相同正例数据合并生成k个新的训练样本。我们在k个训练样本上分别训练一个分类器,最终将k个分类器的结果结合起来,比如求平均值。

但不难看出,其实这样的过程是需要花时间处理数据和编程的,对于很多知识和能力有限的人来说难度比较大。特此推荐两个简单易行且效果中上的做法:

  • 简单的调整阈值,不对数据进行任何处理。此处特指将分类阈值从0.5调整到正例比例;
  • 使用现有的集成学习分类器,如随机森林或者xgboost,并调整分类阈值;

以上总结是个人的一些思考以及前人的一些总结,仅供参考。