機器學習性能指標之ROC和AUC理解與曲線繪制


一. ROC曲線

1、roc曲線:接收者操作特征(receiveroperating characteristic),roc曲線上每個點反映着對同一信號刺激的感受性。

橫軸:負正類率(false postive rate FPR)特異度,划分實例中所有負例占所有負例的比例;(1-Specificity)

縱軸:真正類率(true postive rate TPR)靈敏度,Sensitivity(正類覆蓋率)

2、針對一個二分類問題,將實例分成正類(postive)或者負類(negative)。但是實際中分類時,會出現四種情況.

(1)若一個實例是正類並且被預測為正類,即為真正類(True Postive TP)

(2)若一個實例是正類,但是被預測成為負類,即為假負類(False Negative FN)

(3)若一個實例是負類,但是被預測成為正類,即為假正類(False Postive FP)

(4)若一個實例是負類,但是被預測成為負類,即為真負類(True Negative TN)

TP:正確的肯定數目

FN:漏報,沒有找到正確匹配的數目

FP:誤報,沒有的匹配不正確

TN:正確拒絕的非匹配數目

列聯表如下,1代表正類,0代表負類:

由上表可得出橫,縱軸的計算公式:

(1)真正類率(True Postive Rate)TPR: TP/(TP+FN),代表分類器預測的正類中實際正實例占所有正實例的比例。

(2)負正類率(False Postive Rate)FPR: FP/(FP+TN),代表分類器預測的正類中實際負實例占所有負實例的比例。

(3)真負類率(True Negative Rate)TNR: TN/(FP+TN),代表分類器預測的負類中實際負實例占所有負實例的比例,TNR=1-FPR。

假設采用邏輯回歸分類器,其給出針對每個實例為正類的概率,那么通過設定一個閾值如0.6,概率大於等於0.6的為正類,小於0.6的為負類。對應的就可以算出一組(FPR,TPR),在平面中得到對應坐標點。隨着閾值的逐漸減小,越來越多的實例被划分為正類,但是這些正類中同樣也摻雜着真正的負實例,即TPR和FPR會同時增大。閾值最大時,對應坐標點為(0,0),閾值最小時,對應坐標點(1,1)。

如下面這幅圖,(a)圖中實線為ROC曲線,線上每個點對應一個閾值。

橫軸FPR:1-TNR,1-Specificity,FPR越大,預測正類中實際負類越多。

縱軸TPR:Sensitivity(正類覆蓋率),TPR越大,預測正類中實際正類越多。

二. 如何畫roc曲線

假設已經得出一系列樣本被划分為正類的概率,然后按照大小排序,下圖是一個示例,圖中共有20個測試樣本,“Class”一欄表示每個測試樣本真正的標簽(p表示正樣本,n表示負樣本),“Score”表示每個測試樣本屬於正樣本的概率。

接下來,我們從高到低,依次將“Score”值作為閾值threshold,當測試樣本屬於正樣本的概率大於或等於這個threshold時,我們認為它為正樣本,否則為負樣本。舉例來說,對於圖中的第4個樣本,其“Score”值為0.6,那么樣本1,2,3,4都被認為是正樣本,因為它們的“Score”值都大於等於0.6,而其他樣本則都認為是負樣本。每次選取一個不同的threshold,我們就可以得到一組FPR和TPR,即ROC曲線上的一點。這樣一來,我們一共得到了20組FPR和TPR的值,將它們畫在ROC曲線的結果如下圖:

上圖ROC曲線一些點怎么得到的分析

具體分析如下:
可以看出實際類別為P的有10個,實際類別為N的也有10個

  • Score = 0.9時,樣本1被認為(預測)是正類(P)。此時根據混淆矩陣有: TP = 1, FN = 9, FP = 0,TN = 10。
    這是因為樣本1為正類(P)被正確預測為正類(P),因此TP = 1; 其他實際正類類別(class為P的)樣本有9個,它們被預測為負類(N)了,因此FN = 9; 樣本實際為負類(N)的,被預測為正類(P)的沒有一個,因此FP = 0, 其他實際負類類別(class為N的)樣本有10個,它們全部被預測為負類(N)了,因此TN = 10 。故TPR = 1/(1+9) = 0.1
  • Score = 0.8時, 同理有: TP = 2, FN = 8,FP = 0, TN = 10。 故TPR = 2/(2+8) = 0.2
  • Score = 0.7時,有: TP = 2, FN = 8,FP = 1, TN = 9。 故TPR = 2/(2+8) = 0.2
  • Score = 0.6時,有:TP = 3, FN = 7,FP = 1, TN = 9。 故TPR = 3/(3+7) = 0.3
    以此類推

AUC(Area under Curve):Roc曲線下的面積,介於0.1和1之間。Auc作為數值可以直觀的評價分類器的好壞,值越大越好。

首先AUC值是一個概率值,當你隨機挑選一個正樣本以及負樣本,當前的分類算法根據計算得到的Score值將這個正樣本排在負樣本前面的概率就是AUC值,AUC值越大,當前分類算法越有可能將正樣本排在負樣本前面,從而能夠更好地分類。

三 為什么使用Roc和Auc評價分類器

既然已經這么多標准,為什么還要使用ROC和AUC呢?因為ROC曲線有個很好的特性:當測試集中的正負樣本的分布變換的時候,ROC曲線能夠保持不變。在實際的數據集中經常會出現樣本類不平衡,即正負樣本比例差距較大,而且測試數據中的正負樣本也可能隨着時間變化。下圖是ROC曲線和Presision-Recall曲線的對比:

在上圖中,(a)和(c)為Roc曲線,(b)和(d)為Precision-Recall曲線。

(a)和(b)展示的是分類其在原始測試集(正負樣本分布平衡)的結果,(c)(d)是將測試集中負樣本的數量增加到原來的10倍后,分類器的結果,可以明顯的看出,ROC曲線基本保持原貌,而Precision-Recall曲線變化較大。

繪制ROC曲線計算AUC值

輸入的數據集可以參考svm預測結果

  • case1: 只去前面36行樣本數據,txt文件名為:evaluate_result2
'''
這里的.txt文件格式如:http://kubicode.me/img/AUC-Calculation-by-Python/evaluate_result.txt
'''
#繪制二分類ROC曲線
import matplotlib.pyplot as plt 
from math import log, exp, sqrt

evaluate_result = './evaluate_result2.txt'

db  = [ ]   #[score,nonclk,clk]
pos, neg = 0, 0
with open(evaluate_result, 'r') as fs:
    for line in fs:
        nonclk, clk, score = line.strip().split('\t')  #變成列表list形式
        nonclk = int(nonclk)
        clk = int(clk)
        db.append([score,nonclk,clk])  

        score = float(score)
        neg = neg + nonclk
        #print("neg數量====", neg, end = '')
        pos = pos + clk
        #print(",  pos數量====", pos)
        
#print("db= ",db)

db = sorted(db, key=lambda x:x[0], reverse=True)  #對ad的score進行降序排序
#print("db_reverse= ",db)

#計算ROC坐標點
xy_arr = [ ]
tp, fp = 0., 0.

for i in range(len(db)):
    fp += db[i][1]
    #print("fp ===", fp, end = '')
    tp += db[i][2]   
    #print(",   tp ===",tp)
    xy_arr.append([fp/neg, tp/pos])   #fp除以negative數目, tp除以positive數目。作為坐標點
#print(xy_arr)  #[[0.06666666666666667, 0.0], [0.06666666666666667, 0.029411764705882353],...]

# 計算曲線下面積
auc = 0.
prev_x = 0
for x, y in xy_arr:   #  x= fp/neg, y = tp/pos
    if x != prev_x:
        auc += (x - prev_x) * y  #矩形面積累加
        prev_x = x

print("The auc is %s" %auc)

x = [ v[0] for v in xy_arr]
y = [ v[1] for v in xy_arr]
plt.title("ROC curve of %s (AUC = %.4f)" % ('svm',auc))
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.plot(x, y)
plt.show()

輸出:
The auc is 0.43137254901960786

  • case2: 取全部數據,txt文件名為:evaluate_result
'''
這里的.txt文件格式如:http://kubicode.me/img/AUC-Calculation-by-Python/evaluate_result.txt
'''
#繪制二分類ROC曲線
import matplotlib.pyplot as plt 
from math import log, exp, sqrt

evaluate_result = './evaluate_result.txt'

db  = [ ]   #[score,nonclk,clk]
pos, neg = 0, 0
with open(evaluate_result, 'r') as fs:
    for line in fs:
        nonclk, clk, score = line.strip().split('\t')  #變成列表list形式
        nonclk = int(nonclk)
        clk = int(clk)
        db.append([score,nonclk,clk])  

        score = float(score)
        neg = neg + nonclk
        #print("neg數量====", neg, end = '')
        pos = pos + clk
        #print(",  pos數量====", pos)
        
#print("db= ",db)

db = sorted(db, key=lambda x:x[0], reverse=True)  #對ad的score進行降序排序
#print("db_reverse= ",db)

#計算ROC坐標點
xy_arr = [ ]
tp, fp = 0., 0.

for i in range(len(db)):
    fp += db[i][1]
    #print("fp ===", fp, end = '')
    tp += db[i][2]   
    #print(",   tp ===",tp)
    xy_arr.append([fp/neg, tp/pos])   #fp除以negative數目, tp除以positive數目。作為坐標點
#print(xy_arr)  #[[0.06666666666666667, 0.0], [0.06666666666666667, 0.029411764705882353],...]

# 計算曲線下面積
auc = 0.
prev_x = 0
for x, y in xy_arr:   #  x= fp/neg, y = tp/pos
    if x != prev_x:
        auc += (x - prev_x) * y  #矩形面積累加
        prev_x = x

print("The auc is %s" %auc)

x = [ v[0] for v in xy_arr]
y = [ v[1] for v in xy_arr]
plt.title("ROC curve of %s (AUC = %.4f)" % ('svm',auc))
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.plot(x, y)
plt.show()

輸出:
The auc is 0.5788039199235478

參考資料:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM