解决各种机器学习中样本不均衡问题的整合

前言

大部分分类任务中,各类别下的数据个数基本上不可能完全相等,但是一点点差异是不会产生任何影响与问题的。在现实中有很多类别不均衡问题,它是常见的,并且也是合理的,符合人们期望的。如,在欺诈交易识别中,属于欺诈交易的应该是很少部分,即绝大部分交易是正常的,只有极少部分的交易属于欺诈交易。这就是一个正常的类别不均衡问题。又如,在客户流失的数据集中,绝大部分的客户是会继续享受其服务的(非流失对象),只有极少数部分的客户不会再继续享受其服务(流失对象)。一般而已,如果类别不平衡比例超过4:1,那么其分类器会大大地因为数据不平衡性而无法满足分类要求的。因此在构建分类模型之前,需要对分类不均衡性问题进行处理。 
  
解决这一问题的基本思路是让正负样本在训练过程中拥有相同的话语权,比如利用采样与加权等方法。为了方便起见,我们把数据集中样本较多的那一类称为“大众类”,样本较少的那一类称为“小众类”。 

一、解决方式汇总图: 


二、解决方式的使用场景

解决数据不平衡问题的方法有很多,上面只是一些最常用的方法,而最常用的方法也有这么多种,如何根据实际问题选择合适的方法:

1、在正负样本都非常之少的情况下,应该采用数据合成的方式;
2、在负样本足够多,正样本非常之少且比例及其悬殊的情况下,应该考虑一分类方法;
3、在正负样本都足够多且比例不是特别悬殊的情况下,应该考虑采样或者加权的方法;
4、采样和加权在数学上是等价的,但实际应用中效果却有差别。尤其是采样了诸如Random Forest等分类方法,训练过程会对训练集进行随机采样。在这种情况下,如果计算资源允许上采样往往要比加权好一些。

另外,虽然上采样和下采样都可以使数据集变得平衡,并且在数据足够多的情况下等价,但两者也是有区别的。实际应用中,我的经验是如果计算资源足够且小众类样本足够多的情况下使用上采样,否则使用下采样,因为上采样会增加训练集的大小进而增加训练时间,同时小的训练集非常容易产生过拟合。 
对于下采样,如果计算资源相对较多且有良好的并行环境,应该选择Ensemble方法。

三、评估标准需要改变

对于样本基本均衡的分类任务,我们使用准确度这个指标来评价分类质量,可以看出,在类别不均衡时,准确度这个评价指标并不能work。因为分类器将所有的样本都分类到大类下面时,该指标值仍然会很高。即,该分类器偏向了大类这个类别的数据,在总量中占少数的类别的特征就会被视为噪声,并且通常会被忽略。因此,与多数类别相比,少数类别存在比较高的误判率。对分类算法的表现的评估是用一个包含关于实际类别和预测类别信息的混淆矩阵(Confusion Matrix)来衡量的。

四、大牛对样本不均衡的理解

https://blog.csdn.net/heyongluoyao8/article/details/49408131

五、各方法的实际案例

https://www.cnblogs.com/huanjing/p/6789731.html

六、实战代码:Python处理样本不均衡

示例中,我们主要使用一个新的专门用于不平衡数据处理的Python包imbalanced-learn,读者需要先在系统终端的命令行使用pip install imbalanced-learn进行安装;安装成功后,在Python或IPython命令行窗口通过使用import imblearn(注意导入的库名)检查安装是否正确,示例代码包版本为0.2.1。除此以外,我们还会使用sklearn的SVM在算法中通过调整类别权重来处理样本不均衡问题。

完整代码如下:

import pandas as pd
from imblearn.over_sampling import SMOTE # 过抽样处理库SMOTE
from imblearn.under_sampling import RandomUnderSampler # 欠抽样处理库RandomUnderSampler
from sklearn.svm import SVC #SVM中的分类算法SVC
from imblearn.ensemble import EasyEnsemble # 简单集成方法EasyEnsemble
 
# 导入数据文件
df = pd.read_table('data2.txt', sep=' ', names=['col1', 'col2','col3', 'col4', 'col5', 'label']) # 读取数据文件
x = df.iloc[:, :-1] # 切片,得到输入x
y = df.iloc[:, -1] # 切片,得到标签y
groupby_data_orgianl = df.groupby('label').count() # 对label做分类汇总
print (groupby_data_orgianl) # 打印输出原始数据集样本分类分布
 
# 使用SMOTE方法进行过抽样处理
model_smote = SMOTE() # 建立SMOTE模型对象
x_smote_resampled, y_smote_resampled = model_smote.fit_sample(x,y) # 输入数据并作过抽样处理
x_smote_resampled = pd.DataFrame(x_smote_resampled, columns=['col1','col2', 'col3', 'col4', 'col5']) # 将数据转换为数据框并命名列名
y_smote_resampled = pd.DataFrame(y_smote_resampled,columns=['label']) # 将数据转换为数据框并命名列名
smote_resampled = pd.concat([x_smote_resampled, y_smote_resampled],axis=1) # 按列合并数据框
groupby_data_smote = smote_resampled.groupby('label').count() # 对label做分类汇总
print (groupby_data_smote) # 打印输出经过SMOTE处理后的数据集样本分类分布
 
# 使用RandomUnderSampler方法进行欠抽样处理
model_RandomUnderSampler = RandomUnderSampler() # 建立RandomUnderSampler模型对象
x_RandomUnderSampler_resampled, y_RandomUnderSampler_resampled =model_RandomUnderSampler.fit_sample(x,y) # 输入数据并作欠抽样处理
x_RandomUnderSampler_resampled =pd.DataFrame(x_RandomUnderSampler_resampled,columns=['col1','col2','col3','col4','col5'])
# 将数据转换为数据框并命名列名
y_RandomUnderSampler_resampled =pd.DataFrame(y_RandomUnderSampler_resampled,columns=['label']) # 将数据转换为数据框并命名列名
RandomUnderSampler_resampled =pd.concat([x_RandomUnderSampler_resampled, y_RandomUnderSampler_resampled], axis= 1) # 按列合并数据框
groupby_data_RandomUnderSampler =RandomUnderSampler_resampled.groupby('label').count() # 对label做分类汇总
print (groupby_data_RandomUnderSampler) # 打印输出经过RandomUnderSampler处理后的数据集样本分类分布
 
# 使用SVM的权重调节处理不均衡样本
model_svm = SVC(class_weight='balanced') # 创建SVC模型对象并指定类别权重
model_svm.fit(x, y) # 输入x和y并训练模型
 
# 使用集成方法EasyEnsemble处理不均衡样本
model_EasyEnsemble = EasyEnsemble() # 建立EasyEnsemble模型对象
x_EasyEnsemble_resampled, y_EasyEnsemble_resampled =
model_EasyEnsemble.fit_sample(x, y) # 输入数据并应用集成方法处理
print (x_EasyEnsemble_resampled.shape) # 打印输出集成方法处理后的x样本集概况
print (y_EasyEnsemble_resampled.shape) # 打印输出集成方法处理后的y标签集概况
 
# 抽取其中一份数据做审查
index_num = 1 # 设置抽样样本集索引
x_EasyEnsemble_resampled_t =pd.DataFrame(x_EasyEnsemble_resampled[index_num],columns=['col1','col2','col3','col4','col5'])
# 将数据转换为数据框并命名列名
y_EasyEnsemble_resampled_t =pd.DataFrame(y_EasyEnsemble_resampled[index_num],columns=['label']) # 将数据转换为数据框并命名列名
EasyEnsemble_resampled = pd.concat([x_EasyEnsemble_resampled_t,
y_EasyEnsemble_resampled_t], axis = 1) # 按列合并数据框
groupby_data_EasyEnsemble =EasyEnsemble_resampled.groupby('label').count() # 对label做分类汇总
print (groupby_data_EasyEnsemble) # 打印输出经过EasyEnsemble处理后的数据集样本分类分布

来源:CSDN,作者:Li_yi_chao
原文:https://blog.csdn.net/Li_yi_chao/article/details/87256590
版权声明:本文为博主原创文章,转载请附上博文链接!

最新文章