分类算法中的非均衡问题
一,引言
在前面六个分类算法中,都假设了最后所有的预测类别的分类代价是一样的。但是,在实际中却并非如此,往往不同的决策结果所带来的影响和代价是不一样的。比如,第五章的实例,预测患马疝病的马匹是否死亡的结果,显然,死亡和不死亡的代价不同,毕竟马匹也是有生命的存在,更何况还有跟人类之间的感情。所以,当算法判断出错,毕竟算法并非完美,那么所带来的代价显然更高。再比如,关于垃圾邮件过滤,我们自然是希望所有的合理邮件永远不会被扔进垃圾箱,而可以适度容忍部分垃圾邮件出现在邮箱中,显然,判断某一邮件是否为垃圾邮件的两种结果代价是不一样的。
像这样的例子非常多,但是我们想要表达的意思就是,在大多数情况下,不用类别的分类代价并不相等,这就是我们要说的是非均衡问题。所以,如果一种度量分类器性能的方法中能将不同决策的代价考虑在内,显然是十分有必要的。
二,非均衡问题的相关分析
1 分类器性能度量指标:正确率‚召回率,ROC曲线
前面几章的内容都是基于错误率来衡量分类器任务的成功程度的。错误率是指在所有测试样例中错分样例所占的比例。而事实上,这样的度量方式却掩盖了样例如何被分错的事实。
1.1 正确率,召回率
混淆矩阵是一个被普遍使用的工具,它可以帮助人们更好的理解分类中的错误,比如下面一个三类问题的混淆矩阵,是一个对于在房子周围可能发现的动物类型的预测:
预测结果 | ||||
狗 | 猫 | 鼠 | ||
真实结果 | 狗 | 24 | 2 | 5 |
猫 | 2 | 27 | 0 | |
鼠 | 4 | 2 | 30 |
显然,利用上面的混淆矩阵之后,我们就能够更好地理解分类中的错误了。如果矩阵中非非对角元素都为0,那么显然这就是一个非常好的分类器了。
再来看一个混淆矩阵,该矩阵是针对一个二类分类问题的。需要说明的是,在二类分类问题中,如果将一个正例判为正例,那么就认为产生了一个真正例(True Positive);如果对一个反例正确判为反例,则产生了一个真反例(True Negative)。相应的,另外两种情况则分别称为伪反例(False Positive)和伪正例(False Negative)。具体如下表所示:
预测结果 | |||
+1 | -1 | ||
真实结果 | +1 | 真正例(TP) | 伪反例(FN) |
-1 | 伪正例(FP) | 真反例(TN) |
在分类中,当某个类别的重要性高于其他类别时,我们自然而然就可以利用上述定义来定义出多个比错误率指标更好的新指标。
正确率:precision=TP/(TP+FP),即预测为正例的样本中真正正例的比例;
召回率:recall=TP/(TP+FN),即预测为正例的真实正例占所有真正正例中的比例
显然,当召回率很大时,被判错的真正正例会很少。然而,构造出一个高正确率或者高召回率的分类器很容易实现,但是二者却很难同时成立。如果将任何样本都判为正例,显然召回率会非常高,而正确率却可能非常低。所以,如何构建出一个正确率和召回率都最大的分类器是一个不小的挑战。
1.2 ROC曲线
ROC曲线是另外一个度量分类中非均衡问题的工具。下图是AdaBoost马疝病检测系统的ROC曲线
图中,有两条线,一条实线和一条虚线。图中的横轴表示的是伪正例的比例(假阳率)=FP/(FP+TN),而纵轴是真正例的比例(真阳率=TP/(TP+FN))。图中左上角的点所对应的是将所有样例判为反例的情况,而右下角的点对应的则是将所有样例判为正例的情况。虚线代表随机预测的结果。
理想状态下,最佳的分类器应该尽可能位于左上角,这就意味着分类器在假阳率很低的同时获得了很高的真阳率。应用在垃圾邮件过滤的环境中,就相当于过滤掉了所有的垃圾邮件,但是没有将任何合法邮件误识别为垃圾邮件而放入垃圾桶中。
对于不同的ROC曲线进行比较的一个指标是曲线下的面积,简称AUC。AUC能够给出分类器的平均性能,一个完美分类器的AUC为1,而随机预测的AUC为0.5
ROC曲线的创建需要分类器提供每个阳例或者阴例的可信程度值。朴素贝叶斯分类器能够提供一个可能性值,logistic回归分类器会将计算的一个数值输入到sigmoid函数中,在SVM和AdaBoost中也都会计算出这样一个数值。而有了这样的数值,我们就可以利用这些值衡量给定分类器的预测强度。具体创建ROC的过程为:首先将分类样例按照预测强度进行排序。先从排名最低的样本开始,所有排名更低的样本被判为反例,而所有排名更高的样例都被判为正例。起始点从(1.0,1.0)开始,然后将其移到排名次低的样例中,如果该样例属于正例,那么对正阳例进行修改,如果该样例属于反例,那么就修改假阴率。
具体实现代码如下:
def plotROC(predStrengths, classLabels): import matplotlib.pyplot as plt cur = (1.0,1.0) #cursor ySum = 0.0 #variable to calculate AUC numPosClas = sum(array(classLabels)==1.0) yStep = 1/float(numPosClas); xStep = 1/float(len(classLabels)-numPosClas) sortedIndicies = predStrengths.argsort()#get sorted index, it's reverse fig = plt.figure() #这三行代码用于构建画笔 fig.clf() ax = plt.subplot(111) #loop through all the values, drawing a line segment at each point for index in sortedIndicies.tolist()[0]: if classLabels[index] == 1.0: delX = 0; delY = yStep; else: delX = xStep; delY = 0; ySum += cur[1] #draw line from cur to (cur[0]-delX,cur[1]-delY) ax.plot([cur[0],cur[0]-delX],[cur[1],cur[1]-delY], c='b') cur = (cur[0]-delX,cur[1]-delY) ax.plot([0,1],[0,1],'b--') plt.xlabel('False positive rate'); plt.ylabel('True positive rate') plt.title('ROC curve for AdaBoost horse colic detection system') ax.axis([0,1,0,1]) plt.show() print "the Area Under the Curve is: ",ySum*xStep
在计算AUC的过程中,需要对多个小矩形的面积进行累加,小矩形的宽度是xStep,所以可以先对所有矩阵的高度进行累加,最后再乘以xStep就得到了总面积。所有的高度的和(yStep)随着x轴的每次移动而逐渐增加。一旦决定了在x轴或者y轴上进行移动,我们就在当前点和新点之间画出一条线段出来。接着,更新当前点cur,逐渐累加出AUC的值。
2,基于代价函数的分类器决策控制
处理非均衡分类大代价的方法除了调节分类器的阈值之外,还有其他的一些方法,比如代价敏感学习。比如下面两个表
预测结果 | |||
+1 | -1 | ||
真实结果 | +1 | 0 | 1 |
-1 | 1 | 0 |
我们可以基于上面的代价矩阵,计算分类决策结果的总代价为:TP*0+FN+1+FP*1+TN*0
预测结果 | |||
+1 | -1 | ||
真实结果 | +1 | -5 | 1 |
-1 | 50 | 0 |
那么此时,总代价为:TP*(-5)+FN*1+FP*50+TN*0
这表明两种分类错误的代价结果是不一样的。相应地,分类正确的收益显然也会不一样。如果在构建分类器时,知道了这些分类代价,那么我们就可以选择付出代价最小的分类器了。
在分类算法中,我们可以采用如下方式引入代价信息,比如:
AdaBoost:基于代价函数调整权重向量D
朴素贝叶斯:选择具有最小期望(取代最大释然概率)的类别作为最后预测结果
SVM:对于不同的类别选择不同的参数C
这样,较小的类会获得更多的权重,那么出现的错误更少
3 处理非均衡问题的数据采用方法
也可以对分类器的训练数据进行改造,从而达到调节分类器不均衡问题的效果。这可以通过"过采样"和"欠采样"来得以实现。过采样就是复制部分样例,欠采样即删除部分样例。
有时候我们可能需要用到过采样和欠采样相结合的方法来调整数据的非均衡问题。比如在信用卡欺诈当中,信用卡欺诈交易定义为正类别,信用卡合法交易则为反例。那么此时,假设有50例信用卡欺诈交易和5000例合法交易(显然,信用卡欺诈交易属于罕见类别,相对于合法交易明显较少)。显然,正反样例不均衡,而我们的正样例本身就较少,所以需要尽可能的保留正样例的全部信息,于是,我们会选择保留正样例的所有样例,而对反例类别进行欠采样或样例删除处理。
此外,在进行反例样例删除操作时,选择剔除的样例中可能会携带了剩余样例中不包含的价值信息,这就会给分类结果带来影响。于是,我们可以从以下两个方面进行处理:一方面,我们可以选择那么离决策边界较远的样例进行删除,这样要删除的样例所包含的价值信息相对较少。再者,我们可以采用过采样和欠采样相结合的方式,即对正样例进行过采样,复制部分正例的同时删除部分反例,从而达到缓解删除样例中有用信息的损失问题。