不均衡样本集的处理


不均衡样本集的处理

不均衡样本在分类时会出现问题,本质原因是模型在训练时优化的目标函数和在测试时使用的评价标准不一致。这种“不一致”可能是由于训练数据的样本分布于测试时期望的样本分布不一致(如训练集正负样本比例是1:99,而实际测试时期望的正负样本比例是1:1);也可能是由于训练阶段不同类别的权重与测试阶段不一致(如训练时认为所有样本的贡献是相等的,而测试时假阳性样本和假阴性样本有着不同的代价)。

基于上述分析,一般从两个角度来处理样本不均衡的问题,分别为基于数据和基于算法

在Python中对应的处理数据不平衡的库为(imblearn)。

基于数据的方法

基于数据的方法是对样本进行重采样,使原本不均衡的样本变得均衡。使用\(C_{maj}\)表示样本数大的类别,\(C_{min}\)表示样本数小的类别。对应的样本集分别为\(S_{maj}\)\(S_{min}\),并且有|\(S_{maj}\)|>>|\(S_{min}\)|。

1. 随机采样

随机采样是最简单的一种方法,一般分为过采样(Over-sampling)和欠采样(Under-sampling)。

随机过采样是从少数样本集\(S_{min}\)中随机重复抽取样本(有放回)以得到更多样本;随机欠采样则相反,从多类样本集中随机选取较少的样本(有放回或无放回)。

在Python库中函数为RandomOverSampler和RandomUnderSampler。处理过程如下:

from imblearn.over_sampling
from imblearn.under_sampling

import RandomOverSampler
import RandomUnderSampler

ros = RandomOverSampler(random_state=0)
#将replacement参数设置为True,可实现自助法(boostrap)抽样。
rus = RandomUnderSampler(random_state=0,replacement=True)
X_resampled, y_resampled = ros.fit_sample(X, y)

存在问题:过采样对少数类样本进行了多次复制, 扩大了数据规模, 增加了模型训练的复杂度, 同时也容易造成过拟合; 欠采样会丢弃一些样本, 可能会损失部分有用信息, 造成模型只学到了整体模式的一部分。

2. 采样一些方法生产新样本,解决过采样产生的问题

为了解决随机采样存在的一些问题,可以在采样时并不是简单的复制样本,而是采用一些方法生产新的样本。

  • SMOTE算法

    SMOTE算法对少数类样本集\(S_{min}\)中每个样本x,从它在\(S_{min}\)中的K近邻中随机选一个样本y, 然后在x,y连线上随机选取一点作为新合成的样本(根据需要的过采样倍率重复上述过程若干次),这种合成新样本的过采样方法可以降低过拟合风险。

    问题:SMOTE算法为每个少数类样本合成相同数量的新样本,这可能会增大类间重叠度,并且生成一些不能提供有益信息的无用样本。下面的两种算法就是对SMOTE算法的改进。

    如下图所示:

    Python库中SMOTE函数的使用:

    from imblearn.over_sampling import SMOTE
    
    X_resampled_smote, y_resampled_smote = SMOTE().fit_sample(X, y)
    
  • Borderline-SMOTE

    Borderline-SMOTE只给那些处在分类边界上的少数类样本合成新样本 。

    判断边界的一个简单的规则为:K 近邻中有一半以上多数类样本的少数类为边界样本。直观地讲,只为那些周围大部分是多数类样本的少数类样本生成新样本。

    假设 a 为少数类中的一个样本,此时少数类的样本分为三类,如下图所示:

    (i) 噪音样本 (noise), 该少数类的所有最近邻样本都来自于不同于样本 a 的其他类别:

    (ii) 危险样本 (in danger), 至少一半的最近邻样本来自于同一类 (不同于 a 的类别);

    (iii) 安全样本 (safe), 所有的最近邻样本都来自于同一个类。

    对应的 Python 库中的实现有三种可以选择的规则:

    SMOTE 函数中的 kind 参数控制了选择哪种规则:

    borderline1:最近邻中的随机样本与该少数类样本 a 来自于不同的类;

    borderline2:最近邻中的随机样本可以是属于任何一个类的样本;

    svm:使用支持向量机分类器产生支持向量然后再生成新的少数类样本。

    from imblearn.under_sampling
    
    import ClusterCentroids
    
    cc = ClusterCentroids(random_state=0)
    
    X_resampled, y_resampled = cc.fit_sample(X, y)
    
  • ADASYN

    ADASYN改进主要是根据数据分布情况为不同的少数类样本合成不同个数的新样本 。

    首先根据最终的平衡程度设定总共需要生成的新少数类样本数量 ,然后为每个少数类样本 x 计算分布比例。

    对应的Python库中的函数为:

    from imblearn.over_sampling import ADASYN
    
    X_resampled_adasyn, y_resampled_adasyn = ADASYN().fit_sample(X, y)
    
  • 数据清洗方法

    • Tomek Links

      使用数据清理的方法来进一步降低合成样本带来的类间重叠,得到更加良定义(well-defined)的类簇。

      假设样本点 \(x_i\)\(x_j\) 属于不同的类别,d (\(x_i, x_j\)) 表示两个样本点之间的距离。称 (\(x_i\),\(x_j\)) 为一个 Tomek link 对,如果不存在第三个样本点 \(x_l\) 使得 d (\(x_l,x_i\))<d (\(x_i,x_j\)) 或者 d (\(x_l,x_j\))<d (\(x_i,x_j\)) 成立。也就是说这两个样本互为近邻关系。

      容易看出,如果两个样本点为 Tomek link 对,则其中某个样本为噪声(偏离正常分布太多)或者两个样本都在两类的边界上。

      所以Tomek Links方法的作用有两个,一个是欠采样,将 Tomek link 对中属于多数类的样本剔除;而是数据清洗,经Tomek link对中的两个样本都剔除。

      在Python库中TomekLinks 函数中的 auto 参数控制 Tomek’s links 中的哪些样本被剔除。默认的 ratio='auto' 移除多数类的样本,当 ratio='all' 时,两个样本均被移除。

    • EditedNearestNeighbours

      EditedNearestNeighbours 这种方法应用最近邻算法来编辑 (edit) 数据集,找出那些与邻居不太友好的样本然后移除。对于每一个要进行下采样的样本,那些不满足一些准则的样本将会被移除;他们的绝大多数 (kind_sel='mode') 或者全部 (kind_sel='all') 的近邻样本都属于同一个类,这些样本会被保留在数据集中.

      from imblearn.under_sampling import EditedNearestNeighbours
      enn = EditedNearestNeighbours(random_state=0)
      X_resampled, y_resampled = enn.fit_sample(X, y)
      

      在此基础上,延伸出了 RepeatedEditedNearestNeighbours 算法,重复基础的 EditedNearestNeighbours 算法多次。

      from imblearn.under_sampling import RepeatedEditedNearestNeighbours
      renn = RepeatedEditedNearestNeighbours(random_state=0)
      X_resampled, y_resampled = renn.fit_sample(X, y)
      
      print sorted(Counter(y_resampled).items())
      

      RepeatedEditedNearestNeighbours 算法不同的是,ALLKNN 算法在进行每次迭代的时候,最近邻的数量都在增加.

      from imblearn.under_sampling import AllKNN
      allknn = AllKNN(random_state=0)
      X_resampled, y_resampled = allknn.fit_sample(X, y)
      
    • CondensedNearestNeighbour

      使用 1 近邻的方法来进行迭代,来判断一个样本是应该保留还是剔除,具体的实现步骤如下:

      集合 C: 所有的少数类样本;
      选择一个多数类样本 (需要下采样) 加入集合 C, 其他的这类样本放入集合 S;
      使用集合 S 训练一个 1-NN 的分类器,对集合 S 中的样本进行分类;
      将集合 S 中错分的样本加入集合 C;
      重复上述过程,直到没有样本再加入到集合 C.

      from imblearn.under_sampling import CondensedNearestNeighbour
      cnn = CondensedNearestNeighbour(random_state=0)
      X_resampled, y_resampled = cnn.fit_sample(X, y)
      

      显然,CondensedNearestNeighbour 方法对噪音数据是很敏感的,也容易加入噪音数据到集合 C 中.

      因此,OneSidedSelection 函数使用 TomekLinks 方法来剔除噪声数据 (多数类样本).

    • NeighbourhoodCleaningRule

      该算法主要关注如何清洗数据而不是筛选 (considering) 他们。因此,该算法将使用

      EditedNearestNeighbours和 3-NN 分类器结果拒绝的样本之间的并集.

      from imblearn.under_sampling import NeighbourhoodCleaningRule
      ncr = NeighbourhoodCleaningRule(random_state=0)
      X_resampled, y_resampled = ncr.fit_sample(X, y)
      
3. 使用Informed Undersampling来解决欠采样带来的数据丢失问题
  • Easy Ensemble算法。

    每次从多数类\(S_{maj}\)中上随机抽取一个子集E(|E|≈|\(S_{min}\)|), 然后用E+\(S_{min}\)训练一个分类器; 重复上述过程若干次, 得到多个分类器,最终的分类结果是这多个分类器结果的融合。

    EasyEnsemble 方法对应 Python 库中函数为 EasyEnsemble,有两个很重要的参数: (i) n_subsets 控制的是子集的个数 ;(ii) replacement 决定是有放回还是无放回的随机采样。

    from imblearn.ensemble
    
    import EasyEnsemble
    
    ee = EasyEnsemble(random_state=0, n_subsets=10)
    
    X_resampled, y_resampled = ee.fit_sample(X, y)
    
  • Balance Cascade算法

    级联结构, 在每一级中从多数类\(S_{maj}\)中随机抽取子集E, 用E+\(S_{min}\)训练该级的分类器; 然后将\(S_{maj}\)中能够被当前分类器正确判别的样本剔除掉, 继续在比之前较小的多数类样本集中执行下才采样的操作, 重复若干次得到级联结构; 最终的输出结果也是各级分类器结果的融合。

    BalanceCascade 方法对应 Python 库中函数为 BalanceCascade,有三个很重要的参数: (i) estimator 是选择使用的分类器;(ii) n_max_subset 控制的是子集的个数;(iii) bootstrap 决定是有放回还是无放回的随机采样。

    from imblearn.ensemble
    
    import BalanceCascade
    
    from sklearn.linear_model
    
    import LogisticRegression
    
    bc = BalanceCascade(random_state=0,
    
              estimator=LogisticRegression(random_state=0),
    
              n_max_subset=4)
    
    X_resampled, y_resampled = bc.fit_sample(X, y)
    
  • NearMiss

    利用K近邻信息挑选具有代表性的多数类样本。首先计算出每个样本点之间的距离,通过一定规则来选取保留的多数类样本点。因此该方法的计算量通常很大。

    NearMiss 方法对应 Python 库中函数为 NearMiss,通过 version 来选择使用的规则:

    NearMiss-1:选择离 N 个近邻的负样本的平均距离最小的正样本;

    NearMiss-2:选择离 N 个负样本最远的平均距离最小的正样本;

    NearMiss-3:是一个两段式的算法。 首先,对于每一个负样本, 保留它们的 M 个近邻样本;接着,那些到 N 个近邻样本平均距离最大的正样本将被选择。

    from imblearn.under_sampling
    
    import NearMiss nm1 = NearMiss(random_state=0, version=1)
    
    X_resampled_nm1, y_resampled = nm1.fit_sample(X, y)
    
  • One-Sided Selection

    One-Sided Selection 算法的目的是剔除多数类样本中噪声、边界样本和多余样本,其算法流程如下 (S 为原始训练样本集合):

    初始化集合 C,C应该包括所有的少数类样本和随机选择的一个多数类样本

    集合 C 训练一个 1-NN 分类器(即 kNN 中选择近邻数为 1),并用这个分类器对 S 中的样本进行分类,将错分的多数类样本并入集合 C。

    对集合 C 使用 Tomek links 方法剔除多数类样本,得到最终的训练样本集合 T。

    One-Sided Selection 算法中使用 Tomek links 剔除多数类样本中的噪声和边界样本,未被 1-NN 分类器错分的样本则被视为多余样本,最终得到一个类别分布更为平衡的样本集合。

    from imblearn.under_sampling import OneSidedSelection
    oss = OneSidedSelection(random_state=0)
    X_resampled, y_resampled = oss.fit_sample(X, y)
    
4. 其他一些有用的方法
  • 基于聚类的方法

    基于聚类的方法,利用数据的类簇信息来指导过采样/欠采样操作;

  • 数据扩充方法

    是一个过采样技术,对少数类样本进行一些噪声扰动或变换(如图像数据集中对图像进行裁剪、翻转、旋转、光照等)以构造出新样本;

  • Hard Negative Mining

    是一种欠采样,把比较难分的样本抽取出来,用于迭代分类器。

基于算法的方法

  • 改变模型训练时的目标函数

    当样本不均衡时,改变模型训练的目标函数,如使用代价敏感学习中不同类别有不同的权重来矫正这种不平衡性。

  • 改变问题类别

    当样本极度不平衡时,可以将问题转变为单类学习(one-class learning)、异常检测(anomaly detection)。

如何选择使用何种处理方法

解决数据不平衡问题的方法有很多,上面只是一些最常用的方法,而最常用的方法也有这么多种,如何根据实际问题选择合适的方法呢:

在正负样本都非常之少的情况下,应该采用数据合成的方式;
在负样本足够多,正样本非常之少且比例及其悬殊的情况下,应该考虑一分类方法;
在正负样本都足够多且比例不是特别悬殊的情况下,应该考虑采样或者加权的方法。
采样和加权在数学上是等价的,但实际应用中效果却有差别。尤其是采样了诸如 Random Forest 等分类方法,训练过程会对训练集进行随机采样。在这种情况下,如果计算资源允许上采样往往要比加权好一些。

另外,虽然上采样和下采样都可以使数据集变得平衡,并且在数据足够多的情况下等价,但两者也是有区别的。实际应用中,经验的做法是如果计算资源足够且小众类样本足够多的情况下使用上采样,否则使用下采样,因为上采样会增加训练集的大小进而增加训练时间,同时小的训练集非常容易产生过拟合。
对于下采样,如果计算资源相对较多且有良好的并行环境,应该选择 Ensemble 方法。

模型在不均衡样本集上的评价标准

  • 对不平衡的数据生成模型应用不当的评估指标是相当危险的,很容易就生成了一个“假”的模型。例如一个模型的正负样本比例是99:1,若使用精度来衡量模型的好坏,将所有测试样本分类为 “0” 的模型将具有很好的准确性(99%),但显然这种模型不会为我们提供任何有价值的信息。

  • 可以应用其他评估指标替代精度指标

    F1_Score,准确率和召回率的调和平均值;

    P-R曲线

    G-Mean

    ROC曲线和AUC

参考文献:

不平衡数据处理

不平衡数据集的处理

Imblearn package study(不平衡数据处理之过采样、下采样、综合采样)

百面机器学习


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM