分類之性能評估

轉自:http://www.csuldw.com/2016/03/12/2016-03-12-performance-evaluation/

本文主要介紹幾種常用的用於分類的性能評估指標,同時介紹如何繪製ROC曲線以及計算AUC值的便捷方法。最後再附上一個繪製ROC曲線和計算AUC的Python源碼實現。

Precision和Recall

首先我們來看看下面這個混淆矩陣:

pred_label/true_label Positive Negative
Positive TP FP
Negtive FN TN

如上表所示,行表示預測的label值,列表示真實label值。TP,FP,FN,TN分別表示如下意思:

  • TP(true positive):表示樣本的真實類別爲正,最後預測得到的結果也爲正;
  • FP(false positive):表示樣本的真實類別爲負,最後預測得到的結果卻爲正;
  • FN(false negative):表示樣本的真實類別爲正,最後預測得到的結果卻爲負;
  • TN(true negative):表示樣本的真實類別爲負,最後預測得到的結果也爲負.

根據以上幾個指標,可以分別計算出Accuracy、Precision、Recall(Sensitivity,SN),Specificity(SP)。

Accuracy=TP+TNTP+FP+TN+FN
Precision=TPTP+FP
Recall=TPTP+FN
SP=TNTN+FP
  • Accuracy:表示預測結果的精確度,預測正確的樣本數除以總樣本數。
  • precision,準確率,表示預測結果中,預測爲正樣本的樣本中,正確預測爲正樣本的概率;
  • recall,召回率,表示在原始樣本的正樣本中,最後被正確預測爲正樣本的概率;
  • specificity,常常稱作特異性,它研究的樣本集是原始樣本中的負樣本,表示的是在這些負樣本中最後被正確預測爲負樣本的概率。

在實際當中,我們往往希望得到的precision和recall都比較高,比如當FN和FP等於0的時候,他們的值都等於1。但是,它們往往在某種情況下是互斥的。例如,有50個正樣本,50個負樣本,結果全部預測爲正樣本,那麼TP=50,FP=50,TN=0,FN=0,按照上面的公式計算,可以得到正樣本的recall卻爲1,precision卻爲0.5.所以需要一種折衷的方式,因此就有了F1-score。

F1score=2×recall×precisionrecall+precision

F1-score表示的是precision和recall的調和平均評估指標。

另外還有一個指標,即MCC,該指標對於不均衡數據集的評估非常有效,公式如下:

$$MCC = \frac{TP \times TN - FP \times FN}{ \sqrt {(TP + FP)(TP + FN)( TN + FP)(TN+FN)}}$$

ROC曲線

ROC(receiver operating characteristic),平面的橫座標是false positive rate(FPR)假陽率,縱座標是true positive rate(TPR)真陽率。ROC計算過程如下:

  • 首先每個樣本都需要有一個label值,並且還需要一個預測的score值(取值0到1);
  • 然後按這個score對樣本由大到小進行排序,假設這些數據位於表格中的一列,從上到下依次降序;
  • 現在從上到下按照樣本點的取值進行劃分,位於分界點上面的我們把它歸爲預測爲正樣本,位於分界點下面的歸爲負樣本;
  • 分別計算出此時的TPR(Recall)=TP/P和FPR(1-SP)=FP/N,然後在圖中繪製(FPR, TPR)點。

從上往下逐個樣本計算,最後會得到一條光滑的曲線 。

然而,千言萬語都不如下面這幅圖懂得快:

『roc曲線繪製動畫—圖片來自參考文獻5.』

AUC計算

AUC(area under the curve)就是ROC曲線下方的面積,取值在0.5到1之間,因爲隨機猜測得到額AUC就是0.5。面積如下圖所示,陰影部分即爲AUC面積:

『AUC面積圖解—圖片來自參考文獻5.』

AUC的幾種解釋(來自【Interpreting the AUROC】):

  • The expectation that a uniformly drawn random positive is ranked before a uniformly drawn random negative.
  • The expected proportion of positives ranked before a uniformly drawn random negative.
  • The expected true positive rate if the ranking is split just before a uniformly drawn random negative.
  • The expected proportion of negatives ranked after a uniformly drawn random positive.
  • The expected false positive rate if the ranking is split just after a uniformly drawn random positive.

下面來介紹下它的計算方法,AUC的計算主要有以下三種。

第一種:積分思維。這也是在早期機器學習文獻中常用的AUC計算方法。從積分的思想中演化而來的。假如我們的測試樣本有限,那麼我們得到的AUC曲線必然是呈現階梯形狀。因此,計算的AUC也就是這些階梯下面的面積之和(有沒有想起以前學高數時的積分面積哈)。我們可以這樣來計算,首先把score值進行排序,假設score越大,此樣本屬於正類的概率就越大。然後一邊掃描一邊計算就可以得到我們想要的AUC。但是,這樣做會有個缺點,當多個測試樣本的score值相等時,我們調整一下閾值,得到的不是往上或者往右的延展,而是斜着向上形成一個梯形。此時,就需要計算這個梯形的面積,這樣是比較麻煩。 簡單的用代碼描述下

1
2
3
4
5
6
7
8
9
10
auc = 0.0
height = 0.0

for each training example x_i, y_i:
  if y_i = 1.0:
    height = height + tpr
  else 
    auc +=  height * fpr

return auc

第二種:Mann–Whitney U test(MWW)。關於AUC還有一個很有趣的性質,它和Wilcoxon-Mann-Witney Test類似(可以去google搜一下),而Wilcoxon-Mann-Witney Test就是測試任意給一個正類樣本和一個負類樣本,正類樣本的score有多大的概率大於負類樣本的score。有了這個定義,就可以得到了另外一中計算AUC的方法:計算出這個概率值。我們知道,在有限樣本中我們常用的得到概率的辦法就是通過頻率來估計之。這種估計隨着樣本規模的擴大而逐漸逼近真實值。樣本數越多,計算的AUC越準確類似,也和計算積分的時候,小區間劃分的越細,計算的越準確是同樣的道理。具體來說就是: 統計一下所有的 M×N(M爲正類樣本的數目,N爲負類樣本的數目)個正負樣本對中,有多少個組中的正樣本的score大於負樣本的score。當二元組中正負樣本的 score相等的時候,按照0.5計算。然後除以MN。實現這個方法的複雜度爲O(n^2 )。n爲樣本數(即n=M+N),公式表示如下:

$$**AUC = \frac{\sum_i^n ( \ pos\_score  > neg\_score \ )}{M * N}**$$

第三種:該方法和上述第二種方法原理一樣,但複雜度降低了。首先對score從大到小排序,然後令最大score對應的sample的rank值爲n,第二大score對應sample的rank值爲n-1,以此類推從n到1。然後把所有的正類樣本的rank相加,再減去正類樣本的score爲最小的那M個值的情況。得到的結果就是有多少對正類樣本的score值大於負類樣本的score值,最後再除以M×N即可。值得注意的是,當存在score相等的時候,對於score相等的樣本,需要賦予相同的rank值(無論這個相等的score是出現在同類樣本還是不同類的樣本之間,都需要這樣處理)。具體操作就是再把所有這些score相等的樣本 的rank取平均。然後再使用上述公式。此公式描述如下:

$$AUC = \frac{\sum_{ins_i \epsilon pos}rank_{ins_i} - \frac{M * (M+1)}{2}}{M * N}$$

這三種方法,第一種比較好理解,後面兩種確實不太好理解,先記下,慢慢理解。

源碼

最後,附上ROC曲線繪製代碼。下面使用的思想類似積分,但是求得是AUC的近似值,忽略了梯形部分,Code如下:

依賴庫:

  • numpy
  • matplotlib
# -*- coding: utf-8 -*-
"""
Created on Sat Mar 12 17:43:48 2016

@author: liudiwei
"""
import numpy as np
import matplotlib.pyplot as plt

def plotROC(predScore, labels):
    point = (1.0, 1.0) #由於下面排序的索引是從小到大,所以這裏從(1,1)開始繪製
    ySum = 0.0 
    numPos = np.sum(np.array(labels)==1.0)
    numNeg = len(labels)-numPos
    yStep = 1/np.float(numPos)
    xStep = 1/np.float(numNeg)
    sortedIndex = predScore.argsort() #對predScore進行排序,的到排序索引值
    fig = plt.figure()
    fig.clf()
    ax = plt.subplot(111)
    for index in sortedIndex.tolist()[0]:
        if labels[index] == 1.0: #如果正樣本各入加1,則x不走動,y往下走動一步
            delX = 0
            delY = yStep;
        else:                   #否則,x往左走動一步,y不走動
            delX = xStep
            delY = 0
            ySum += point[1]     #統計y走動的所有步數的和
        ax.plot([point[0], point[0] - delX], [point[1], point[1] - delY],c='b')
        point = (point[0] - delX, point[1] - delY)
    ax.plot([0,1],[0,1],'b--')
    plt.xlabel('False positive rate'); plt.ylabel('True positive rate')
    plt.title('ROC Curve')
    ax.axis([0, 1, 0, 1])
    plt.show() 
    #最後,所有將所有矩形的高度進行累加,最後乘以xStep得到的總面積,即爲AUC值
    print "the Area Under the Curve is: ", ySum * xStep

對於ROC曲線繪製中的參數,輸入的第二個參數是類別標籤(如,+1,-1形成的文件,每行表示一個樣本的真實類別);第一個參數則是由模型訓練出來的預測強度,如Adaboost對樣本i預測的結果爲0.67,對i+1個樣本預測的結果是0.3,等等,每行一個,格式和classLabels一樣。最後繪製ROC曲線的同時,也在輸出ROC曲線下方的AUC面積。

參考文獻

[1] https://en.wikipedia.org/wiki/Receiver_operating_characteristic
[2] http://blog.csdn.net/chjjunking/article/details/5933105
[3]《Machine Learning in Action》
[4] https://en.wikipedia.org/wiki/Mann%E2%80%93Whitney_U_test
[5] Understanding ROC curve
[6] http://stats.stackexchange.com/questions/145566/how-to-calculate-area-under-the-curve-auc-or-the-c-statistic-by-hand

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章