样本不平衡的解决方案(很详细)

​ 举个例子,在广告CTR预估场景中,正负样本的占比可以达到1:500,点击的正样本是少数类,没点击的负样本为多数类。如果直接拿这个比例去训练模型的话, 很容易学出一个把所有样本都预测为负的模型,因为喂进去学习的样本大多都是负样本。这种情况下,损失会很低,准确率一般都会很高,比如0.98,但是F1会很低,比如0.01。你可以理解为, 模型最终学习的并不是如何分辨正负,而是学到了”负远比正的多”这样的先验信息,凭着这个信息模型就会把所有的样本都判定为负。

​ 所有,样本不均衡带来的影响就是 模型会学习到训练空间中样本比例的差距,或差距悬殊这种先验信息,以致于实际预测时就会对多数类别有侧重。

本文以正样本为少数类、负样本为多数类进行阐述。

对于简单线性可分任务,样本不均衡的影响不会很大。

2.1 采样

  • 正样本过采样
  • 如果随机的复制多分正样本进行过采样,那么必然会导致过拟合,因为训练数据中的正样本会反复出现。这种做法不建议。
  • 正样本smote
  • smote是一种合成采样的方法,它主要基于少数样本,计算样本空间之间的相似度,然后创建人工合成样本,大致流程如下:
  • 1.对于正样本(少数类)S m i n ∈ S S_{min} ∈ S S m i n ​∈S 中的样本,即x i ∈ S m i n x_i ∈ S_{min}x i ​∈S m i n ​,计算它的K个近邻;
  • 2.通过计算欧式距离,得到距离x i x_i x i ​最近的K个S m i n S_{min}S m i n ​中的样本数据;
  • 3.然后从K个近邻中,随机选择一个样本,产生人工合成的数据,K和KNN中的含义一致,属于超参;
  • 4.x n e w = x i + ( x ^ i − x i ) ∗ δ x_{new} = x_i + (\hat x_i – x_i) * \delta x n e w ​=x i ​+(x ^i ​−x i ​)∗δ,其中,x ^ i \hat x_i x ^i ​是x i x_i x i ​的其中一个近邻,δ ∈ [ 0 , 1 ] \delta ∈ [0, 1]δ∈[0 ,1 ]是一个随机数。
  • smote的方法也可能会造成过拟合,除了常用的smote之外,还有自适应合成采样,比如Borderline-SMOTE、Adaptive Synthetic Sampling(ADA-SYN),请参考:https://blog.csdn.net/hren_ron/article/details/81172044
  • 负样本欠采样
  • 在负样本空间中,随机的不放回的丢掉一些样本。
  • 因为欠采样会丢掉信息,所以可以通过Ensemble、Boosting的思想来进行欠采样。
  • EasyEnsemble
  • 利用模型融合的方法(Ensemble):多次下采样(放回采样,这样产生的训练集才相互独立)产生多个不同的训练集,进而训练多个不同的分类器,通过组合多个分类器的结果得到最终的结果。
  • BalanceCascade
  • 利用增量训练的思想(Boosting):先通过一次下采样产生训练集,训练一个分类器,对于那些分类正确的大众样本不放回,然后对这个更小的大众样本下采样产生训练集,训练第二个分类器,以此类推,最终组合所有分类器的结果得到最终结果。
  • 在计算性能足够的情况下,可以考虑数据分布的信息,通常是基于距离的邻域关系的采样方法,如ENN、NearMiss等,这里不过多介绍。

2.2 数据增强

数据增强是指从原始数据中加工出更多的数据表示,提高原数据的数量和质量,从而提高模型的学习效果。

  • 基于样本变换的数据增强
  • 单样本增强:主要用于图像,比如几何操作、颜色变换、随机查出、剪切旋转等等,可参见imgaug开源库。
  • 多样本增强:是指通过组合及转换多个样本的方式,比如刚刚提到的smote,还有SamplePairing、Mixup等方法在特征空间内构造已知样本的邻域值样本。
  • 基于深度学习的数据增强
  • 生成模型,如变分自编码网络(VAE)和生成生成对抗网络(GAN),其生成样本的方法也可以用于数据增强,这种基于网络合成的方法相比于传统的数据增强技术虽然过程复杂,但是生成的样本更加多样。

不论是过采样还是欠采样,都会引入噪声,导致过拟合,可以通过类似Pu-Learning半监督的思路选择增强数据的较优子集,以提高模型的泛化能力。

2.3 loss

loss层面的主流就是常用的 代价敏感学习,为不同的分类错误给予不同惩罚力度(权重),在调解类别平衡的同时,也不会增加计算复杂度。即对类别比例小的样本给更大的权重系数,对类别比例大的样本给更小的权重系数,通过这种方式可以在一定程度上解决正负样本不均衡的问题。

  • class weight
  • class weight可以为不同类别的样本提供不同的权重,少数类的正样本有更高的权重,从而模型可以平衡各类别的学习。如sklearn实现如下,类别权重除了设定为balanced外,还可以作为超参调试,避免决策边界偏重多数类的现象
model = LogisticRegression(class_weight={0:1,1:10})

import torch
pos_weight = num_neg / num_pos
torch.mean(pos_weight * y_true * -torch.log(y_pred) + (1 - y_true) * -torch.log(1 - y_pred))

import torch.nn as nn
loss_fn = nn.CrossEntropyLoss(weight=[1,2,1])
loss = loss_fn(output, label)
  • OHEM、Focal Loss
  • 类别不平衡可以归结为难易样本不平衡,而难易样本不平衡可以归结为梯度不平衡。OHEM和Focal Loss都做了两件事:难样本挖掘以及类别的平衡。
  • OHEM算法的核心是选择一些难样本(多样性和高损失的样本)作为训练样本,针对性的改善模型学习效果。对于数据类别不平衡问题,OHEM的针对性更强。
  • Focal Loss的核心思想是在交叉熵的基础上增加了类别的不同权重以及困难样本的权重,以改善模型学习效果。
  • 另外还有GHM、PISA等方法,可自行了解。
  • 关于Focal loss详细请看:https://blog.csdn.net/qq_42363032/article/details/121573416

2.4 模型层面

模型方面可以选择对不均衡比较不敏感的算法,例如树模型、以及集成树模型的方法。因为树模型是按照增益递归的划分数据,划分过程考虑的是局部的增益,全局样本是不均衡,但是局部空间不一定,所以比较不敏感一些些。当然这不是绝对的,相关实验可见https://arxiv.org/abs/2104.02240

解决不均衡问题,更为优秀的是基于 采样+集成树模型等方法,可以在类别不均衡数据上表现良好。

  • BalanceCascade
  • 上面也提到过,论文原文使用Adaboost作为基分类器,这里在过多啰嗦一下。
  • 核心思路就是在每一轮训练时都使用多数类与少数类数量上相等的训练集,然后使用该分类器对全体多数类进行预测,通过控制分类阈值来控制FP,将所有判断正确的删除,保留误判的,然后进入下一轮迭代继续降低多数类数量。
  • EasyEnsemble
  • 论文原文也是基于Adaboost作为基分类器,核心思路就是将多数类样本集随机分成 N 个子集,且每一个子集样本与少数类样本相同,然后分别将各个多数类样本子集与少数类样本进行组合,使用基分类模型进行训练,最后bagging集成各基分类器,得到最终模型。

通常,在数据集噪声较小的情况下,可以用BalanceCascade,可以用较少的基分类器数量得到较好的表现(基于串行的集成学习方法,对噪声敏感容易过拟合)。

噪声大的情况下,可以用EasyEnsemble,基于串行+并行的集成学习方法,bagging多个Adaboost过程可以抵消一些噪声影响。

此外还有RUSB、SmoteBoost、balanced RF等其他集成方法可以自行了解。

  • 还可以将二分类看成一分类或异常检测问题
  • 对于正负样本极不平衡的场景,我们可以换一个完全不同的角度来看待问题:把它看做一分类(One Class Learning)或异常检测(Novelty Detection)问题。这类方法的重点不在于捕捉类间的差别,而是为其中一类进行建模,经典的工作包括One-class SVM等。

from sklearn.svm import OneClassSVM

from sklearn.ensemble import IsolationForest
  • imbalance-XGBoost
  • 这是一个有关不平衡样本的XGB库,它在XGB上集成了focal loss和代价敏感学习。官网如下:https://github.com/jhwjhw0123/Imbalance-XGBoost

from imxgboost.imbalance_xgb import imbalance_xgboost as imb_xgb

base = imb_xgb(special_objective='focal', focal_gamma=focal_gamma)
base.fit(x_train, y_train)
print('base fit over')
y_test_preba = base.predict_sigmoid(x_test)

base = imb_xgb(special_objective='weighted', imbalance_alpha=imbalance_alpha)
base.fit(x_train, y_train)
print('base fit over')
y_test_preba = base.predict_sigmoid(x_test)

2.5 评估指标

机器学习正负样本失衡时的评估指标参考,及代码实现:

https://blog.csdn.net/qq_42363032/article/details/121560262

参考:

https://blog.csdn.net/u011414200/article/details/50664266

https://blog.csdn.net/qq_42363032?type=blog

Original: https://blog.csdn.net/qq_42363032/article/details/123646457
Author: WGS.
Title: 样本不平衡的解决方案(很详细)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/613737/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球