五、衡量分類任務的性能指標
5、ROC曲線與AUC
(1)ROC曲線
ROC曲線( Receiver Operating Cha\fracteristic Curve )描述的 TPR ( True Positive Rate )與 FPR ( False Positive Rate )之間關系的曲線。
TPR 與 FPR 的計算公式如下:
舉例:
真實\預測 | 0 | 1 |
0 | 9978 | 12 |
1 | 2 | 8 |
FPR=12/9990=0.0012
TPR=8/10=0.8
分析:
TPR描述的是模型預測Positive並且預測正確的數量占真實類別為Positive樣本的比例。
FPR描述的模型預測Positive並且預測錯了的數量占真實類別為Negtive樣本的比例。
(2)TPR 與 FPR 關系
假設有這么一組數據,菱形代表 Positive,圓形代表 Negtive。
現在需要訓練一個邏輯回歸的模型對數據進行分類,假如將從 0 到 1 中的一些值作為模型的分類閾值。若模型認為當前數據是 Positive 的概率小於分類閾值則分類為 Negtive ,否則就分類為 Positive (*假設分類閾值為 0.8,模型認為這條數據是 Positive 的概率為 0.7, 0.7 小於 0.8,那么模型就認為這條數據是 Negtive *)。在不同的分類閾值下,模型所對應的 TPR 與 FPR 如下圖所示(豎線代表分類閾值,模型會將豎線左邊的數據分類成 Negtive,豎線右邊的分類成 Positive ):
從圖中可以看出,當模型的 TPR 越高 FPR 也會越高, TPR 越低 FPR 也會越低。這與精准率和召回率之間的關系剛好相反。並且,模型的分類閾值一但改變,就有一組對應的 TPR 與 FPR 。
舉例:
TPR | 0.20 | 0.35 | 0.37 | 0.51 | 0.53 | 0.56 | 0.71 | 0.82 | 0.92 | 0.93 |
FPR | 0.08 | 0.10 | 0.111 | 0.12 | 0.13 | 0.14 | 0.21 | 0.26 | 0.41 | 0.42 |
若將 FPR 作為橫軸, TPR 作為縱軸,將上面的表格以折線圖的形式畫出來就是 ROC曲線 :
假設現在有模型 A 和模型 B ,它們的 ROC 曲線如下圖所示(其中模型A的ROC曲線為黃色,模型B的 ROC 曲線為藍色):
那么模型 A 的性能比模型 B 的性能好,因為模型 A 當 FPR 較低時所對應的 TPR 比模型 B 的低 FPR 所對應的 TPR 更高。由由於隨着 FPR 的增大, TPR 也會增大。所以 ROC 曲線與橫軸所圍成的面積越大,模型的分類性能就越高。而 ROC曲線的面積稱為AUC。
(3)AUC
很明顯模型的 AUC 越高,模型的二分類性能就越強。AUC 的計算公式如下:
其中 M 為真實類別為 Positive 的樣本數量,N 為真實類別為 Negtive 的樣本數量。ranki 代表了真實類別為 Positive 的樣本點額預測概率從小到大排序后,該預測概率排在第幾。
舉例:
現有預測概率與真實類別的表格如下所示(其中 0 表示 Negtive, 1 表示 Positive ):
編號 | 預測概率 | 真實類別 |
---|---|---|
1 | 0.1 | 0 |
2 | 0.4 | 0 |
3 | 0.3 | 1 |
4 | 0.8 | 1 |
想要得到公式中的 rank,就需要將預測概率從小到大排序,排序后如下:
編號 | 預測概率 | 真實類別 |
---|---|---|
1 | 0.1 | 0 |
3 | 0.3 | 1 |
2 | 0.4 | 0 |
4 | 0.8 | 1 |
排序后的表格中,真實類別為 Positive 只有編號為 3 和編號為 4 的數據,並且編號為 3 的數據排在第 2 ,編號為 4 的數據排在第 4。所以 rank=[2, 4] 。又因表格中真是類別為 Positive 的數據有 2 條, Negtive 的數據有 2 條。因此 M 為2, N 為2。所以根據 AUC 的計算公式可知:
繪制AUC曲線,代碼實現:
import numpy as np def calAUC(prob, labels): ''' 計算AUC並返回 :param prob: 模型預測樣本為Positive的概率列表,類型為ndarray :param labels: 樣本的真實類別列表,其中1表示Positive,0表示Negtive,類型為ndarray :return: AUC,類型為float ''' f = list(zip(prob,labels)) #zip函數能將列表序列。依次取出組成一個由元組組成的列表
rank = [values2 for values1,values2 in sorted(f,key = lambda x:x[0])] # 按概率從小到大排序
rankList = [i+1 for i in range(len(rank)) if rank[i] == 1] # 得到rank
posNum = 0 negNum = 0 for i in range(len(labels)): if(labels[i] == 1): posNum += 1
else: negNum += 1
# 根據公式計算AUC
auc = (sum(rankList) - (posNum*(posNum+1))/2)/(posNum*negNum) return auc