什么是不平衡问题
不平衡数据一直是业务场景比较常见的问题之一,癌症数据、欺诈数据、不合格产品数据等都是不平衡数据问题的典型应用。对于一个分类不平衡问题属于有监督机器学习问题,主要指因变量具有不平衡的构成比例问题,或者说在不同分类上,数据具有不相等的数据分布。
机器学习算法需要处理不平衡数据的原因
由于因变量非同分布,ML需要调整准确性
由于多数类的存在,导致现存的分类偏向多数类;
ML算法以准确性为驱动(如最小化总误差),这将导致少数类对误差的贡献率小;
ML算法假设不同分类数据的分类错误的代价相同。
处理不平衡数据的方法
下采样;即减少多数类观测值使数据达到平衡。适用于数据集巨大,减少训练样本可提高运算时间和空间问题。下采样方法具体又可分为随机下采样和基于先验信息的下采样(EasyEnsemble & BalanceCascade)。下采样主要缺点是会使训练样本损失多数类的重要信息。
过采样;即重复少数观测值使数据达到平衡。过采样具体方法同下采样。该方法优点是没有信息损失,缺点是易导致过拟合,且一致性(外推性)不足,受异常值影响大。
人工数据合成;属于过采样的一种,通过生成手动数据使少数类达到平衡。使用最广泛方法是synthetic minority oversampling technique(SMOTE),人工数据生成基于少数类样本特征空间(而非数据空间)的相似性,运用booststrapping和k-nearest,在一些位置相近的少数类样本中插入新样本达到平衡样本目的。新的少数样本Pj=x(原始少数样本)+rand(0,1) *(yj-x),yj为第j个x的最近邻样本。可以用DMwR包或ROSE包实现。
代价敏感学习(Cost Sensitive Learning(CSL))一般的学习算法通过最小化分类损失使分类错误率最小化,而代价敏感学习则以最小化分类代价为目标,需构造代价敏感损失。
衡量模型准确性指标
Accuracy: (TP + TN)/(TP+TN+FP+FN)
Error Rate = 1 - Accuracy = (FP+FN)/(TP+TN+FP+FN)
Precision = TP / (TP + FP)
Recall = TP / (TP + FN)
F measure = ((1 + β)² × Recall × Precision) / ( β² × Recall + Precision ),β 为衡量recall和precision重要性参数,一般为1.
ROC曲线,曲线下面积越大,准确度越高。
不平衡数据ROSE包实现
library(ROSE)
data(hacide)
table(hacide.train$cls)
## 0 1
## 980 20
prop.table(table(hacide.train$cls))
## 0 1
## 0.98 0.02
数据为不平衡数据集,仅仅有2%的因变量cls为阳性,98%为阴性。对于这种严重不平衡数据,我们先用决策树看看这种不平衡对模型准确性的影响。
library(rpart)
tree <- rpart(cls ~ .,data = hacide.train)
pred.tree <- predict(tree,newdata = hacide.test)
ROSE包中accurary.meas()函数可以计算precision、recall、F值等模型准确性指标。
accuracy.meas(hacide.test$cls,pred.tree[,2])
## Call:
## accuracy.meas(response = hacide.test$cls, predicted = pred.tree[,2])
## Examples are labelled as positive when predicted is greater than 0.5
## precision: 1.000
## recall: 0.200
## F: 0.167
结果可以看出以0.5为截断点,模型精确度为100%,即没有假阳性;非常低的recall=0.2表明模型具有非常高的假阴性值;F=0.167也说明模型预测准确性很低。
roc.curve(hacide.test$cls,pred.tree[,2],plotit = TRUE)
## Area under the curve (AUC): 0.600
最终ROC曲线下面积AUC=0.6也说明模型在截断点为0.5的条件下具有较差的得分。
让我们运用采样技术对不平衡数据进行处理,以提高模型准确性。
不平衡数据处理方法
data_balanced_over <- ovun.sample(cls ~ ., data = hacide.train,method = "over",N = 1960)$data
table(data_balanced_over$cls)
## 0 1
## 980 980
运行“过采样”技术,通过重抽样增加较少分组(阳性组)的数量,使数据达到平衡。同样的代码,可以实现“下采样”和同时过采样和下采样。运用ROSE()函数实现SMOTE方法。
data_balanced_under <- ovun.sample(cls ~ .,data = hacide.train,method = "under",N = 40,seed = 1)$data
table(data_balanced_under$cls)
## 0 1
## 20 20
data_balanced_both <- ovun.sample(cls ~ ., data = hacide.train,method = "both", p = 0.5,N = 1000,seed = 1)$data
table(data_balanced_both$cls)
## 0 1
## 520 480
data.rose <- ROSE(cls ~.,data = hacide.train,seed = 1)$data
table(data.rose$cls)
## 0 1
## 520 480
对不同抽样技术进行比较
分别对4种不同抽样数据集拟合决策树函数,通过绘制ROC曲线比较抽样技术处理不平衡数据方法的好坏。
#build decision tree models
tree.rose <- rpart(cls ~ ., data = data.rose)
tree.over <- rpart(cls ~ ., data = data_balanced_over)
tree.under <- rpart(cls ~ ., data = data_balanced_under)
tree.both <- rpart(cls ~ ., data = data_balanced_both)
#make predictions on unseen data
pred.tree.rose <- predict(tree.rose, newdata = hacide.test)
pred.tree.over <- predict(tree.over, newdata = hacide.test)
pred.tree.under <- predict(tree.under, newdata = hacide.test)
pred.tree.both <- predict(tree.both, newdata = hacide.test)
#AUC ROSE
roc.curve(hacide.test$cls, pred.tree.rose[,2])
## Area under the curve (AUC): 0.989
#AUC Oversampling
roc.curve(hacide.test$cls, pred.tree.over[,2],add.roc = TRUE,col = "red")
## Area under the curve (AUC): 0.798
#AUC Undersampling
roc.curve(hacide.test$cls, pred.tree.under[,2],add.roc = TRUE,col = "blue")
## Area under the curve (AUC): 0.867
#AUC Both
roc.curve(hacide.test$cls, pred.tree.both[,2],add.roc = TRUE,type = "o")
## Area under the curve (AUC): 0.798
由模型比较可知,ROSE()函数运用SMOTE方法(基于随机森林和boosting)得到的“平衡数据”,模型准确性最高(AUC= 0.989)。ROSE()函数也可以指定检验模型准确性的方法,如holdout和bagging。extr.pred参数用于提取属于阳性类的概率。
ROSE.holdout <- ROSE.eval(cls ~.,data = hacide.train,learner = rpart,method.assess = "holdout",extr.pred = function(obj) obj[,2],seed = 1)
ROSE.holdout
## Call:
## ROSE.eval(formula = cls ~ ., data = hacide.train, learner = rpart,
## extr.pred = function(obj) obj[, 2], method.assess = "holdout",
## seed = 1)
## Holdout estimate of auc: 0.985
但是在截断点为0.5条件下,模型F值仍然较低。我们尝试调整不同截断点,使模型准确性最好。由结果可以看出,截断点设置在0.868时,模型准确率最高(precision: 1.000,recall: 0.600,F: 0.375)。
c <- roc.curve(hacide.test$cls, pred.tree.rose[,2])
accuracy <- function(x){
accuracy.meas(hacide.test$cls, pred.tree.rose[,2],threshold = x)}a <- list()for(i in c$thresholds[2:5]) {
a=accuracy(i)
print(a)}
## Call:
## accuracy.meas(response = hacide.test$cls, predicted = pred.tree.rose[,
## 2], threshold = x)
## Examples are labelled as positive when predicted is greater than 0.8687
## precision: 1.000
## recall: 0.600
## F: 0.375
参考资料
MANISH SARASWAT,Analytics Vidhya,Practical Guide to deal with Imbalanced Classification Problems in R
SMOT算法在不平衡数据中的应用,孙涛,首都医科大学学术论文征文集
代价敏感性学习方法研究,刘胥影,南京大学博士学位论文 -砍柴问樵夫,数据快速处理—data.table包简单介绍 -SCAN:mlr: Machine Learning in R -Bernd Bischl,et al.mlr - Machine Learning in R,JMLR,17(170):1−5, 2016.