[ML] 解决样本类别分布不均衡的问题

 

转自:3.4 解决样本类别分布不均衡的问题 | 数据常青藤 (组织排版上稍有修改)html

3.4 解决样本类别分布不均衡的问题

说明:本文是《Python数据分析与数据化运营》中的“3.4 解决样本类别分布不均衡的问题”。算法

 

-----------------------------下面是正文内容--------------------------网络

 

所谓的不平衡指的是不一样类别的样本量异很是大。样本类别分布不平衡主要出如今分类相关的建模问题上。样本类别分布不均衡从数据规模上能够分为大数据分布不均衡和小数据分布不均衡两种。dom

  • 大数据分布不均衡。这种状况下总体数据规模大,只是其中的少样本类的占比较少。可是从每一个特征的分布来看,小样本也覆盖了大部分或所有的特征。例如拥有1000万条记录的数据集中,其中占比50万条的少数分类样本便于属于这种状况。
  • 小数据分布不均衡。这种状况下总体数据规模小,而且占据少许样本比例的分类数量也少,这会致使特征分布的严重不平衡。例如拥有1000条数据样本的数据集中,其中占有10条样本的分类,其特征不管如何拟合也没法实现完整特征值的覆盖,此时属于严重的数据样本分布不均衡。

样本分布不均衡将致使样本量少的分类所包含的特征过少,并很难从中提取规律;即便获得分类模型,也容易产生过分依赖于有限的数据样本而致使过拟合的问题,当模型应用到新的数据上时,模型的准确性和鲁棒性将不好。ide

样本分布不平衡主要在于不一样类别间的样本比例差别,以笔者的工做经验看,若是不一样分类间的样本量差别达到超过10倍就须要引发警觉并考虑处理该问题,超过20倍就要必定要解决该问题。函数

3.4.1 哪些运营场景中容易出现样本不均衡

在数据化运营过程当中,如下场景会常常产生样本分布不均衡的问题:学习

  • 异常检测场景。大多数企业中的异常个案都是少许的,好比恶意刷单、黄牛订单、信用卡欺诈、电力窃电、设备故障等,这些数据样本所占的比例一般是总体样本中不多的一部分,以信用卡欺诈为例,刷实体信用卡的欺诈比例通常都在0.1%之内。
  • 客户流失场景。大型企业的流失客户相对于总体客户一般是少许的,尤为对于具备垄断地位的行业巨擘,例如电信、石油、网络运营商等更是如此。
  • 罕见事件的分析。罕见事件与异常检测相似,都属于发生个案较少;但不一样点在于异常检测一般都有是预先定义好的规则和逻辑,而且大多数异常事件都对会企业运营形成负面影响,所以针对异常事件的检测和预防很是重要;但罕见事件则没法预判,而且也没有明显的积极和消极影响倾向。例如因为某网络大V无心中转发了企业的一条趣味广告致使用户流量明显提高便属于此类。
  • 发生频率低的事件。这种事件是预期或计划性事件,可是发生频率很是低。例如每一年1次的双11盛会通常都会产生较高的销售额,但放到整年来看这一天的销售额占比极可能只有1%不到,尤为对于不多参与活动的公司而言,这种状况更加明显。这种属于典型的低频事件。

3.4.2 解决样本不均衡的方法

3.4.2.1 经过过抽样和欠抽样

抽样是解决样本分布不均衡相对简单且经常使用的方法,包括过抽样和欠抽样两种。大数据

  • 过抽样(也叫上采样、over-sampling)方法经过增长分类中少数类样本的数量来实现样本均衡,最直接的方法是简单复制少数类样本造成多条记录,这种方法的缺点是若是样本特征少而可能致使过拟合的问题;通过改进的过抽样方法经过在少数类中加入随机噪声、干扰数据或经过必定规则产生新的合成样本,例如SMOTE算法。
  • 欠抽样(也叫下采样、under-sampling)方法经过减小分类中多数类样本的样本数量来实现样本均衡,最直接的方法是随机地去掉一些多数类样原本减少多数类的规模,缺点是会丢失多数类样本中的一些重要信息。

整体上,过抽样和欠抽样更适合大数据分布不均衡的状况,尤为是第一种(过抽样)方法应用更加普遍。spa

3.4.2.2 经过正负样本的惩罚权重

经过正负样本的惩罚权重解决样本不均衡的问题的思想是在算法实现过程当中,对于分类中不一样样本数量的类别分别赋予不一样的权重(通常思路分类中的小样本量类别权重高,大样本量类别权重低),而后进行计算和建模。.net

使用这种方法时须要对样本自己作额外处理,只需在算法模型的参数中进行相应设置便可。不少模型和算法中都有基于类别参数的调整设置,以scikit-learn中的SVM为例,经过在class_weight: {dict, 'balanced'}中针对不一样类别针对不一样的权重,来手动指定不一样类别的权重。若是使用其默认的方法balanced,那么SVM会将权重设置为与不一样类别样本数量呈反比的权重来作自动均衡处理,计算公式为:n_samples / (n_classes * np.bincount(y))。

若是算法自己支持,这种思路是更加简单且高效的方法。

3.4.2.3 经过组合/集成方法

组合/集成方法指的是在每次生成训练集时使用全部分类中的小样本量,同时从分类中的大样本量中随机抽取数据来与小样本量合并构成训练集,这样反复屡次会获得不少训练集和训练模型。最后在应用时,使用组合方法(例如投票、加权投票等)产生分类预测结果。

例如,在数据集中的正、负例的样本分别为100和10000条,比例为1:100。此时能够将负例样本(类别中的大量样本集)随机分为100份(固然也能够分更多),每份100条数据;而后每次造成训练集时使用全部的正样本(100条)和随机抽取的负样本(100条)造成新的数据集。如此反复能够获得100个训练集和对应的训练模型。

这种解决问题的思路相似于随机森林。在随机森林中,虽然每一个小决策树的分类能力很弱,可是经过大量的“小树”组合造成的“森林”具备良好的模型预测能力。

若是计算资源充足,而且对于模型的时效性要求不高的话,这种方法比较合适。

3.4.2.4 经过特征选择

上述几种方法都是基于数据行的操做,经过多种途径来使得不一样类别的样本数据行记录均衡。除此之外,还能够考虑使用或辅助于基于列的特征选择方法。

通常状况下,样本不均衡也会致使特征分布不均衡,但若是小类别样本量具备必定的规模,那么意味着其特征值的分布较为均匀,可经过选择具备显著型的特征配合参与解决样本不均衡问题,也能在必定程度上提升模型效果。

提示 上述几种方法的思路都是基于分类问题解决的。实际上,这种从大规模数据中寻找罕见数据的状况,也可使用非监督式的学习方法,例如使用One-class SVM进行异常检测。分类是监督式方法,前期是基于带有标签(Label)的数据进行分类预测;而采用非监督式方法,则是使用除了标签之外的其余特征进行模型拟合,这样也能获得异常数据记录。因此,要解决异常检测类的问题,先是考虑总体思路,而后再考虑方法模型。

3.4.3 代码实操:Python处理样本不均衡

本示例中,咱们主要使用一个新的专门用于不平衡数据处理的Python包imbalanced-learn,读者须要先在系统终端的命令行使用pip install imbalanced-learn进行安装;安装成功后,在Python或IPython命令行窗口经过使用import imblearn(注意导入的库名)检查安装是否正确,示例代码包版本为0.2.1。除此之外,咱们还会使用sklearn的SVM在算法中经过调整类别权重来处理样本不均衡问题。本示例使用的数据源文件data2.txt位于“附件-chapter3”中,默认工做目录为“附件-chapter3”(若是不是,请cd切换到该目录下,不然会报“IOError: File data2.txt does not exist”)。完整代码以下:

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处理后的数据集样本分类分布
View Code

 

示例代码以空行分为6部分。

 

第一部分导入库。本示例中用到了第三方库imbalanced-learn实现主要的样本不均衡处理,而pandas的引入主要用于解释和说明不一样处理方法获得的结果集样本的分布状况,sklearn.svm中的SVC主要用于说明SVM如何在算法中自动调整分类权重。

 

第二部分导入数据文件。该过程当中使用pandas的read_table读取本地文件,为了更好的区别不一样的列,经过names指定列名;对数据框作切片分割获得输入的x和目标变量y;经过pandas的groupby()方法按照label类作分类汇总,汇总方式是使用count()函数计数。输入原始数据集样本分类分布以下:

col1 col2 col3 col4 col5 label 
0.0 942 942 942 942 942
1.0 58 58 58 58 58

 输出结果显示了原始数据集中,正样本(label为1)的数量仅有58个,占总样本量的5.8%,属于严重不均衡分布。

 

第三部分使用SMOTE方法进行过抽样处理。该过程当中首先创建SMOTE模型对象,并直接应用fit_sample对数据进行过抽样处理,若是要得到有关smote的具体参数信息,可先使用fit(x,y)方法得到模型信息,并获得模型不一样参数和属性;从fit_sample方法分别获得对x和y过抽样处理后的数据集,将两份数据集转换为数据框而后合并为一个总体数据框;最后经过pandas提供的groupby()方法按照label类作分类汇总,汇总方式是使用count()函数计数。通过SMOTE处理后的数据集样本分类分布以下:

col1 col2 col3 col4 col5 label 
0.0 942 942 942 942 942
1.0 942 942 942 942 942

 经过对比第二部分代码段的原始数据集返回结果发现,该结果中的正样本(label为1)的数量增长,并与负样本数量相同,均为942条,数据分类样本获得平衡。

 

第四部分使用RandomUnderSampler方法进行欠抽样处理。该过程与第三部分步骤彻底相同,在此略过各模块介绍,用途都已在代码备注中注明。通过RandomUnderSampler处理后的数据集样本分类分布以下:

col1 col2 col3 col4 col5 label 
0.0 58 58 58 58 58
1.0 58 58 58 58 58

 经过对比第二部分代码段的原始数据集返回的结果,该结果中的负样本(label为0)的数量减小,并跟正样本相同,均为58条,样本获得平衡。

 

第五部分使用SVM的权重调节处理不均衡样本。该过程主要经过配置SVC中的class_weight参数和值的设置来处理样本权重,该参数可设置为字典、None或字符串balanced三种模式:

  • 字典:经过手动指定的不一样类别的权重,例如{1:10,0:1}
  • None:表明类别的权重相同
  • balanced:表明算法将自动调整与输入数据中的类频率成反比的权重,具体公式为n_samples /(n_classes * np.bincount(y)),程序示例中使用了该方法

通过设置后,算法自动处理样本分类权重,无需用户作其余处理。要对新的数据集作预测,只须要调用model_svm模型对象的predict方法便可。

 

第六部分使用集成方法EasyEnsemble处理不均衡样本。该方法的主要过程与其余imblearn方法过程相似,不一样点在于集成方法返回的数据为三维数据,即将数据在原来的基础上新增了一个维度——“份数”,集成方法返回的数据x和y的形状为(10, 116, 5)和(10, 116)。为了更详细的查看其中每一份数据,抽取其中一份数据作审查,获得的每份数据返回结果以下:

col1 col2 col3 col4 col5 label 
0.0 58 58 58 58 58
1.0 58 58 58 58 58

经过对比第二部分代码段的原始数据集返回的结果,该结果中的负样本(label为0)的数量减小,并跟正样本相同,均为58条,样本集获得平衡。随后的应用中,能够经过循环读取每一份数据训练模型并获得结果,而后将10(x处理后返回的结果,经过形状名年龄返回的元组中的第一个数值,x_EasyEnsemble_resampled.shape[0])份数据的结果经过必定方法作汇总。

 

上述过程当中,主要须要考虑的关键点是:

  • 如何针对不一样的具体场景选择最合适的样本均衡解决方案,选择过程当中既要考虑到每一个类别样本的分布状况以及总样本状况,又要考虑后续数据建模算法的适应性,以及整个数据模型计算的数据时效性。

代码实操小结:本小节示例中,主要用了几个知识点:

  • 经过pandas的read_table方法读取文本数据文件,并指定列名
  • 对数据框作切片处理
  • 经过pandas提供的groupby()方法配合count()作分类汇总
  • 使用imblearn.over_sampling中的SMOTE作过抽样处理
  • 使用imblearn.under_sampling中的RandomUnderSampler作欠抽样处理
  • 使用imblearn.ensemble中的EasyEnsemble作集成处理
  • 使用sklearn.svm 中的SVC自动调整算法对不一样类别的权重设置

提示 第三方库imblearn提供了很是多的样本不均衡处理方法,限于篇幅没法作一一介绍,建议读者自行安装并学习和了解不一样的用法。

 

其它参考:

How to Handle Imbalanced Classes in Machine Learning  (译文https://yq.aliyun.com/articles/226016

http://www.javashuo.com/article/p-fpwqhxde-p.html

https://blog.csdn.net/login_sonata/article/details/54290402

http://www.cnblogs.com/lyr2015/p/8711120.html

https://blog.csdn.net/weixin_42243942/article/details/80480313

相关文章
相关标签/搜索