越来越多的机器学习算法从学术界走向工业界,而在这个过程中会有很多困难,数据不平衡问题虽然不是最难的,但绝对是最重要的问题之一。
一 数据不平衡
在学术研究和教学中,很多算法都有一个基本假设,就是数据分布是均匀的。当我们把这些算法直接应用在实际数据中时,大多数情况下都无法取得理想的结果,因为实际数据往往分布的很不均衡,都存在长尾效应。
可以看到大部分微博的总互动数(被转发,评论和点赞数量)在0-5之间,交互数多的微博(多于100)非常之少,如果我们去预测一条微博交互数所在档位,预测器只需要把所有微博预测为第一档(0-5)就能解决非常高的准确率,而这样的预测器没有任何价值,那如何解决机器学习中的数据不平衡问题?这就是本文章要讨论的主要内容。
严格的说,任何数据集上都有数据不平衡的现象,这往往由问题本身决定的,但我们只关注那些分布差别比较悬殊的,另外虽然很多数据集都包含很多的类别,但是这里只考虑二分类,因为解决了二分类中的数据不平衡,推而广之就是得到了多分类的情况。综上,这里主要讨论如何解决二分类中正负样本差两个或以上数量级情况下数据不平衡的问题。
不平衡的难易程度取决于我们所拥有的数据有多大? 比如在预测微博互动的问题中,虽然数据不平衡,但每个档位的数据量都很大,最少的也有几万个样本,这样的问题通常比较容易解决,而在癌症诊断的场景中,因为癌症的人本来就很少,所以数据不但不平衡,样本数还非常少,这样的问题就很棘手,综上,可以把问题根据难度从小到大排个序:
大数据+分布均衡 《 大数据+ 分布不均衡 《 小数据+ 数据均衡 《 小数据 + 分布式不均衡
对于需要解决的问题,拿到数据后,先看数据的大小,再观察数据分布情况,经验表明,训练数据中每个类别有5000个以上样本,数据量是足够的,正负样本差在一个数量级是可以接受的,不太需要考虑数据的不平衡的。
二 如何解决
解决这一问题的基本思路是让正负样本在训练的过程中拥有相同的话语权,比如利用采样和加权等方法,我们把样本较多的那一类成为大众类,样本较少的那一类叫做小众类
1 采样
采样方法是通过对训练集进行处理使其从不平衡的数据集变成平衡的数据集,在大部分情况下,会对最终的结果带来提升。
采样分为上采样和下采样,上采样是把小种类复制多份,下采样是从大众类中剔除一些样本,或者说只从大众类中选取部分样本。
上采样会把小众样本复制多份,一个点在高维空间中反复出现,这会导致一个问题,就是运气好就能分对很多点,否则会错很多点,为了解决这个问题,可以在每次生成新数据点时加入轻微的随机扰动,经验表明这种做法很有效。
因为下采样会丢失信息,如何减少信息的损失?第一种方法叫做easyensemble,利用模型融合的方法,多次下采样(放回采样,这样产生的训练集才是相互独立的)产生多个不同的训练集,进行训练多个不同的分类器,通过组合多个分类器的结果得到最终的结果。第二种方法叫做balanceCascade,利用增量训练的思想:先通过一次下采样产生训练集,训练一个分类器,对于那些分类正确的大众样本不放回,然后对这个更小的大众样本下采样产生训练集,训练第二个分类器,以此类推,最终组合所有分类器得到最终结果。
2 数据合成
数据合成方法就是利用已有的样本生成更多样本,这类方法在小数据场景下有很多成功案例,比如医学图像分析。
其中最常见的一种方法叫做smote,它利用小众样本在特征空间的相似性来生成新样本。
上图是smote方法在k=6近邻下的示意图,黑色方格是生成的新样本。
smote为每个小众样本合成相同数量的新样本,这带来一些潜在的问题,一方面是增加了类之间重叠的可能性,另一方面是生成一些没法提供有益信息的样本,为了解决这个问题,出现两种方法:borderline-SMOTE与ADASYN
borderline-SMOTE的思路是寻找那些应该为之合成新样本的小众样本。即为每个小众样本计算K近邻,只为那些K近邻中有一半以上大众样本的小众样本生成新样本,直观的讲,只为那些周围大部分是大众样本的小众样本生成新样本,因为这些样本往往是边界样本。确定了为哪些小众样本生成样本后再利用SMOTE生成新样本。
ADASYN的解决思路是根据数据分布情况为不同小众样本生成不同数量的新样本。
3 加权
除了采样和生成新数据等方法,还可以通过加权的方式来解决数据不平衡的问题。
横向是真实分类情况,纵向是预测分类情况,C(i,j)是把真实类别为j的样本预测为i时的损失,我们需要根据实际情况来设定它的值
这样方法的难点在于设置合理的权重,实际应用中一般让各个分类间的加权损失值近似相等,当然这并不是通过法则,还是需要具体问题具体分析。
4 一分类
对于正负样本极不平衡的场景,我们可以换一个完全不同的角度来看待问题:把它看做一分类(one class learning) 或异常检测问题,这类方法的重点不在于捕捉类间的差别,而是为其中一类进行建模,经典的工作包括one-class-SVM