这是一篇机器学习的介绍,本文不会涉及公式推导,主要是一些算法思想的随笔记录。
适用人群:机器学习初学者,转AI的开发人员。
编程语言:Python
自己在项目中拿到数据,大部分情况下都是自己切分训练集、测试集,对于训练集,经常会遇到正负样本比例很不均衡的情况,即偏斜类(Skewed Class)问题,有些时候往往还很严重,比如数据量上负样本:正样本>=100,这是比较严重的偏斜类问题,下面针对这种问题,探讨一下:
解决样本分布不平衡问题
对于偏斜类问题,主要有三种方式解决:
除了上面三种常见的方式外,还可以转化问题思考角度:例如我们可以把那些小类的样本作为异常点(outliers),因此该问题便转化为异常点检测(anomaly detection)与变化趋势检测问题(change detection)。异常点检测即是对那些罕见事件进行识别。如:银行信用卡诈骗识别,几十万中样本中可能有几百个诈骗用户。这些事件相对于正常情况是很少见的。变化趋势检测类似于异常点检测,不同在于其通过检测不寻常的变化趋势来识别。如通过观察用户模式或银行交易来检测用户行为的不寻常改变。
分类中常见的类别不平衡问题解决方法
对于偏斜类问题,不再用精度accuracy作为模型好坏的衡量指标,因为数据量多的那个分类已经严重影响了整个accuracy,具体要看各个分类的召回率recall(一般我们关注正样本,即1的recall值),更推荐使用roc曲线的auc值(在sklearn中用roc_auc表示)作为衡量指标。
上层领导可能只知道精度,即准确率,即accuracy,并不知道recall、auc等,所以精度是领导关注的问题。
关于衡量指标的问题,以后会单独写一篇来介绍。
经历的两个项目,都有严重的偏斜类问题。
第一个项目是正负样本数据量都足够(总量120w左右),且正样本:负样本=96:4,由于有足够的正样本,这不是什么棘手的问题,采用欠采样的方式就可以解决,按照原数据量的分布96:4共取了25w数据作为训练集(按原始数据量的分布是为了尽量符合线上场景,这样得出的accuracy更接近实际情况,取了数据量25w是由学习曲线得出,学习曲线后续篇章会单独介绍)左右的正样本和1,并且模型会有较好的表现。
第二个项目是正样本过少,只有1000左右,而负样本有100多万,这种正样本过少,是比较棘手的问题,对于这种问题,先尽量多采集些正样本,但是注意不能用太旧的数据(由于是投资问题,涉及到产品的更替等受时间影响),采集近半年或三个月(推荐)的数据,但是即便如此,正样本依旧很少,那么上述三种方式均可采用。下面先说一下训练集正负样本划分比例带来的影响。
对于正样本过少的偏斜类问题,我们每次采取不同量的负样本与全量的正样本,带来的效果如下(采用的xgboost算法,同样,也试用了svm,但是即便在数据量很少的情况下,xgboost的得分更高,当然,不排除过拟合的情况):
如上,负样本量越少,整体精度accuracy越少,但是正样本的recall越高。实际上,从accuracy和recall的计算公式来看,accuracy由量多的决定,虽然不断降低负样本量,正样本的recall会越高,但是整体数据量越少,对于整体模型的置信度(可靠性)就越少,毕竟,人们更愿意相信大数据,模型也会从大数据学到更多信息。
所以,需要找到合数的训练量,这一点可以从经验和学习曲线得到。
针对上面提到的第二个项目,尝试着用三种方式处理,并实际测试:
分两种思路:
a.将正样本复制累加
经过验证,这种方式是有效的,通过复杂少数样本,提高了少数样本的recall,进入提高了auc
b.SMOTE算法或ADASYN(自适应综合过采样)
这里以SMOTE算法为例,SMOTE算法在sklearn中没有集成,需要单独下载lmblearn包,使用如下:
from imblearn.over_sampling import SMOTE
sm = SMOTE(random_state=42) #随机因子,每次随机生成不要和上次一样
X_res,y_res = sm.fit_sample(X_train,y_train)
如上述代码,会将正样本生成新的值,使得num(正样本):num(负样本)=1:1
这种方式会减少很多负样本的信息,为了保留这种信息,将负样本按1k或500切分10份,每份分别与全量正样本进行进行训练得到分类器,然后集成学习assemble的方式进行组合成一个分类器
在训练的时候调节权重:
a.对于xgboost,因为xgboost不属于sklearn,需调节scale_pos_weight参数值,实测结果——改善不大,需要自己不断尝试权重值;
b.针对sklearn中的分类方法,如svm,调节class_weight参数
from sklearn.svm import SVC
model_svm=SVC(class_weight='balanced') #算法权衡权重
model_svm.fit(x,y)
实测——将class_weight设置为‘balanced’,效果改善不明显
from sklearn.svm import SVC
model_svm=SVC(class_weight={0:1,1:10}) #自己设定正负样本权重
model_svm.fit(x,y)
实测——将class_weight指定权重,会比设置为‘balanced’效果改善,但具体权重的值设定为什么数值,需要测试,可以结合网格搜索来找最优权重
XGBoost、LightGBM的详细对比介绍
对于正样本量足够、负样本不足的偏斜类问题,由于有足够的正样本,采用欠采样的方式就可以解决;
对于正样本量严重不足、负样本过多的偏斜类问题,由于严重缺少正样本,可以采用上述的三种方式解决,如果采用调整权重的方式,权重的值需要不断尝试,若采用过采样方式,可以通过单纯的复制少数样本数据,也可以通过SMOTE算法生成少数样本,大家都可以尝试。