机器学习超详细实践攻略(23):三板斧干掉样本不均衡问题之3——通过集成学习方法解决样本不均衡

在这里插入图片描述

一、原理

本文是处理样本不均衡的第三种方法。思路也很简单:从样本量比较多的类别中随机抽取一定数量的样本,与样本量比较小的类别组合在一块儿训练模型。这样会训练出好几个模型,最后在应用时,使用组合的方法(例如投票、加权投票等)产生分类预测结果。例如,若数据集中的正、负样本的比例为1:10。此时可以将负样本随机分为10份(或者每次随机抽取和正样本相同数量的负样本),然后和所有的正样本组成训练集。这样可以得到10个训练集,分别输入模型之后就可以得到10个训练模型。

这种方式其实借鉴了集成学习中的bagging思想,随机森林也是采用这种思想。但是因为这种方法要分别训练多个模型,所以耗时比较长。如果等得起,相对于单一模型绝对可以得到一个更好的提升。

小时候看《西游记》,太上老君的炼丹炉里,炼了九九八十一天的仙丹,绝对会比练了七七四十九天的仙丹有更厉害的功效,果然小说来源于生活。

二、实现

具体操作:类似于scikit-learn中的BaggingClassifier类。只是scikit-learn没有实现在不同类别中分别采样的功能,所以我们依旧借助imbalanced-learn包来进行预处理。

特别提醒一句:安装这个包使用以下语句:pip install imbalanced-learn,而导入这个包只需要:import imblearn即可。

因为imblearn包也基于scikit-learn实现了随机森林算法,而且加了一个sampling_strategy参数来控制不同类别的采样方式,我们比较一下两个算法的准确率。

sampling_strategy参数选参数如下:

  • 浮点数:这个数值 = 采样之后的少数类样本数/多数类样本数。需要注意的是,浮点数只能应用在二分类问题中。
  • ’majority’: 只对数量较多的类别进行重新采样
  • ’not minority’: 对除数量较少的类以外的所有类重新采样
  • ’not majority’: 对除数量较多的类以外的所有类重新采样
  • ’all’: 重采样所有类别,类似于scikit-learn中的
  • ’auto’: 和 'not minority’效果相同,也是这个参数的默认值
  • 字典形式:形式为:{类别1:个数1,类别2:个数2}

我们对比一下不加处理的随机森林算法和采样时注重数据集均衡的情况下模型的表现。

1)导入相关的包和生成数据集

from imblearn.ensemble import BalancedRandomForestClassifier #导入imblearn中随机森林包
from sklearn.ensemble import RandomForestClassifier #导入sklearn中的随机森林包
from sklearn.model_selection import train_test_split
from sklearn.metrics import recall_score
import numpy as np
############################ 生成不均衡的分类数据集###########
from sklearn import datasets
X,Y = datasets.make_classification(n_samples = 10000,
                                   n_features = 4,
                                   n_classes = 2,
                                   weights = [0.95,0.05])

train_x,test_x,train_y,test_y = train_test_split(X,Y,test_size=0.1,random_state=0)

这里,我们生成了数据集大小为10000的数据集。

2)sklearn包中的随机森林算法训练模型

###############随机森林实现##################
from sklearn.ensemble import RandomForestClassifier 
RF = RandomForestClassifier(random_state = 66,
                            n_estimators = 100)

RF.fit(train_x, train_y)
y_pred1 = RF.predict(test_x)

print('召回率: ',recall_score(test_y, y_pred1))

输出:

召回率: 0.625

3)imblearn包中的随机森林算法训练模型

eec = EasyEnsembleClassifier(random_state = 66,sampling_strategy = 'not minority',n_estimators = 100)
eec.fit(train_x, train_y) # 

y_pred = eec.predict(test_x)
print('召回率: ',recall_score(test_y, y_pred))

输出:

召回率: 0.9166666666666666

在两个算法中,我们控制其生成了相同的树的棵数,只是第二个随机森林算法中,每次使用所用的少数类样本,然后抽取等量的多数类样本组成训练集进行训练。

可以看到,虽然第二种算法可能因为采样过程更为复杂,所以耗时更长,但是获得了更好的召回率。

如果想训练多个SVM等算法进行集成学习,可以使用imblearn中的ensemble.BalancedBaggingClassifier这个包,可以自己定义子算法。

【注:在0.2版本中,还可以使用imblearn.ensemble.EasyEnsemble这个函数来随机划分数据集,但是这个 函数在0.6版本之后这个函数就已经移除了。】

三、样本极度不平衡的一个新奇的解决思路

对于二分类问题,如果正负样本分布比例极度不平衡,我们可以换一个角度来看待问题:把它看做一分类(One Class Learning)或异常检测(Novelty Detection)问题。

仔细想想,银行业务中的洗钱交易、信用卡中的不良贷款都算是在大多数正常行为中的一些异常行为。这也启示我们,有时候换个角度想想,问题就会有新的解决方案。

而这类异常检测方法的重点不在于捕捉类间的差别,而是找到其中我们关注的一类的特征,不符合这类特征的,都可以算作是另外一类。主要用到的方法是一类SVM(One-class SVM)算法。

One Class SVM 是指你的训练数据只有一类正(或者负)样本的数据, 而没有另外的一类。在这时,你需要学习的实际上你训练数据的边界。而这时不能使用最大化软边缘了,因为你没有两类的数据。模型的训练目标就是找一个离这一类的聚集点比较远的边界。

在scikit-learn中也有One-class SVM的实现,可以参考以下链接:sklearn.svm.OneClassSVM

本系列相关文章

发布了67 篇原创文章 · 获赞 204 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/u013044310/article/details/104096078