真實值:1 | 真實值:0 | |
預測值:1 | TP | FP |
預測值:0 | FN | TN |
真陽率(True positive):$TPr=\frac{ TP}{(TP+FN)} $真正的1中,被預測為1的比例
假陽率(False positive):$FPr= \frac{FP}{(FP+TN)}$ 真正的0中,被預測為1的比例
精確率(Precision):$Precision = \frac{TP}{(TP+FP)} $預測出來的1中,真正為1的比例
召回率(Recall):$Recall = \frac{TP}{(TP+FN) }$真正的1中,被預測為1的比例
准確率(Accuracy):$Accuracy = \frac{(TP+TN)}{(TP+FN+FP+TN)}$所有樣本中能被正確識別為0或者1的概率
1.ROC 曲線
因為預測出來的評分需要有一個閾值,擦能把他划分為1或者0.
一個閾值對應一組(TPr,FPr),多個閾值就能夠得到多組(TPr,FPr),就能得到ROC曲線.
我們希望一組(TPr,FPr)中,TPr越大越好,FPr越小越好
sklearn代碼如下:
import numpy as np from sklearn import metrics y = np.array([1, 1, 2, 2]) scores = np.array([0.1, 0.4, 0.35, 0.8]) fpr, tpr, thresholds = metrics.roc_curve(y, scores, pos_label=2) print(fpr, tpr, thresholds)
# [0. 0. 0.5 0.5 1. ] [0. 0.5 0.5 1. 1. ] [1.8 0.8 0.4 0.35 0.1 ]
y = np.array([0, 0, 1, 1])
scores = np.array([0.1, 0.4, 0.35, 0.8])
fpr, tpr, thresholds = metrics.roc_curve(y, scores)
print(fpr, tpr, thresholds)
# [0. 0. 0.5 0.5 1. ] [0. 0.5 0.5 1. 1. ] [1.8 0.8 0.4 0.35 0.1 ]
因為真實的標簽使用{1,2}來區分的,所以需要用pos_label=2來制定2是正類的標簽。
如果你的數據標簽是{0,1}或者{-1,1},那么可以不用指定pos_label。
(很容易看到:如果閾值取大於0.8的數,那么TPr=FPr=0。sklearn可能是默認取了最高分0.8+1,所以閾值才會出現1.8)
閾值是自動從最高分[1.8 0.8 0.4 0.35 0.1 ]依次往下取的。
大於等於閾值,預測為1.
不同閾值時的預測標簽 | ||||||
真實標簽y | 得分scores | 閾值=1.8 | 閾值=0.8 | 閾值=0.4 | 閾值=0.35 | 閾值=0.1 |
1 | 0.8 | 0 | 1 | 1 | 1 | 1 |
1 | 0.35 | 0 | 0 | 0 | 1 | 1 |
0 | 0.4 | 0 | 0 | 1 | 1 | 1 |
0 | 0.1 | 0 | 0 | 0 | 0 | 1 |
當閾值=1.8: TP=0,FP=0,FN=2,TN=2;所以tpr=0, fpr=0.
當閾值=0.8: TP=1,FP=0,FN=1,TN=2;所以tpr=0.5, fpr=0.
當閾值=0.4: TP=1,FP=1,FN=1,TN=1;所以tpr=0.5, fpr=0.5.
當閾值=0.35: TP=2,FP=1,FN=0,TN=1;所以tpr=1, fpr=0.5.
當閾值=0.1: TP=2,FP=2,FN=0,TN=0;所以tpr=1, fpr=1.
五組(fpr,tpr)數據,把他們連起來就得到了ROC曲線
實際中,閾值的取值非常多,所以roc曲線更加光滑
2.AUC
AUC值就是ROC曲線下面的面積,怎么計算呢?
方法一:可以采用積分方法求得面積,不過未免有些麻煩。
方法二:sklearn.metrics.roc_auc_score(或者sklearn.metrics.auc)可以計算AUC,但是需要通過“真實標簽y_true”和“模型預測得到的概率y_scores”來計算的。
roc_auc_score直接根據標簽y和預測概率得分scores計算得到AUC的值
sklearn.metrics.auc唏噓通過roc_curve先得到fpr, tpr作為輸入。
import numpy as np from sklearn.metrics import roc_auc_score,auc y = np.array([0, 0, 1, 1]) scores = np.array([0.1, 0.4, 0.35, 0.8]) auc1 = roc_auc_score(y, scores) fpr, tpr, thresholds = roc_curve(y, scores) auc2 = auc(fpr, tpr) print(auc1,auc2)
auc1 = 0.75
auc2 = 0.75
計算方法:計算(正樣本預測得分大於負樣本預測得分)的組數。
''' 1 0.9 1 0.8 1 0.3 0 0.2 0 0.4 正樣本個數*負樣本個數=3*2 = 6 第一個正樣本預測為0.9,0.9大於負樣本預測出來的0.2和0.4,所以計數為2 第一個正樣本預測為0.8,0.9大於負樣本預測出來的0.2和0.4,所以計數為2 第一個正樣本預測為0.3,0.9大於負樣本預測出來的0.2,所以計數為1 2+2+1 = 5 所以auc=5/6,auc>0.7都可以運用到線上生產環境 '''
方法三:快速計算方法。
方法二中需要比較每一個正樣本和每一個負樣本之間的預測概率大小,這是非常麻煩的。設正樣本數目為n1,負樣本數目為n0.按照得分從小到大排列所有的正負樣本。然后采用下面說的方法來計算AUC值(轉)。
3. AP
點擊查看官方文檔說明
公式:$AP = \sum_{n}{(R_{n}-R_{n-1})P_{n}}$
這兒涉及到了兩個函數
1.precision_recall_curve、可以求得不同閾值下的precision和recall,
2.average_precision_score,AP就是通過這個函數求得
precision_recall_curve得到了precision和recall,還便於我們可以手動計算,驗證average_precision_score的計算結果。
import numpy as np from sklearn.metrics import precision_recall_curve y_true = np.array([0, 0, 1,1]) y_scores = np.array([0.1, 0.4, 0.35, 0.8]) precision, recall, thresholds = precision_recall_curve(y_true, y_scores)# stop when full recall attained print(precision,recall,thresholds) a_p_s = average_precision_score(y_true, y_scores) print("aps=",a_p_s)
precision=[0.66666667 0.5 1. 1. ]
recall = [1. 0.5 0.5 0. ]
thresholds = [0.35 0.4 0.8 ] aps= 0.8333333333333333
注意到為什么thresholds的結果為[0.35 0.4 0.8 ],為什么沒了0.1,也沒了1.8.(因為在metrics.roc_curve(y, scores)我們看到thresholds的結果為[0.1, 0.35, 0.4, 0.8, 1.8]含有0.1和1.8)
文檔這么寫的:
The last precision and recall values are 1. and 0. respectively and do not have a corresponding threshold. This ensures that the graph starts on the y axis.
我們可以理解到:之所以1.8沒了,因為直接把最高分0.8當成閾值。並且在precision和recall對應的列表分別添加了“1”、“0”
為什么最小閾值0.1也沒了呢,注意看在代碼注釋處這樣寫道
# stop when full recall attained # and reverse the outputs so recall is decreasing
所以說可能是在閾值為0.35的時候,召回率recall已經為1.我們來驗證一下:
當閾值=0.35: TP=2,FP=1,FN=0,TN=1; recall = TP/(TP+FN)=1,precision=TP/(TP+FP)=2/3=0.6667
當閾值=0.1: TP=2,FP=2,FN=0,TN=0; recall = TP/(TP+FN)=1,precision=TP/(TP+FP)=1/2=0.5
可以看到當閾值=0.35的時候,recall確實已經為1.
我們換一組數據嘗試一下,看看到底是recall=1就停止了,還是說最小的閾值沒有考慮:
import numpy as np from sklearn.metrics import precision_recall_curve y_true = np.array([0, 0, 1,1]) y_scores = np.array([0.5, 0.4, 0.35, 0.8]) precision, recall, thresholds = precision_recall_curve(y_true, y_scores)# stop when full recall attained print(precision,recall,thresholds) a_p_s = average_precision_score(y_true, y_scores) print("aps=",a_p_s)
precision = [0.5 0.33333333 0.5 1. 1. ]
recall = [1. 0.5 0.5 0.5 0. ]
thresholds = [0.35 0.4 0.5 0.8 ] aps= 0.75
發現輸出了所有的閾值(除了1.8):thresholds = [0.35 0.4 0.5 0.8 ]。
說明precision_recall_curve函數,
1.是從預測結果的最高分作為閾值開始計算的precision和recall,當recall=1,就停止了計算
2.並且在precision和recall對應的列表分別添加了“1”、“0”
a.在第一組數據中
precision=[0.66666667 0.5 1. 1. ]
recall = [1. 0.5 0.5 0. ]
thresholds = [0.35 0.4 0.8 ] aps= 0.8333333333333333
根據公式來計算一下:
AP=(1-0.5)*0.666667+(0.5-0.5)*0.5+(0.5-0)*1=0.83333333333=aps
b.在第二組數據中
precision = [0.5 0.33333333 0.5 1. 1. ]
recall = [1. 0.5 0.5 0.5 0. ]
thresholds = [0.35 0.4 0.5 0.8 ]
aps = 0.75
根據公式計算一下:
AP = (1-0.5)*0.5 + (0.5-0.5)*0.33333 +(0.5-0.5)*0.5 + (0.5-0)*1 = 0.75
4.precision,recall,accuracy
from sklearn.metrics import recall_score,precision_score, accuracy_score y_true = [0, 1, 1, 0, 1, 0,1,1] y_pred = [0, 1, 1, 1, 0, 0,0,1] precision =precision_score(y_true, y_pred) # doctest: +ELLIPSIS recall =recall_score(y_true, y_pred) accuracy = accuracy_score(y_true, y_pred) print(precision, recall, accuracy) # 0.75 0.6 0.625
真實標簽 y_true = [0, 1, 1, 0, 1, 0, 1, 1]
預測標簽 y_pred = [0, 1, 1, 1, 0, 0, 0,1]
TP = 3 FP = 1
FN = 2 TN = 2
所以precision = TP/(TP+FP)=3/4=0.75
racall = TP/(TP+FN)=3/5=0.6
accuracy = (TP+TN)/(TP+FP+FN+TN)=5/8=0.625