最新消息: 电脑我帮您提供丰富的电脑知识,编程学习,软件下载,win7系统下载。

不平衡样本处理策略

IT培训 admin 1浏览 0评论

不平衡样本处理策略

不平衡样本处理策略

文章目录

  • 不平衡样本处理策略
    • 前期准备工作
      • 不平衡数据的生成
      • logistic回归结果可视化
    • 过采样
      • 简单过采样方法
      • SMOTE
      • Borderline-SMOTE
        • borderline1
        • borderline2
    • 欠采样
      • 简单欠采样方法
      • Tomek’s Links
      • NearMiss
    • 综合采样
      • SMOTETomek
    • 样本的集成学习方法
      • EasyEnsemble
      • BalanceCascade
    • 总结

前期准备工作

不平衡数据的生成

采用sklearn.datasets的make_classification来生成试验的不平衡数据集。

from sklearn.datasets import make_classification
from collections import Counter'''
make_classification的参数说明:
n_samples=5000:生成5000个样本
n_features=2:特征数为2
n_informative=2:有用特征数为2
n_redundant=0:冗余特征数为0,冗余特征是有用特征的随机线性组合
n_repeated=0:重复特征数为0,重复特征是有用特征和冗余特征的随机线性组合
n_classes=3:样本类别数为3
n_clusters_per_class=1:每个类别只有1个簇类
weights=[0.01, 0.05, 0.94]:第0,1,2类样本数量比例采用0.01:0.05:0.94,默认为平衡
class_sep=1.5:控制簇类之间距离的参数因子为1.5,越大簇类之间离得越远
random_state=34:随机种子设为34
'''
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=1.5,random_state=34)# Counter统计各类别样本出现的次数
Counter(y)

结果

Counter({0: 65, 2: 4668, 1: 267})

make_classification生成的数据各类别的数量比例接近0.01 : 0.05 : 0.94。

也可以用计数图来可视化展示。

import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline# 画出y的计数图
sns.countplot(y)

logistic回归结果可视化

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.linear_model import LogisticRegression# 把坐标图网格划分
h = .02  # 设置网状间隔为0.2
# 规定数据X两个特征方向的最大最小值
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
# 用meshgrid产生网格数据
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),np.arange(y_min, y_max, h))# ravel()能将多维数组转换为一维数组,它跟flatten()的区别在于:
# ravel()返回的是原数据,flatten()返回的是原数据的拷贝
# np.c_的作用是按列拼接xx.ravel()和yy.ravel()
data_mesh = np.c_[xx.ravel(), yy.ravel()]# 用逻辑回归做多分类,并画出结果,写成函数方便后续调用
def lr_result_plot(X, y):# 调用LogisticRegression函数,规定相应的参数lr = LogisticRegression(solver='sag',max_iter=100,random_state=19,multi_class='multinomial').fit(X, y)# 输出训练的评价指标结果print("training score : %.3f ('multinomial')" % lr.score(X, y))# 将网格数据输入逻辑回归做预测Z = lr.predict(data_mesh)# 预测结果变换成与网格数据同样的维度Z = Z.reshape(xx.shape)plt.figure()# contour和contourf都可以画三维等高线图# 不同点在于contour()是绘制轮廓线,contourf()会填充轮廓plt.contourf(xx, yy, Z, cmap=plt.cm.Set2)plt.title("Decision surface of LogisticRegression ('multinomial')")plt.axis('tight')# 画样本的散点图,用不同颜色区分不同类的样本colors = "rby"for i,color in zip(lr.classes_, colors):# 查找类别i的所有样本的所在行数idx = np.where(y == i)# 画出样本的坐标图plt.scatter(X[idx, 0], X[idx, 1], c=color, cmap=plt.cm.hot,edgecolor='black', s=20)lr_result_plot(X, y)

分类结果如下图

红蓝黄3种颜色代表不同类别的样本,不同颜色的背景表示Logistic回归的分类结果。

后面只介绍不平衡数据处理方法中的数据处理方法。

过采样

简单过采样方法


简单过采样,即从少数类的样本中随机采样来增加新的样本,api使用RandomOverSampler。

from imblearn.over_sampling import RandomOverSamplerros = RandomOverSampler(random_state=0)
X_over_resampled, y_over_resampled = ros.fit_sample(X, y)Counter(y_over_resampled)

结果如下

Counter({0: 4668, 2: 4668, 1: 4668})

简单过采样出来的结果,各类别的数量占比是1:1:1。

# 画出逻辑回归结果
lr_result_plot(X_over_resampled, y_over_resampled)


可以看到Logistic分类平面明显向类3样本(黄色)方向推进了。

因为简单过采样是重复采样,出来的样本在图中都是重叠的,所以少数类看起来数量没有变化,其实3类数据是一样多的。

简单过采样方法容易导致过拟合(因为少数类样本重复了很多次,训练时相当于重复学习了很多次那一小撮少数类样本的特征),为避免简单重复过采样,于是有了SMOTE算法。

SMOTE

SMOTE(Synthetic Minority Oversampling Tenchnique)是一种不重复的过采样算法,它的算法步骤如下:

  1. 算法只接收少数类样本;

  2. 每个少数类样本搜索K个最近的样本;

  3. 根据所需要的采样倍数,从K个最近邻中随机抽取M个样本;

  4. 合成的样本随机地生成在少数类样本与其M个近邻点之间的连线上。


    api采用imblearn.over_sampling的SMOTE,具体使用如下:

from imblearn.over_sampling import SMOTEsmt = SMOTE()
X_smote, y_smote = smt.fit_sample(X,y)Counter(y_smote)

结果

Counter({0: 4668, 2: 4668, 1: 4668})

SMOTE算法生成的数据是平衡的。

# 画出逻辑回归结果
lr_result_plot(X_smote, y_smote)


因为SMOTE不是简单重复采样,所以从图可以很明显看出,类0样本(红色)和类1样本(蓝色)的数量有所增多。但是,图中比之前出现了更多的噪声(合成的样本跑到其他类别堆里),这是因为如果存在异常点,异常点与其近邻合成的样本很可能会变成噪声。


这是SMOTE算法非常致命的缺点,它加大了后续模型对样本的分类难度。

SMOTE算法的另一个问题是,远离两类数据边界的点合成的样本对模型分类几乎没有贡献,这是因为很多分类模型(如SVM、决策树等)都依赖于边界附近的样本做判断。

Borderline-SMOTE

为克服SMOTE算法的缺点,于是有论文提出了一种改进算法Borderline-SMOTE。

Borderline-SMOTE的思路是每个少数类样本搜索 m \text{m} m个最近邻,依据K个最近邻中多数类样本的个数 m ′ \text{m}' m′,将少数类样本分成3类:

  • NOISE(异常点): m ′ = m \text{m}' = \text{m} m′=m,即 m \text{m} m个最近邻都是多数类样本;
  • DANGER(边界点): m 2 ≤ m ′ < m \frac{\text{m}}{2} \le \text{m}' \lt \text{m} 2m​≤m′<m,即 m \text{m} m个最近邻中多数类样本不少于一半;
  • SAFE(远离边界的点): 0 ≤ m ′ < m 2 0 \le \text{m}' \lt \frac{\text{m}}{2} 0≤m′<2m​,即 m \text{m} m个最近邻中多数类样本少于一半。

后续只对DANGER样本进行SMOTE算法样本合成。


在进行SMOTE样本合成过程中,根据K个最近邻是否也包括多数类样本,Borderline-SMOTE还可以细分成两种:borderline1,borderline2。

这两种细分算法的api都采用imblearn.over_sampling中的BorderlineSMOTE。

borderline1

做SMOTE算法样本合成时,borderline1搜索的K个最近邻只针对少数类样本。


borderline1的例子代码:

from imblearn.over_sampling import BorderlineSMOTE# kind设置成采用borderline-1算法
bls1 = BorderlineSMOTE(kind='borderline-1')
X_smote_bl1, y_smote_bl1 = bls1.fit_sample(X,y)Counter(y_smote_bl1)

结果

Counter({0: 4668, 2: 4668, 1: 4668})

画逻辑回归结果

lr_result_plot(X_smote_bl1, y_smote_bl1)

borderline1合成的样本没有出现SMOTE算法的噪声现象。

borderline2

borderline2搜索的K个最近邻既包括少数类样本也包括多数类样本。

要注意的一点是,在DANGER样本与其近邻的多数类样本点之间的连线上,随机生成的合成样本只会出现在靠近DANGER样本的这半边连线上。


borderline2的例子代码:

from imblearn.over_sampling import BorderlineSMOTEbls2 = BorderlineSMOTE(kind='borderline-2')
X_smote_bl2, y_smote_bl2 = bls2.fit_sample(X,y)Counter(y_smote_bl2)

结果

Counter({0: 4667, 2: 4668, 1: 4667})

画逻辑回归结果

lr_result_plot(X_smote_bl2, y_smote_bl2)


比起borderline1,borderline2合成的样本要更加靠近多数类样本。

Borderline-SMOTE的详细原理请参考论文:

Borderline-SMOTE: A New Over-Sampling Method in Imbalanced Data Sets Learning

下载链接:.pdf

欠采样

简单欠采样方法


RandomUnderSampler函数实现的就是简单欠采样,就是从多数类中随机选择少量样本,再合并原有少数类样本作为新的训练数据集。

通过设定RandomUnderSampler中的replacement参数,可以设置是否有放回采样,True为有放回采样,False为无放回采样,默认为False。

from imblearn.under_sampling import RandomUnderSampler# 设置replacement=True,有放回采样
rus = RandomUnderSampler(random_state=0, replacement=True)
X_under_resampled, y_under_resampled = rus.fit_sample(X, y)Counter(y_under_resampled)
Counter({0: 65, 1: 65, 2: 65})

画逻辑回归结果

lr_result_plot(X_under_resampled, y_under_resampled)

Tomek’s Links

Tomek’s Links指的是属于不同类的两个点,这两个点的特别之处在于,比起自己同类的样本,它们在距离上更靠近异类样本,所以也被看作是各自类别的噪声。

下图绿圈圈起来的两个点就是Tomek’s Links。


Tomek’s Links有什么用呢?

可以用来去除噪声,通常是去除Tomek’s Links中的多数类样本,从而达到下采样的效果。


Tomek’s Links的api是TomekLinks,它的参数sampling_strategy可以控制删除Tomek’s Links中的哪个样本。

  • 如果设置sampling_strategy=auto,那就是默认sampling_strategy='not minority',即删除Tomek’s Links中的非少数类样本。

  • 如果设置sampling_strategy='not majority',会删除Tomek’s Links中的非多数类样本。

  • 如果设置sampling_strategy=all,会删除Tome’s Links中的所有样本。


给个实际的代码例子:

# 生成二分类训练样本
X, y = make_classification(n_samples=200, n_features=2, n_informative=2,n_redundant=0, n_repeated=0, n_classes=2,n_clusters_per_class=1, weights=[0.2, 0.8],class_sep=1.3, random_state=26, hypercube=True)fig, ax = plt.subplots(1, 1, figsize=(6, 6))# 画出多数类样本和少数类样本的散点图
ax.scatter(X[y==1, 0], X[y==1, 1], label='Majority class', s=20)
ax.scatter(X[y==0, 0], X[y==0, 1], label='Minority class', s=20)ax.legend()
ax.set_title('before remove TomekLinks')

上面的代码生成了如下的两类不平衡训练样本。


尝试用TomekLinks来消除噪声,sampling_strategy设置为auto,即删掉Tome’s Links中的多数类样本。

from imblearn.under_sampling import TomekLinks# TomekLinks设置成删除Tome's Links中的所有样本
tl = TomekLinks(sampling_strategy='majority')X_res, y_res = tl.fit_resample(X, y)fig, ax = plt.subplots(1, 1, figsize=(6, 6))ax.scatter(X_res[y_res==1, 0], X_res[y_res==1, 1], label='Majority class', s=20)
ax.scatter(X_res[y_res==0, 0], X_res[y_res==0, 1], label='Minority class', s=20)ax.legend()
ax.set_title('after remove TomekLinks')


可以发现,之前红圈中的蓝点都被删除掉了。

NearMiss

NearMiss函数添加了一些启发式(heuristic)的规则来选择样本,这些规则可以用于多数类的下采样。

NearMiss说明例子使用的数据生成函数设置如下:

X, y = make_classification(n_samples=1000, n_features=2, n_informative=2,n_redundant=0, n_repeated=0, n_classes=3,n_clusters_per_class=1, weights=[0.1, 0.3, 0.6],class_sep=1.3, random_state=12, hypercube=True)Counter(y)

各类的数量结果

Counter({2: 596, 1: 298, 0: 106})

生成数据的逻辑回归结果

lr_result_plot(X, y)


NearMiss使用的api是imblearn.under_sampling中的NearMiss,通过设定version参数可以选择3种启发式规则:

  • NearMiss-1

    抽取多数类样本的规则:找到离自己最近的N个少数类样本,计算平均距离,按照距离从小到大排序,根据需要的数目取靠前的样本。

    from imblearn.under_sampling import NearMiss# version=1表示采用NearMiss-1规则
    # n_neighbors就是参数N,n_neighbors=5表示选最近的5个少数类样本计算平均距离
    nm1 = NearMiss(random_state=0, n_neighbors=5, version=1)
    X_nearmiss1, y_nearmiss1 = nm1.fit_sample(X, y)Counter(y_nearmiss1)
    

    结果

    Counter({0: 106, 1: 106, 2: 106})
    

    画出逻辑回归结果

    lr_result_plot(X_nearmiss1, y_nearmiss1)
    


观察上图,NearMiss-1选取的黄色样本点是靠近离得近的少数类样本(红点),但这样容易让混在黄点附近的少数类噪声点(如上图中黄色点最右边的红点)影响选取结果。

  • NearMiss-2

    抽取多数类样本的规则:找到离自己最远的N个少数类样本,计算平均距离,按照距离从小到大排序,根据需要的数目取靠前的样本。

from imblearn.under_sampling import NearMiss# version=2表示采用NearMiss-2规则
# n_neighbors就是参数N,n_neighbors=5表示选最远的5个少数类样本计算平均距离
nm2 = NearMiss(random_state=0, version=2, n_neighbors=5)
X_nearmiss2, y_nearmiss2 = nm2.fit_sample(X, y)Counter(y_nearmiss2)

结果

Counter({0: 106, 1: 106, 2: 106})

画出逻辑回归结果

lr_result_plot(X_nearmiss2, y_nearmiss2)


观察上图,NearMiss-2选取的黄色样本点由离得远的少数类样本(红点)决定的,但同样无法排除远点存在少数类噪声点,从而影响选取结果。

  • NearMiss-3

    跟其它两种规则不同,NearMiss-3分两步走:

    首先,对每个少数类,保留离它最近的M个多数类样本;

    然后,这M个多数类样本分别找到离自己最近的N个少数类样本,计算平均距离,按照距离从小到大排序,根据需要的数目取靠前的样本。

from imblearn.under_sampling import NearMiss# version=3表示采用NearMiss-3规则
# n_neighbors_ver3就是参数M,n_neighbors_ver3=15表示保留最近的15个多数类样本
# n_neighbors就是参数N,n_neighbors=5表示选最近的5个少数类样本计算平均距离
nm3 = NearMiss(random_state=0, version=3, n_neighbors_ver3=15, n_neighbors=5)
X_nearmiss3, y_nearmiss3 = nm3.fit_sample(X, y)Counter(y_nearmiss3)

结果

Counter({0: 106, 1: 98, 2: 93})

画出逻辑回归结果

lr_result_plot(X_nearmiss3, y_nearmiss3)


相比前两种选取规则,NearMiss-3最不受噪声影响,原因在于第一步由全体少数类样本选择候选的多数类样本,虽然也会受到噪声的影响,但由于噪声样本并不多,所以整体来说候选的多数类样本能够体现大部分非噪声的少数类样本的选择。

有一点需要注意:n_neighbors_ver3为什么要取15这么大?

因为很多时候离大部分少数类最近的M个多数类样本基本是相同的,所以NearMiss-3第一步保留的多数类样本大多是重复的,不重复的数量实际很少,甚至比少数类样本量还少,所以n_neighbors_ver3必须取大一点,使得保留的不重复多数类样本起码比少数类样本要多。

综合采样

根据之前的介绍,过采样算法SMOTE的缺点之一在于,如果存在异常点,就会生成噪声。

可以结合欠采样的Tomek’s Links方法,把SMOTE产生的一部分噪声点给清理掉。

这种结合了SMOTE和Tomek’s Links的算法就叫做SMOTETomek。

SMOTETomek

from imblearn.combine import SMOTETomek
smote_tomek = SMOTETomek(random_state=0, sampling_strategy='all')
X_smote_tomek, y_smote_tomek = smote_tomek.fit_sample(X, y)Counter(y_smote_tomek)

结果

Counter({0: 4454, 2: 4355, 1: 4529})

之前单纯用SMOTE算法产生的平衡样本各类有4668个,SMOTETomek产生的各类样本明显要少了100多个,它们都是被Tomek’s Links消除的。

画逻辑回归结果

# 画出用逻辑回归结果
lr_result_plot(X_smote_tomek, y_smote_tomek)


从图来看,SMOTETomek的去噪效果并不是特别明显。

样本的集成学习方法

EasyEnsemble

一个不平衡数据集可以拆分成多个平衡的子集来实现数据均衡的目的。

根据以上想法,EasyEnsemble对多数类样本进行n次采样,生成n份子集,这n份子集分别与少数类样本合并,从而得到n份平衡的训练数据集。

后续,可以用这n份平衡的训练数据集分别训练一个基学习器,最终预测结果由n个基学习器来共同决定(对于分类,用少数服从多数投票;对于回归,取预测结果的平均值)。

EasyEnsemble有两个重要的参数:n_subsetsreplacement

n_subsets控制的是子集的个数,replacement决定是有放回还是无放回随机采样。

from imblearn.ensemble import EasyEnsemble
ee = EasyEnsemble(random_state=0, n_subsets=10)X_ee, y_ee = ee.fit_sample(X, y)print(y_ee)

结果

[[0 0 0 ... 2 2 2][0 0 0 ... 2 2 2][0 0 0 ... 2 2 2]...[0 0 0 ... 2 2 2][0 0 0 ... 2 2 2][0 0 0 ... 2 2 2]]

注意:EasyEnsemble将在imblearn的0.6版本移除,不过有相应的api可以替代,这里简单介绍一下:

  • BalancedBaggingClassifier:它其实是EasyEnsemble+基学习器(如下图所示),可以用参数base_estimator设置基学习器,最终得到的是训练好的多个基学习器的综合;

    示例代码:

    from imblearn.ensemble import BalancedBaggingClassifierlr = LogisticRegression(random_state=0, solver='lbfgs', multi_class='auto')
    bbc = BalancedBaggingClassifier(base_estimator=lr,sampling_strategy='auto',replacement=False,random_state=0)bbc.fit(X_train, y_train)y_pred = bbc.predict(X_test)
    balanced_accuracy_score(y_test, y_pred)
    

    结果

    0.8758793713213233
    
  • BalancedRandomForestClassifier:就是EasyEnsemble+决策树模型(决策树模型会在后面课程学到),跟scikit-learn中的RandomForestClassifier一样,它也有feature_importances_属性,可以查看特征的重要性;

    示例代码:

    from imblearn.ensemble import BalancedRandomForestClassifierbrf = BalancedRandomForestClassifier(n_estimators=100, random_state=0)
    brf.fit(X_train, y_train)y_pred = brf.predict(X_test)
    balanced_accuracy_score(y_test, y_pred)
    

    结果

    0.8843060148359996
    

    调用feature_importances_属性:

    brf.feature_importances_
    

    结果

    array([0.5461519, 0.4538481])
    

    两个特征的重要性是0.55 : 0.45,所以第一个特征比第二个特征重要。

  • EasyEnsembleClassifier:EasyEnsemble+AdaBoost(AdaBoost是一种集成学习方法,后面课程会学到)。

    示例代码:

    from imblearn.ensemble import EasyEnsembleClassifiereec = EasyEnsembleClassifier(random_state=0)
    eec.fit(X_train, y_train)y_pred = eec.predict(X_test)
    balanced_accuracy_score(y_test, y_pred)
    

    结果

    0.8504632525992791
    

BalanceCascade

与EasyEnsemble的并行处理不同,BalanceCascade(级联平衡)是串行的思路。

BalanceCascade先对多数类样本随机抽取一个与少数类样本量相等的子集,和少数类样本合并为一份平衡的训练数据集,用于训练一个基学习器。

训练好的基学习器对所有多数类样本进行预测,对预测正确的样本不考虑将其作为下一轮的训练样本。

依次迭代直到满足某一停止条件(达到了设定的迭代次数,或者预测错误的多数类样本少于少数类样本),BalanceCascade最终输出的是每轮迭代用于训练的平衡数据集,具体过程如下图所示。


BalanceCascade参数estimators输入的是基学习器,参数n_max_subset控制抽取多数类样本的最大子集数。

为什么是设定最大子集数,而不是指定具体输出多少个子集?

因为有可能没到规定的最大子集数,迭代就已经满足终止条件,不再进行下一轮的采样。

from imblearn.ensemble import BalanceCascade
from sklearn.linear_model import LogisticRegressionlr = LogisticRegression(solver='lbfgs', multi_class='auto', random_state=0)
bc = BalanceCascade(estimator=lr, n_max_subset=10, random_state=0)X_bc, y_bc = bc.fit_sample(X, y)print(y_bc)

结果

[[2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 22 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0][2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 22 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0][2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 22 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0][2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 22 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]

这里的结果只有4个子集,说明还没到规定的10个子集,迭代已经满足终止条件。

与EasyEnsemble一样,也有BalanceCascade+基学习器的api:

RUSBoostClassifier:可以用参数base_estimator设置基学习器,默认采用最大深度为1的决策树。

示例代码:

from imblearn.ensemble import RUSBoostClassifier
from sklearn.tree import DecisionTreeClassifierdtc = DecisionTreeClassifier(max_depth=4)
rusboost = RUSBoostClassifier(base_estimator=dtc, n_estimators=200, algorithm='SAMME.R', random_state=0)
rusboost.fit(X_train, y_train)y_pred = rusboost.predict(X_test)balanced_accuracy_score(y_test, y_pred)

结果

0.7890679195979043

EasyEnsemble和BalanceCascade的详细原理请参照论文:

Exploratory Undersampling for Class-Imbalance Learning

论文链接:.pdf

样本的集成学习方法的所有api的详细内容请参考:.html#module-imblearn.ensemble

总结

下面对不平衡样本处理策略做一个总结:

  • 过采样方法

    这部分讲了简单过采样、SMOTE和Borderline-SMOTE,SMOTE算法是为了避免重复采样导致过拟合而提出的,但SMOTE算法有两个缺点:异常点会导致噪声产生、远离边界点生成的数据对分类无影响,为克服这些缺点,于是提出了Borderline-SMOTE算法。

    过采样方法推荐使用Borderline-SMOTE算法。

  • 欠采样方法

    这部分有提到简单欠采样、Tomek’s Links和NearMiss,Tomek’s Links的功能主要是清除部分噪声,属于辅助型的算法,NearMiss通过3种样本选择的规则达到欠采样的效果。

    欠采样方法推荐使用NearMiss算法。

  • 综合采样

    这里只讲了SMOTETomek,它通过Tomek’s Links清除部分噪声的功能来弥补SMOTE算法的缺陷,但效果不太明显,不太推荐使用。

  • 样本的集成学习方法

    EasyEnsemble和BalanceCascade都是非常重要的算法,都需要学会,它们的目的都是将一个不平衡的数据集拆分成多个平衡的子集,只是EasyEnsemble采用的是并行方法,而BalanceCascade采样串行的方法。

不平衡样本处理策略

不平衡样本处理策略

文章目录

  • 不平衡样本处理策略
    • 前期准备工作
      • 不平衡数据的生成
      • logistic回归结果可视化
    • 过采样
      • 简单过采样方法
      • SMOTE
      • Borderline-SMOTE
        • borderline1
        • borderline2
    • 欠采样
      • 简单欠采样方法
      • Tomek’s Links
      • NearMiss
    • 综合采样
      • SMOTETomek
    • 样本的集成学习方法
      • EasyEnsemble
      • BalanceCascade
    • 总结

前期准备工作

不平衡数据的生成

采用sklearn.datasets的make_classification来生成试验的不平衡数据集。

from sklearn.datasets import make_classification
from collections import Counter'''
make_classification的参数说明:
n_samples=5000:生成5000个样本
n_features=2:特征数为2
n_informative=2:有用特征数为2
n_redundant=0:冗余特征数为0,冗余特征是有用特征的随机线性组合
n_repeated=0:重复特征数为0,重复特征是有用特征和冗余特征的随机线性组合
n_classes=3:样本类别数为3
n_clusters_per_class=1:每个类别只有1个簇类
weights=[0.01, 0.05, 0.94]:第0,1,2类样本数量比例采用0.01:0.05:0.94,默认为平衡
class_sep=1.5:控制簇类之间距离的参数因子为1.5,越大簇类之间离得越远
random_state=34:随机种子设为34
'''
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=1.5,random_state=34)# Counter统计各类别样本出现的次数
Counter(y)

结果

Counter({0: 65, 2: 4668, 1: 267})

make_classification生成的数据各类别的数量比例接近0.01 : 0.05 : 0.94。

也可以用计数图来可视化展示。

import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline# 画出y的计数图
sns.countplot(y)

logistic回归结果可视化

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.linear_model import LogisticRegression# 把坐标图网格划分
h = .02  # 设置网状间隔为0.2
# 规定数据X两个特征方向的最大最小值
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
# 用meshgrid产生网格数据
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),np.arange(y_min, y_max, h))# ravel()能将多维数组转换为一维数组,它跟flatten()的区别在于:
# ravel()返回的是原数据,flatten()返回的是原数据的拷贝
# np.c_的作用是按列拼接xx.ravel()和yy.ravel()
data_mesh = np.c_[xx.ravel(), yy.ravel()]# 用逻辑回归做多分类,并画出结果,写成函数方便后续调用
def lr_result_plot(X, y):# 调用LogisticRegression函数,规定相应的参数lr = LogisticRegression(solver='sag',max_iter=100,random_state=19,multi_class='multinomial').fit(X, y)# 输出训练的评价指标结果print("training score : %.3f ('multinomial')" % lr.score(X, y))# 将网格数据输入逻辑回归做预测Z = lr.predict(data_mesh)# 预测结果变换成与网格数据同样的维度Z = Z.reshape(xx.shape)plt.figure()# contour和contourf都可以画三维等高线图# 不同点在于contour()是绘制轮廓线,contourf()会填充轮廓plt.contourf(xx, yy, Z, cmap=plt.cm.Set2)plt.title("Decision surface of LogisticRegression ('multinomial')")plt.axis('tight')# 画样本的散点图,用不同颜色区分不同类的样本colors = "rby"for i,color in zip(lr.classes_, colors):# 查找类别i的所有样本的所在行数idx = np.where(y == i)# 画出样本的坐标图plt.scatter(X[idx, 0], X[idx, 1], c=color, cmap=plt.cm.hot,edgecolor='black', s=20)lr_result_plot(X, y)

分类结果如下图

红蓝黄3种颜色代表不同类别的样本,不同颜色的背景表示Logistic回归的分类结果。

后面只介绍不平衡数据处理方法中的数据处理方法。

过采样

简单过采样方法


简单过采样,即从少数类的样本中随机采样来增加新的样本,api使用RandomOverSampler。

from imblearn.over_sampling import RandomOverSamplerros = RandomOverSampler(random_state=0)
X_over_resampled, y_over_resampled = ros.fit_sample(X, y)Counter(y_over_resampled)

结果如下

Counter({0: 4668, 2: 4668, 1: 4668})

简单过采样出来的结果,各类别的数量占比是1:1:1。

# 画出逻辑回归结果
lr_result_plot(X_over_resampled, y_over_resampled)


可以看到Logistic分类平面明显向类3样本(黄色)方向推进了。

因为简单过采样是重复采样,出来的样本在图中都是重叠的,所以少数类看起来数量没有变化,其实3类数据是一样多的。

简单过采样方法容易导致过拟合(因为少数类样本重复了很多次,训练时相当于重复学习了很多次那一小撮少数类样本的特征),为避免简单重复过采样,于是有了SMOTE算法。

SMOTE

SMOTE(Synthetic Minority Oversampling Tenchnique)是一种不重复的过采样算法,它的算法步骤如下:

  1. 算法只接收少数类样本;

  2. 每个少数类样本搜索K个最近的样本;

  3. 根据所需要的采样倍数,从K个最近邻中随机抽取M个样本;

  4. 合成的样本随机地生成在少数类样本与其M个近邻点之间的连线上。


    api采用imblearn.over_sampling的SMOTE,具体使用如下:

from imblearn.over_sampling import SMOTEsmt = SMOTE()
X_smote, y_smote = smt.fit_sample(X,y)Counter(y_smote)

结果

Counter({0: 4668, 2: 4668, 1: 4668})

SMOTE算法生成的数据是平衡的。

# 画出逻辑回归结果
lr_result_plot(X_smote, y_smote)


因为SMOTE不是简单重复采样,所以从图可以很明显看出,类0样本(红色)和类1样本(蓝色)的数量有所增多。但是,图中比之前出现了更多的噪声(合成的样本跑到其他类别堆里),这是因为如果存在异常点,异常点与其近邻合成的样本很可能会变成噪声。


这是SMOTE算法非常致命的缺点,它加大了后续模型对样本的分类难度。

SMOTE算法的另一个问题是,远离两类数据边界的点合成的样本对模型分类几乎没有贡献,这是因为很多分类模型(如SVM、决策树等)都依赖于边界附近的样本做判断。

Borderline-SMOTE

为克服SMOTE算法的缺点,于是有论文提出了一种改进算法Borderline-SMOTE。

Borderline-SMOTE的思路是每个少数类样本搜索 m \text{m} m个最近邻,依据K个最近邻中多数类样本的个数 m ′ \text{m}' m′,将少数类样本分成3类:

  • NOISE(异常点): m ′ = m \text{m}' = \text{m} m′=m,即 m \text{m} m个最近邻都是多数类样本;
  • DANGER(边界点): m 2 ≤ m ′ < m \frac{\text{m}}{2} \le \text{m}' \lt \text{m} 2m​≤m′<m,即 m \text{m} m个最近邻中多数类样本不少于一半;
  • SAFE(远离边界的点): 0 ≤ m ′ < m 2 0 \le \text{m}' \lt \frac{\text{m}}{2} 0≤m′<2m​,即 m \text{m} m个最近邻中多数类样本少于一半。

后续只对DANGER样本进行SMOTE算法样本合成。


在进行SMOTE样本合成过程中,根据K个最近邻是否也包括多数类样本,Borderline-SMOTE还可以细分成两种:borderline1,borderline2。

这两种细分算法的api都采用imblearn.over_sampling中的BorderlineSMOTE。

borderline1

做SMOTE算法样本合成时,borderline1搜索的K个最近邻只针对少数类样本。


borderline1的例子代码:

from imblearn.over_sampling import BorderlineSMOTE# kind设置成采用borderline-1算法
bls1 = BorderlineSMOTE(kind='borderline-1')
X_smote_bl1, y_smote_bl1 = bls1.fit_sample(X,y)Counter(y_smote_bl1)

结果

Counter({0: 4668, 2: 4668, 1: 4668})

画逻辑回归结果

lr_result_plot(X_smote_bl1, y_smote_bl1)

borderline1合成的样本没有出现SMOTE算法的噪声现象。

borderline2

borderline2搜索的K个最近邻既包括少数类样本也包括多数类样本。

要注意的一点是,在DANGER样本与其近邻的多数类样本点之间的连线上,随机生成的合成样本只会出现在靠近DANGER样本的这半边连线上。


borderline2的例子代码:

from imblearn.over_sampling import BorderlineSMOTEbls2 = BorderlineSMOTE(kind='borderline-2')
X_smote_bl2, y_smote_bl2 = bls2.fit_sample(X,y)Counter(y_smote_bl2)

结果

Counter({0: 4667, 2: 4668, 1: 4667})

画逻辑回归结果

lr_result_plot(X_smote_bl2, y_smote_bl2)


比起borderline1,borderline2合成的样本要更加靠近多数类样本。

Borderline-SMOTE的详细原理请参考论文:

Borderline-SMOTE: A New Over-Sampling Method in Imbalanced Data Sets Learning

下载链接:.pdf

欠采样

简单欠采样方法


RandomUnderSampler函数实现的就是简单欠采样,就是从多数类中随机选择少量样本,再合并原有少数类样本作为新的训练数据集。

通过设定RandomUnderSampler中的replacement参数,可以设置是否有放回采样,True为有放回采样,False为无放回采样,默认为False。

from imblearn.under_sampling import RandomUnderSampler# 设置replacement=True,有放回采样
rus = RandomUnderSampler(random_state=0, replacement=True)
X_under_resampled, y_under_resampled = rus.fit_sample(X, y)Counter(y_under_resampled)
Counter({0: 65, 1: 65, 2: 65})

画逻辑回归结果

lr_result_plot(X_under_resampled, y_under_resampled)

Tomek’s Links

Tomek’s Links指的是属于不同类的两个点,这两个点的特别之处在于,比起自己同类的样本,它们在距离上更靠近异类样本,所以也被看作是各自类别的噪声。

下图绿圈圈起来的两个点就是Tomek’s Links。


Tomek’s Links有什么用呢?

可以用来去除噪声,通常是去除Tomek’s Links中的多数类样本,从而达到下采样的效果。


Tomek’s Links的api是TomekLinks,它的参数sampling_strategy可以控制删除Tomek’s Links中的哪个样本。

  • 如果设置sampling_strategy=auto,那就是默认sampling_strategy='not minority',即删除Tomek’s Links中的非少数类样本。

  • 如果设置sampling_strategy='not majority',会删除Tomek’s Links中的非多数类样本。

  • 如果设置sampling_strategy=all,会删除Tome’s Links中的所有样本。


给个实际的代码例子:

# 生成二分类训练样本
X, y = make_classification(n_samples=200, n_features=2, n_informative=2,n_redundant=0, n_repeated=0, n_classes=2,n_clusters_per_class=1, weights=[0.2, 0.8],class_sep=1.3, random_state=26, hypercube=True)fig, ax = plt.subplots(1, 1, figsize=(6, 6))# 画出多数类样本和少数类样本的散点图
ax.scatter(X[y==1, 0], X[y==1, 1], label='Majority class', s=20)
ax.scatter(X[y==0, 0], X[y==0, 1], label='Minority class', s=20)ax.legend()
ax.set_title('before remove TomekLinks')

上面的代码生成了如下的两类不平衡训练样本。


尝试用TomekLinks来消除噪声,sampling_strategy设置为auto,即删掉Tome’s Links中的多数类样本。

from imblearn.under_sampling import TomekLinks# TomekLinks设置成删除Tome's Links中的所有样本
tl = TomekLinks(sampling_strategy='majority')X_res, y_res = tl.fit_resample(X, y)fig, ax = plt.subplots(1, 1, figsize=(6, 6))ax.scatter(X_res[y_res==1, 0], X_res[y_res==1, 1], label='Majority class', s=20)
ax.scatter(X_res[y_res==0, 0], X_res[y_res==0, 1], label='Minority class', s=20)ax.legend()
ax.set_title('after remove TomekLinks')


可以发现,之前红圈中的蓝点都被删除掉了。

NearMiss

NearMiss函数添加了一些启发式(heuristic)的规则来选择样本,这些规则可以用于多数类的下采样。

NearMiss说明例子使用的数据生成函数设置如下:

X, y = make_classification(n_samples=1000, n_features=2, n_informative=2,n_redundant=0, n_repeated=0, n_classes=3,n_clusters_per_class=1, weights=[0.1, 0.3, 0.6],class_sep=1.3, random_state=12, hypercube=True)Counter(y)

各类的数量结果

Counter({2: 596, 1: 298, 0: 106})

生成数据的逻辑回归结果

lr_result_plot(X, y)


NearMiss使用的api是imblearn.under_sampling中的NearMiss,通过设定version参数可以选择3种启发式规则:

  • NearMiss-1

    抽取多数类样本的规则:找到离自己最近的N个少数类样本,计算平均距离,按照距离从小到大排序,根据需要的数目取靠前的样本。

    from imblearn.under_sampling import NearMiss# version=1表示采用NearMiss-1规则
    # n_neighbors就是参数N,n_neighbors=5表示选最近的5个少数类样本计算平均距离
    nm1 = NearMiss(random_state=0, n_neighbors=5, version=1)
    X_nearmiss1, y_nearmiss1 = nm1.fit_sample(X, y)Counter(y_nearmiss1)
    

    结果

    Counter({0: 106, 1: 106, 2: 106})
    

    画出逻辑回归结果

    lr_result_plot(X_nearmiss1, y_nearmiss1)
    


观察上图,NearMiss-1选取的黄色样本点是靠近离得近的少数类样本(红点),但这样容易让混在黄点附近的少数类噪声点(如上图中黄色点最右边的红点)影响选取结果。

  • NearMiss-2

    抽取多数类样本的规则:找到离自己最远的N个少数类样本,计算平均距离,按照距离从小到大排序,根据需要的数目取靠前的样本。

from imblearn.under_sampling import NearMiss# version=2表示采用NearMiss-2规则
# n_neighbors就是参数N,n_neighbors=5表示选最远的5个少数类样本计算平均距离
nm2 = NearMiss(random_state=0, version=2, n_neighbors=5)
X_nearmiss2, y_nearmiss2 = nm2.fit_sample(X, y)Counter(y_nearmiss2)

结果

Counter({0: 106, 1: 106, 2: 106})

画出逻辑回归结果

lr_result_plot(X_nearmiss2, y_nearmiss2)


观察上图,NearMiss-2选取的黄色样本点由离得远的少数类样本(红点)决定的,但同样无法排除远点存在少数类噪声点,从而影响选取结果。

  • NearMiss-3

    跟其它两种规则不同,NearMiss-3分两步走:

    首先,对每个少数类,保留离它最近的M个多数类样本;

    然后,这M个多数类样本分别找到离自己最近的N个少数类样本,计算平均距离,按照距离从小到大排序,根据需要的数目取靠前的样本。

from imblearn.under_sampling import NearMiss# version=3表示采用NearMiss-3规则
# n_neighbors_ver3就是参数M,n_neighbors_ver3=15表示保留最近的15个多数类样本
# n_neighbors就是参数N,n_neighbors=5表示选最近的5个少数类样本计算平均距离
nm3 = NearMiss(random_state=0, version=3, n_neighbors_ver3=15, n_neighbors=5)
X_nearmiss3, y_nearmiss3 = nm3.fit_sample(X, y)Counter(y_nearmiss3)

结果

Counter({0: 106, 1: 98, 2: 93})

画出逻辑回归结果

lr_result_plot(X_nearmiss3, y_nearmiss3)


相比前两种选取规则,NearMiss-3最不受噪声影响,原因在于第一步由全体少数类样本选择候选的多数类样本,虽然也会受到噪声的影响,但由于噪声样本并不多,所以整体来说候选的多数类样本能够体现大部分非噪声的少数类样本的选择。

有一点需要注意:n_neighbors_ver3为什么要取15这么大?

因为很多时候离大部分少数类最近的M个多数类样本基本是相同的,所以NearMiss-3第一步保留的多数类样本大多是重复的,不重复的数量实际很少,甚至比少数类样本量还少,所以n_neighbors_ver3必须取大一点,使得保留的不重复多数类样本起码比少数类样本要多。

综合采样

根据之前的介绍,过采样算法SMOTE的缺点之一在于,如果存在异常点,就会生成噪声。

可以结合欠采样的Tomek’s Links方法,把SMOTE产生的一部分噪声点给清理掉。

这种结合了SMOTE和Tomek’s Links的算法就叫做SMOTETomek。

SMOTETomek

from imblearn.combine import SMOTETomek
smote_tomek = SMOTETomek(random_state=0, sampling_strategy='all')
X_smote_tomek, y_smote_tomek = smote_tomek.fit_sample(X, y)Counter(y_smote_tomek)

结果

Counter({0: 4454, 2: 4355, 1: 4529})

之前单纯用SMOTE算法产生的平衡样本各类有4668个,SMOTETomek产生的各类样本明显要少了100多个,它们都是被Tomek’s Links消除的。

画逻辑回归结果

# 画出用逻辑回归结果
lr_result_plot(X_smote_tomek, y_smote_tomek)


从图来看,SMOTETomek的去噪效果并不是特别明显。

样本的集成学习方法

EasyEnsemble

一个不平衡数据集可以拆分成多个平衡的子集来实现数据均衡的目的。

根据以上想法,EasyEnsemble对多数类样本进行n次采样,生成n份子集,这n份子集分别与少数类样本合并,从而得到n份平衡的训练数据集。

后续,可以用这n份平衡的训练数据集分别训练一个基学习器,最终预测结果由n个基学习器来共同决定(对于分类,用少数服从多数投票;对于回归,取预测结果的平均值)。

EasyEnsemble有两个重要的参数:n_subsetsreplacement

n_subsets控制的是子集的个数,replacement决定是有放回还是无放回随机采样。

from imblearn.ensemble import EasyEnsemble
ee = EasyEnsemble(random_state=0, n_subsets=10)X_ee, y_ee = ee.fit_sample(X, y)print(y_ee)

结果

[[0 0 0 ... 2 2 2][0 0 0 ... 2 2 2][0 0 0 ... 2 2 2]...[0 0 0 ... 2 2 2][0 0 0 ... 2 2 2][0 0 0 ... 2 2 2]]

注意:EasyEnsemble将在imblearn的0.6版本移除,不过有相应的api可以替代,这里简单介绍一下:

  • BalancedBaggingClassifier:它其实是EasyEnsemble+基学习器(如下图所示),可以用参数base_estimator设置基学习器,最终得到的是训练好的多个基学习器的综合;

    示例代码:

    from imblearn.ensemble import BalancedBaggingClassifierlr = LogisticRegression(random_state=0, solver='lbfgs', multi_class='auto')
    bbc = BalancedBaggingClassifier(base_estimator=lr,sampling_strategy='auto',replacement=False,random_state=0)bbc.fit(X_train, y_train)y_pred = bbc.predict(X_test)
    balanced_accuracy_score(y_test, y_pred)
    

    结果

    0.8758793713213233
    
  • BalancedRandomForestClassifier:就是EasyEnsemble+决策树模型(决策树模型会在后面课程学到),跟scikit-learn中的RandomForestClassifier一样,它也有feature_importances_属性,可以查看特征的重要性;

    示例代码:

    from imblearn.ensemble import BalancedRandomForestClassifierbrf = BalancedRandomForestClassifier(n_estimators=100, random_state=0)
    brf.fit(X_train, y_train)y_pred = brf.predict(X_test)
    balanced_accuracy_score(y_test, y_pred)
    

    结果

    0.8843060148359996
    

    调用feature_importances_属性:

    brf.feature_importances_
    

    结果

    array([0.5461519, 0.4538481])
    

    两个特征的重要性是0.55 : 0.45,所以第一个特征比第二个特征重要。

  • EasyEnsembleClassifier:EasyEnsemble+AdaBoost(AdaBoost是一种集成学习方法,后面课程会学到)。

    示例代码:

    from imblearn.ensemble import EasyEnsembleClassifiereec = EasyEnsembleClassifier(random_state=0)
    eec.fit(X_train, y_train)y_pred = eec.predict(X_test)
    balanced_accuracy_score(y_test, y_pred)
    

    结果

    0.8504632525992791
    

BalanceCascade

与EasyEnsemble的并行处理不同,BalanceCascade(级联平衡)是串行的思路。

BalanceCascade先对多数类样本随机抽取一个与少数类样本量相等的子集,和少数类样本合并为一份平衡的训练数据集,用于训练一个基学习器。

训练好的基学习器对所有多数类样本进行预测,对预测正确的样本不考虑将其作为下一轮的训练样本。

依次迭代直到满足某一停止条件(达到了设定的迭代次数,或者预测错误的多数类样本少于少数类样本),BalanceCascade最终输出的是每轮迭代用于训练的平衡数据集,具体过程如下图所示。


BalanceCascade参数estimators输入的是基学习器,参数n_max_subset控制抽取多数类样本的最大子集数。

为什么是设定最大子集数,而不是指定具体输出多少个子集?

因为有可能没到规定的最大子集数,迭代就已经满足终止条件,不再进行下一轮的采样。

from imblearn.ensemble import BalanceCascade
from sklearn.linear_model import LogisticRegressionlr = LogisticRegression(solver='lbfgs', multi_class='auto', random_state=0)
bc = BalanceCascade(estimator=lr, n_max_subset=10, random_state=0)X_bc, y_bc = bc.fit_sample(X, y)print(y_bc)

结果

[[2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 22 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0][2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 22 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0][2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 22 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0][2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 22 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]

这里的结果只有4个子集,说明还没到规定的10个子集,迭代已经满足终止条件。

与EasyEnsemble一样,也有BalanceCascade+基学习器的api:

RUSBoostClassifier:可以用参数base_estimator设置基学习器,默认采用最大深度为1的决策树。

示例代码:

from imblearn.ensemble import RUSBoostClassifier
from sklearn.tree import DecisionTreeClassifierdtc = DecisionTreeClassifier(max_depth=4)
rusboost = RUSBoostClassifier(base_estimator=dtc, n_estimators=200, algorithm='SAMME.R', random_state=0)
rusboost.fit(X_train, y_train)y_pred = rusboost.predict(X_test)balanced_accuracy_score(y_test, y_pred)

结果

0.7890679195979043

EasyEnsemble和BalanceCascade的详细原理请参照论文:

Exploratory Undersampling for Class-Imbalance Learning

论文链接:.pdf

样本的集成学习方法的所有api的详细内容请参考:.html#module-imblearn.ensemble

总结

下面对不平衡样本处理策略做一个总结:

  • 过采样方法

    这部分讲了简单过采样、SMOTE和Borderline-SMOTE,SMOTE算法是为了避免重复采样导致过拟合而提出的,但SMOTE算法有两个缺点:异常点会导致噪声产生、远离边界点生成的数据对分类无影响,为克服这些缺点,于是提出了Borderline-SMOTE算法。

    过采样方法推荐使用Borderline-SMOTE算法。

  • 欠采样方法

    这部分有提到简单欠采样、Tomek’s Links和NearMiss,Tomek’s Links的功能主要是清除部分噪声,属于辅助型的算法,NearMiss通过3种样本选择的规则达到欠采样的效果。

    欠采样方法推荐使用NearMiss算法。

  • 综合采样

    这里只讲了SMOTETomek,它通过Tomek’s Links清除部分噪声的功能来弥补SMOTE算法的缺陷,但效果不太明显,不太推荐使用。

  • 样本的集成学习方法

    EasyEnsemble和BalanceCascade都是非常重要的算法,都需要学会,它们的目的都是将一个不平衡的数据集拆分成多个平衡的子集,只是EasyEnsemble采用的是并行方法,而BalanceCascade采样串行的方法。

11136

与本文相关的文章

发布评论

评论列表 (0)

  1. 暂无评论