文本分类实战---数据分布不平衡问题

最近在做的项目的数据集里的数据分布非常不平衡,虽然是简单的二分类任务,但是两类数据的比例相差有两个数量级。实现的代码里大多数没有针对这个问题做专门的处理,只是在预测时简单的调小了阈值。因此查了一些解决数据分布不平衡的方法,在这里先总结一下,后面会单独挑出一些方法实现,并针对相应的代码和效果在写一篇文章。

1.重新采样训练集

可以使用不同的数据集。有两种方法使不平衡的数据集来建立一个平衡的数据集——欠采样和过采样。

1.1 欠采样

欠采样是通过减少丰富类的大小来平衡数据集,当数据量足够时就该使用此方法。通过保存所有稀有类样本,并在丰富类别中随机选择与稀有类别样本相等数量的样本,可以检索平衡的新数据集以进一步建模。

1.2. 过采样

相反,当数据量不足时就应该使用过采样,它尝试通过增加稀有样本的数量来平衡数据集,而不是去除丰富类别的样本的数量。通过使用重复、自举或合成少数类过采样等方法(SMOTE)来生成新的稀有样品。

注意到欠采样和过采样这两种方法相比而言,都没有绝对的优势。这两种方法的应用取决于它适用的用例和数据集本身。另外将过采样和欠采样结合起来使用也是成功的。

随机采样最大的优点是简单,但缺点也很明显。上采样后的数据集中会反复出现一些样本,训练出来的模型会有一定的过拟合;而下采样的缺点显而易见,那就是最终的训练集丢失了数据,模型只学到了总体模式的一部分。

2.组合不同的重采样数据集

成功泛化模型的最简单方法是使用更多的数据,问题是像逻辑回归或随机森林这样开箱即用的分类器,倾向于通过舍去稀有类来泛化模型。一个简单的最佳实践是建立n个模型,每个模型使用稀有类别的所有样本和丰富类别的n个不同样本。假设想要合并10个模型,那么将保留例如1000例稀有类别,并随机抽取10000例丰富类别。然后,只需将10000个案例分成10块,并训练10个不同的模型。
在这里插入图片描述
方法2可以很好地将稀有类别和丰富类别之间的比例进行微调,最好的比例在很大程度上取决于所使用的数据和模型。但是,不是在整体中以相同的比例训练所有模型,所以值得尝试合并不同的比例。如果10个模型被训练,有一个模型比例为1:1(稀有:丰富)和另一个1:3甚至是2:1的模型都是有意义的。一个类别获得的权重依赖于使用的模型。
在这里插入图片描述

3.转化为一分类问题

对于二分类问题,如果正负样本分布比例极不平衡,我们可以换一个完全不同的角度来看待问题:把它看做一分类(One Class Learning)或异常检测(Novelty Detection)问题。这类方法的重点不在于捕捉类间的差别,而是为其中一类进行建模,经典的工作包括One-class SVM等,如下图所示:
在这里插入图片描述
One Class SVM 是指你的训练数据只有一类正(或者负)样本的数据, 而没有另外的一类。在这时,你需要学习的实际上你训练数据的边界。而这时不能使用最大化软边缘了,因为你没有两类的数据。 所以呢,在这边文章中,“Estimating the support of a high-dimensional distribution”, Sch?lkopf 假设最好的边缘要远离特征空间中的原点。左边是在原始空间中的边界,可以看到有很多的边界都符合要求,但是比较靠谱的是找一个比较紧的边界(红色的)。这个目标转换到特征空间就是找一个离原点比较远的边界,同样是红色的直线。当然这些约束条件都是人为加上去的,你可以按照你自己的需要采取相应的约束条件。比如让你data 的中心离原点最远。

说明:对于正负样本极不均匀的问题,使用异常检测,或者一分类问题,也是一个思路。

4.多模型Bagging

上面所介绍的方法都是从数据的角度出发的,虽然可以选出合适的样本,但是不能保证鲁棒性,因为他们依赖于样本。
所以换一个角度,从模型方面下手,可以考虑使用多模型bagging。bagging算法是集成学习的一种,与boosting算法并列。boosting算法各个弱学习器之间是有依赖关系的,而bagging算法各个学习器之间没有依赖关系,可以并行拟合。bagging的原理可以用下面这张图表示:
在这里插入图片描述

bagging算法的特点在于随机采样(bootsrap),也就是有放回的采样。对于Bagging算法,一般会随机采集和训练集样本数m一样个数的样本。这样得到的采样集和训练集样本的个数相同,但是样本内容不同。如果我们对有m个样本训练集做T次的随机采样,则由于随机性,T个采样集各不相同。数学方法可以证明,随机采样的方法中,大约有36.8%的数据不会被采样到,,这部分数据可以用来检测模型的泛化能力。

注意到这和GBDT的子采样是不同的。GBDT的子采样是无放回采样,而Bagging的子采样是放回采样。

bagging对于弱学习器没有限制,这和Adaboost一样。但是最常用的一般也是决策树和神经网络。使用决策树的bagging算法就是随机森林了。

5. XGBoost

上面说到了bagging算法,与之平行的boosting算法中的XGBoost本身的设计可以很好的针对不平衡数据。并且现在的XGBoost实现的接口有专门的参数来控制处理不平衡数据。可以一试。

6. 转化为无监督学习的聚类,后使用监督学习的分类方法

首先,我们可以对具有大量样本的丰富类进行聚类操作。假设我们使用的方法是 K-Means聚类算法 。此时,我们可以选择K值为稀有类中的数据样本的个数,并将聚类后的中心点以及相应的聚类中心当做富类样本的代表样例,类标与富类类标一致。

经过上述步骤的聚类操作,我们对富类训练样本进行了筛选,接下来我们就可以将相等样本数的K个正负样本进行有监督训练。

7. 已有算法–SMOTE,EasyEnsemble和BalanceCascade

在知乎上看到一个回答,他的数据比例也是两个数量级的差距,他使用的EasyEnsemble效果很好。
这几篇文章是关于这三个算法的:
http://www.cnblogs.com/ljygoodgoodstudydaydayup/p/6485152.html
https://blog.csdn.net/u011414200/article/details/50664266
https://blog.csdn.net/march_on/article/details/48650237
https://zhuanlan.zhihu.com/p/36381828

接下来说说做的项目数据不平衡的问题。

项目中的数据是二类的,两种类型的数据相差两个数量级,训练集中一个是八万左右,另一个是一百多万。测试集中两者数量无法获知。
不采用上面介绍的方法进行数据平衡的情况下,(训练集按9:1分为训练集和验证集),最佳阈值在0.3左右,各模型的accuracy在90%左右,f1值在0.65左右。训练集上也查不多,只比验证集低一点。

为了处理不平衡的问题,我先用了最简单的方法,就是同时欠采样和过采样。为了将正例和负例平衡到统一的数量级,对负例以0.8的比例降采样,对正例以3倍数量过采样。在将训练集按9:1分为训练集和验证集。这时候的验证集上的结果有了很大的提升,f1值直接提升到了0.9左右,阈值向右靠到了0.45。但是在测试集上,效果却大大下降了(具体是多少我忘记记了。。但差的挺大的)。
跟同学讨论了一下,觉得可能是测试集的数据与原始训练集的数据分布应该是一样的,就是都是不平衡的一个分布,如果在训练集更改了数据的分布,那么训练出来的模型拟合的就是平衡的数据分布,在去预测测试集的不平衡数据的时候,就会有较大差距了。如果是这样的话,不对数据进行平衡处理才是正确的做法。。所以后面我就没有再对数据用上面的方法进行平衡处理了。。

参考文献:
https://www.leiphone.com/news/201706/dTRE5ow9qBVLkZSY.html
https://www.cnblogs.com/pinard/p/6131423.html
https://github.com/scikit-learn-contrib/imbalanced-learn

猜你喜欢

转载自blog.csdn.net/pnnngchg/article/details/85728231