美文网首页
训练集的类别不平衡问题

训练集的类别不平衡问题

作者: Byte猫 | 来源:发表于2019-03-18 14:04 被阅读0次

在机器学习任务中,我们经常会遇到这种困扰:数据不平衡问题。
现实中有很多类别不均衡问题,它是常见的并且也是合理的符合人们期望的。如,在欺诈交易识别中,属于欺诈交易的应该是很少部分,即绝大部分交易是正常的,只有极少部分的交易属于欺诈交易。这就是一个正常的类别不均衡问题。又如,在客户流失的数据集中,绝大部分的客户是会继续享受其服务的(非流失对象),只有极少数部分的客户不会再继续享受其服务(流失对象)。
当遇到不平衡数据集时,以总体分类准确率为学习目标的传统分类算法会过多地关注多数类,从而使得少数类样本的分类性能下降。一般来说,如果类别不平衡比例超过4:1,绝大多数常见的机器学习算法就会因为数据不平衡性不能很好地工作。
在数据不均衡的情况下,我们得到90%的准确率(比如包含90%的数据类型一的实例)是因为我们的模型观察数据并且智能地总是根据数据类型一的数据进行预测,并且尽量达到最高精度。 当我们规则基于这个方法进行的时候似乎得到的是最好的答案。但是如果你在最后的模型中仔细考察这个规则,你会发现似乎这个方法是忽略其他数据在只对类型一的数据进行预测。
应对解决方法是什么呢?
迄今为止 , 解决不平衡分类问题的策略可以分为两大类。一类是从训练集入手 , 通过改变训练集样本分布降低不平衡程度;另一类是从学习算法入手 , 根据算法在解决不平衡问题时的缺陷,适当地修改算法使之适应不平衡分类问题。

一、数据层面

1、扩大数据样本

一个更大的数据集,就有可能挖掘出不同的或许更平衡的比例。

2、重采样

重采样方法是通过增加稀有类训练样本数的过采样和减少大类样本数的欠采样使不平衡的样本分布变得比较平衡(生成的数据集叫抽样数据集),从而提高分类器对稀有类的识别率 。

(1)过采样(Oversampling)

当数据量不足(一万条记录或更少)时建议使用过采样,它尝试通过增加稀有样本的数量来平衡数据集。
最原始的过采样方法是复制稀有类的样本 , 但是这样做容易导致过学习,并且对提高稀有类识别率没有太大帮助。

from sklearn.datasets import make_classification
from collections import Counter
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
                           n_redundant=0, n_repeated=0, n_classes=3,
                           n_clusters_per_class=1,
                           weights=[0.01, 0.05, 0.94],
                           class_sep=0.8, random_state=0)
print(Counter(y))
 
from imblearn.over_sampling import RandomOverSampler
 
ros = RandomOverSampler(random_state=0)
X_resampled, y_resampled = ros.fit_sample(X, y)
 
print(sorted(Counter(y_resampled).items()))

较高级的过采样方法则采用一些启发式技巧 , 有选择地复制稀有类样本 , 或者生成新的稀有类样本。
SMOTE: 随机选取少数类的样本,在该样本与最邻近的样本的连线上随机取点,生成无重复的新的稀有类样本。

from sklearn.datasets import make_classification
from collections import Counter
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
                           n_redundant=0, n_repeated=0, n_classes=3,
                           n_clusters_per_class=1,
                           weights=[0.01, 0.05, 0.94],
                           class_sep=0.8, random_state=0)
print(Counter(y))
 
from imblearn.over_sampling import SMOTE

X_resampled, y_resampled = SMOTE(kind='regular').fit_sample(X, y)
print(sorted(Counter(y_resampled).items()))

SMOTE变体: borderline1、borderline2、svm是基本的SMOTE上发展出来的变体。borderline关注在最优化决策函数边界的一些危险样本。svm使用支持向量机分类器产生支持向量然后再生成新的少数类样本。

X_resampled, y_resampled = SMOTE(kind='borderline1').fit_sample(X, y)
X_resampled, y_resampled = SMOTE(kind='borderline2').fit_sample(X, y)
X_resampled, y_resampled = SMOTE(kind='svm').fit_sample(X, y)

ADASYN: 关注的是在那些基于K最近邻分类器被错误分类的原始样本附近生成新的少数类样本

from sklearn.datasets import make_classification
from collections import Counter
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
                           n_redundant=0, n_repeated=0, n_classes=3,
                           n_clusters_per_class=1,
                           weights=[0.01, 0.05, 0.94],
                           class_sep=0.8, random_state=0)
print(Counter(y))
 
from imblearn.over_sampling import ADASYN

X_resampled, y_resampled = ADASYN().fit_sample(X, y)
print(sorted(Counter(y_resampled).items()))

(2)欠采样(Undersampling)

当数据量足够(一万或者十万条记录或更多)时使用欠采样,它记录通过减少丰富类的大小来平衡数据集。
最简单的方法是通过保存所有稀有类样本,并在丰富类别中随机选择与稀有类别样本相等数量的样本。(通过设置replacement=True参数可以实现不放回抽样)

from sklearn.datasets import make_classification
from collections import Counter
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
                           n_redundant=0, n_repeated=0, n_classes=3,
                           n_clusters_per_class=1,
                           weights=[0.01, 0.05, 0.94],
                           class_sep=0.8, random_state=0)
print(Counter(y))
 
from imblearn.under_sampling import RandomUnderSampler
rus = RandomUnderSampler(random_state=0)
X_resampled, y_resampled = rus.fit_sample(X, y)

print(sorted(Counter(y_resampled).items()))

NearMiss函数则添加了一些启发式(heuristic)的规则来选择样本,通过设定version参数(1、2、3)来实现三种启发式的规则。

from sklearn.datasets import make_classification
from collections import Counter
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
                           n_redundant=0, n_repeated=0, n_classes=3,
                           n_clusters_per_class=1,
                           weights=[0.01, 0.05, 0.94],
                           class_sep=0.8, random_state=0)
print(Counter(y))
 
from imblearn.under_sampling import NearMiss
nm = NearMiss(random_state=0, version=1)
X_resampled, y_resampled = nm.fit_sample(X, y)

print(sorted(Counter(y_resampled).items()))

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

from sklearn.datasets import make_classification
from collections import Counter
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
                           n_redundant=0, n_repeated=0, n_classes=3,
                           n_clusters_per_class=1,
                           weights=[0.01, 0.05, 0.94],
                           class_sep=0.8, random_state=0)
print(Counter(y))
 
from imblearn.under_sampling import EditedNearestNeighbours
enn = EditedNearestNeighbours(random_state=0)
X_resampled, y_resampled = enn.fit_sample(X, y)

print(sorted(Counter(y_resampled).items()))

在EditedNearestNeighbours基础上, 延伸出了RepeatedEditedNearestNeighbours算法和ALLKNN算法,前者重复基础的EditedNearestNeighbours算法多次,后者在进行每次迭代的时候,最近邻的数量都在增加。

from imblearn.under_sampling import RepeatedEditedNearestNeighbours
renn = RepeatedEditedNearestNeighbours(random_state=0)

from imblearn.under_sampling import AllKNN
allknn = AllKNN(random_state=0)

ClusterCentroids函数不是从原始数据集中直接抽取数据,每一个类别的样本都会用K-Means算法的中心点来进行合成。

from sklearn.datasets import make_classification
from collections import Counter
X, y = make_classification(n_samples=5000, n_features=2, n_informative=2,
                           n_redundant=0, n_repeated=0, n_classes=3,
                           n_clusters_per_class=1,
                           weights=[0.01, 0.05, 0.94],
                           class_sep=0.8, random_state=0)
print(Counter(y))
 
from imblearn.under_sampling import ClusterCentroids
cc = ClusterCentroids(random_state=0)
X_resampled, y_resampled = cc.fit_sample(X, y)

print(sorted(Counter(y_resampled).items()))

(3)过采样与欠采样结合

在之前的SMOTE方法中, 当由边界的样本与其他样本进行过采样差值时, 很容易生成一些噪音数据。因此, 在过采样之后需要对样本进行清洗。常见的有两种方法:SMOTETomek、SMOTEENN.

from imblearn.combine import SMOTEENN
smote_enn = SMOTEENN(random_state=0)
X_resampled, y_resampled = smote_enn.fit_sample(X, y)

from imblearn.combine import SMOTETomek
smote_tomek = SMOTETomek(random_state=0)
X_resampled, y_resampled = smote_tomek.fit_sample(X, y)

3、训练集划分方法

对训练数据集进行划分 , 是另一种有效的训练集平衡方法。一个不均衡的数据集能够通过多个均衡的子集来实现均衡。
EasyEnsemble 通过对原始的数据集进行随机下采样实现对数据集进行集成,有两个很重要的参数:n_subsets 控制的是子集的个数 ,replacement 决定是有放回还是无放回的随机采样。

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

BalanceCascade(级联平衡)的方法通过使用分类器来确保那些被错分类的样本在下一次进行子集选取的时候也能被采样到。n_max_subset 参数控制子集的个数。可以通过设置bootstrap=True来使用bootstraping(自助法)

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)

二、算法层面

所有之前的方法都集中在数据上,并将模型保持为固定的组件。但事实上,如果设计的模型适用于不平衡数据,则不需要过度关注数据。

1、 惩罚项方法

在大部分不平衡分类问题中 , 稀有类是分类的重点,在这种情况下正确识别出稀有类的样本比识别大类的样本更有价值。反过来说 , 错分稀有类的样本需要付出更大的代价。

通过设计一个代价函数来惩罚稀有类别的错误分类而不是分类丰富类别,可以设计出许多自然泛化为稀有类别的模型。例如,调整SVM以惩罚稀有类别的错误分类。

from sklearn.svm import SVC
clf = SVC(C=0.8, probability=True, class_weight={0:0.25, 1:0.75})

神经网络中也可以如此设置,下面创建了一个字典,其中,“1”类别为75%,表示了占据了75%的loss,因为比“0”的类别更加的重要,“0”的类别设置成了25%。当然,这两个数字可以修改,直到找到最佳的设置为止。我们可以使用这种方法来均衡不同的类别,当类别之间的样本数量差别很大的时候。我们可以使用权值均衡的方式来使我们的所有的类别对loss的贡献是相同的,而不用取费力的收集少数类别的样本了。

import keras
class_weight = {"1": 0.75,
                "0": 0.25}
model.fit(X_train, Y_train, epochs=10, batch_size=32, class_weight=class_weight)

2、特征选择方法

特征选择方法对于不平衡分类问题同样具有重要意义。样本数量分布很不平衡时特征的分布同样会不平衡,尤其是文本分类问题,大类中经常出现的特征也许在稀有类中根本不出现。因此 ,根据不平衡分类问题的特点 , 选取最具有区分能力的特征 ,有利于提高稀有类的识别率。
通常来说,强烈建议对于所有问题不要总是使用自己最喜欢的模型.对于所给的问题你至少应该用不同类型的算法对其进行抽查。决策树往往在处理不平衡类数据集表现不错。在创建树的过程中使用类变量的分裂规则,可以强制地将两个类很好的进行处理。 如果有疑问,请尝试一些流行的决策树算法,如C4.5,C5.0,CART和随机森林。

拓展阅读

相关文章

  • 训练集的类别不平衡问题

    在机器学习任务中,我们经常会遇到这种困扰:数据不平衡问题。现实中有很多类别不均衡问题,它是常见的并且也是合理的符合...

  • 机器学习类别不平衡解决方法

    1、前言   对于分类任务,经常会遇到类别不平衡问题(不通类别训练样本数目差距较大),本文将对该问题给出常见的解决...

  • 西瓜书_3_线性模型及python实现

    类别不平衡问题 .现有技术大体上有三类做法: 第一类是直接对训练集里的反类样例进行"欠采样" (undersamp...

  • 类别不平衡问题

      若训练样例数正例和反例的差别很大,则会对学习过程造成困扰。例如998个反例,2个正例,那么学习方法只需永远将测...

  • 训练技巧

    训练技巧 focal loss:解决类别不平衡、分类难度差异的问题,效果更好。 学习率下降 数据扩增找更多的标签数...

  • 机器学习/深度学习中的类别不均衡问题及处理方法

    类别不均衡问题 数据的类别不平衡(class imbalance),也叫数据偏斜(class skew)。 以常见...

  • Weighted cross entropy and Focal

      在CV、NLP等领域,我们会常常遇到类别不平衡的问题。比如分类,这里主要记录我实际工作中,用于处理类别不平衡问...

  • 机器学习:如何解决类别不平衡问题

    类别不平衡是一个常见问题,其中数据集中示例的分布是倾斜的或有偏差的。 1. 简介 类别不平衡是机器学习中的一个常见...

  • 类别不平衡分类问题和FocalLoss详解

    1.类别不平衡问题 一份给定的数据集中,可能出现类别不平衡,即某种类型的数量特别少,以我现在做的二分类项目为例, ...

  • 机器学习Caret--R处理不平衡数据

    不平衡数据集指的是数据集各个类别的样本数目相差巨大,例如2000的人群中,某疾病的发生只有100 (5%)人,那么...

网友评论

      本文标题:训练集的类别不平衡问题

      本文链接:https://www.haomeiwen.com/subject/lvvvmqtx.html