欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

样本不平衡处理

程序员文章站 2022-06-12 16:54:56
...

一.过采样(Over sampling)

1.朴素随机过采样(Random over sampling)

从少数类的样本中进行随机采样来增加新的样本,RandomOverSampler 函数就能实现上述的功能。

from imblearn.over_sampling import RandomOverSampler
ros = RandomOverSampler(random_state=0)
X_resampled, y_resampled = ros.fit_sample(X, y)

2.SMOTE和ADASYN算法的基本思想:

(smote:对于少数类样本a, 随机选择一个最近邻的样本b, 然后从a与b的连线上随机选取一个点c作为新的少数类样本;)
(adasyn:关注的是在那些基于K最近邻分类器被错误分类的原始样本附近生成新的少数类样本)

  1. 采样最邻近算法,计算出每个少数类样本的K个近邻;
  2. 从K个近邻中随机挑选N个样本进行随机线性插值;
  3. 构造新的少数类样本;
  4. 将新样本与原数据合成,产生新的训练集;

代码实现:

from imblearn.over_sampling import SMOTE,ADASYN
smote = SMOTE(ratio=’auto’, random_state=None, k_neighbors=5, m_neighbors=10,
	 out_step=0.5, kind=’regular’, svm_estimator=None, n_jobs=1)
ada = ADASYN()
X_oversampled, y_oversampled = smote.fit_sample(X,y)
X_oversampled, y_oversampled = ada.fit_sample(X,y)

参数说明:

  • ratio:用于指定重抽样的比例,如果指定字符型的值,可以是’minority’,表示对少数类别的样本进行抽样、’majority’,表示对多数类别的样本进行抽样、’not minority’表示采用欠采样方法、’all’表示采用过采样方法,默认为’auto’,等同于’all’和’not minority’;如果指定字典型的值,其中键为各个类别标签,值为类别下的样本量;
  • random_state:用于指定随机数生成器的种子,默认为None,表示使用默认的随机数生成器;
  • k_neighbors:指定近邻个数,默认为5个;
  • m_neighbors:指定从近邻样本中随机挑选的样本个数,默认为10个;
  • kind:用于指定SMOTE算法在生成新样本时所使用的选项,默认为’regular’,表示对少数类别的样本进行随机采样,也可以是’borderline1’、’borderline2’和’svm’;
  • svm_estimator:用于指定SVM分类器,默认为sklearn.svm.SVC,该参数的目的是利用支持向量机分类器生成支持向量,然后再生成新的少数类别的样本;
  • n_jobs:用于指定SMOTE算法在过采样时所需的CPU数量,默认为1表示仅使用1个CPU运行算法,即不使用并行运算功能;

检查样本比例

print(y.value_counts()/len(y))

二.下采样(Under_sampling)

1.原型生成(prototype generation)

给定数据集S,原型生成算法将生成一个子集S’, 其中|S’| < |S|。其中S’中的数据是由S中数据生成,并不直接取之而来。
ClusterCentroids函数实现了上述功能: 每一个类别的样本都会用K-Means算法的中心点来进行合成, 而不是随机从原始样本进行抽取.

代码实现:

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

2.原型选择(prototype selection)

与原型生成不同的是, 原型选择算法是直接从原始数据集中进行抽取. 抽取的方法大概可以分为两类:
(i) 可控的下采样技术(the controlled under-sampling techniques) ;
第一类的方法可以由用户指定下采样抽取的子集中样本的数量;
(ii) the cleaning under-sampling techniques;
第二类方法则不接受这种用户的干预.

2.1Controlled under-sampling techniques

2.1.1 RandomUnderSampler方法
:随机选取数据的子集
代码实现:

from imblearn.under_sampling import RandomUnderSampler
rus = RandomUnderSampler(random_state=0)  # replacement=True参数, 可以实现自助法(boostrap)抽样,默认不放回采样。
X_resampled, y_resampled = rus.fit_sample(X, y)

2.1.2 NearMiss方法
:通过一些启发式(heuristic)的规则来选择样本, 通过设定version参数来实现三种启发式的规则(假设负样本为小数样本,正样本需要下采样。)

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

代码实现:

from imblearn.under_sampling import NearMiss
nm1 = NearMiss(random_state=0, version=1)
X_resampled, y_resampled = nm1.fit_sample(X, y)

2.2 the cleaning under-sampling techniques

2.2.1 Tomek’s links
:样本x与样本y来自于不同的类别,不存在样本z使得d(x,z) < d(x,y) 或者 d(y,z) < d(x,y)成立,即两个样本之间互为近邻关系. 这个时候, 样本x或样本y很有可能是噪声数据, 或者两个样本在边界的位置附近.
TomekLinks函数中的auto参数控制Tomek’s links中的哪些样本被剔除. 默认的ratio=‘auto’ 移除多数类的样本, 当ratio='all’时, 两个样本均被移除.

代码实现:

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

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

代码实现:

from imblearn.under_sampling import EditedNearestNeighbours,RepeatedEditedNearestNeighbours,AllKNN
enn = EditedNearestNeighbours(random_state=0)
X_resampled, y_resampled = enn.fit_sample(X, y)
### RepeatedEditedNearestNeighbours(单纯的多次迭代),AllKNN算法是EditedNearestNeighbours(迭代时,最近邻数量都在增加)算法的衍生。

2.2.3 Condensed nearest neighbors and derived algorithms
:CondensedNearestNeighbour 使用1近邻的方法来进行迭代, 来判断一个样本是应该保留还是剔除, 具体的实现步骤如下:
(对噪音数据是很敏感的, 也容易加入噪音数据到集合C中)

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

代码实现:

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

基于EditedNearestNeighbours和 3-NN分类器清洗数据,拒绝样本之间的并集:

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

2.2.4 Instance hardness threshold
:InstanceHardnessThreshold是一种很特殊的方法, 是在数据上运用一种分类器, 然后将概率低于阈值的样本剔除掉.

代码实现:

from imblearn.under_sampling import InstanceHardnessThreshold
iht = InstanceHardnessThreshold(random_state=0,
                                estimator=LogisticRegression())
X_resampled, y_resampled = iht.fit_sample(X, y)

三. 过采样与下采样结合

过采样(如SMOTE方法)过程中容易产生以下噪音数据,过采样之后需要进行数据清洗,如是就产生了两种过采样和下采样结合方式:
(i) SMOTETomek
(ii) 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)

四. Ensemble方法

一个不均衡的数据集能够通过多个均衡的子集来实现均衡, imblearn.ensemble模块能实现上述功能.EasyEnsemble 通过对原始的数据集进行随机下采样实现对数据集进行集成.

4.1.1 EasyEnsemble

代码实现:

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

参数说明:

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

4.1.2 BalanceCascade

与EasyEnsemble方法不同,(级联平衡)的方法通过使用分类器(estimator参数)来确保那些被错分类的样本在下一次进行子集选取的时候也能被采样到.

代码实现:

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

参数说明:

  • n_max_subset 参数控制子集的个数
  • bootstrap=True来使用bootstraping(自助法)

4.2 Chaining ensemble of samplers and estimators

装袋方法(Bagging)在不同的随机选取的数据集上建立了多个估计量. 在scikit-learn中这个分类器叫做BaggingClassifier. 然而, 该分类器并不允许对每个数据集进行均衡. 因此, 在对不均衡样本进行训练的时候, 分类器其实是有偏的, 偏向于多数类.

代码实现:

from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
bc = BaggingClassifier(base_estimator=DecisionTreeClassifier(),
                       random_state=0)
bc.fit(X_train, y_train) 
y_pred = bc.predict(y_test)

BalancedBaggingClassifier 允许在训练每个基学习器之前对每个子集进行重抽样. 简而言之, 该方法结合了EasyEnsemble采样器与分类器(如BaggingClassifier)的结果.

from imblearn.ensemble import BalancedBaggingClassifier
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
bbc = BalancedBaggingClassifier(base_estimator=DecisionTreeClassifier(),
                                ratio='auto',
                                replacement=False,
                                random_state=0)
bbc.fit(X, y) 
y_pred = bbc.predict(y_test)

###参考