微信公眾號:小白CV
關注可了解更多CV,ML,DL領域基礎/最新知識;
如果你覺得小白CV對您有幫助,歡迎點讚/收藏/轉發
在機器學習領域中,用於評價一個模型的性能有多種指標,其中最常用的幾項有FP、FN、TP、TN、精確率(Precision)、召回率(Recall)、準確率(Accuracy)。
在上一篇原創文章FP、FN、TP、TN、精確率(Precision)、召回率(Recall)、準確率(Accuracy)評價指標詳述中,詳細的介紹了FP、FN、TP、TN、精確率(Precision)、召回率(Recall)、準確率(Accuracy)評價指標的概念和採用python的實現方式。
與上述評價指標還有一個孿生兄弟,就是ROC曲線和AUC值。接下來我們就針對這個孿生兄弟進行詳細的學習。
ROC曲線:全稱是「受試者工作特性」曲線(Receiver Operating Characteristic),源於二戰中用於敵機檢測的雷達信號分析技術,是反映敏感性和特異性的綜合指標。
它通過將連續變量設定出多個不同的臨界值,從而計算出一系列敏感性和特異性,再以敏感性為縱坐標、(1-特異性)為橫坐標繪製成曲線,曲線下面積越大,判別的準確性越高。
在ROC曲線上,最靠近坐標圖左上方的點為敏感性和特異性均較高的臨界值。
在醫學統計裡,任何一個診斷指標,都有兩個最基本的特徵,即敏感性和特異性。
單獨一個指標,如果提高其診斷的敏感性,必然降低其診斷的特異性,換句話說,減少漏診必然增加誤診,反之亦然。
所以,該指標也被引用到AI領域,用於對模型測試結果進行描述,進而反應模型的性能。
針對如何繪製ROC曲線這個問題,首先需要做一下幾個步驟:
根據機器學習中分類器的預測得分對樣例進行排序
按照順序逐個把樣本作為正例進行預測,計算出FPR和TPR
分別以FPR、TPR為橫縱坐標作圖即可得到ROC曲線
所以,作ROC曲線時,需要先求出FPR和TPR。這兩個變量的定義:
FPR = TP/(TP+FN)
TPR = TP/(TP+FP)
ROC曲線示意圖如下:
綜上,此時可以發現,在繪製ROC曲線中,求出FPR和TPR是重中之重。
FPR和TPR該如何計算得到呢?sklearn.metrics.roc_curve函數提供了很好的解決方案。
fpr,tpr,thresholds=sklearn.metrics.roc_curve(y_true,
y_score,
pos_label=None,
sample_weight=None,
drop_intermediate=True)
y_true:為真值,是label
y_score:是模型的預測結果
標籤中認定為正的label個數,例如label= [1,2,3,4],如果設置pos_label = 2,則認為3,4為positive,其他均為negtive
此時以下面一個案例,查看下roc_curve函數返回的數據是什麼樣子的:得到的就是我們所需要的FPR和TPR值,是不是很開心。
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:{}".format(fpr,tpr,thresholds))
之後,我們就拿FPR和TPR數列表,來幹些事情吧
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:{}".format(fpr,tpr,thresholds))
roc_auc = metrics.auc(fpr, tpr)
print(roc_auc)
pyplot.plot(fpr, tpr, lw=1, label="TB vs nonTB, area=%0.2f)" % (roc_auc))
pyplot.xlim([0.00, 1.0])
pyplot.ylim([0.00, 1.0])
pyplot.xlabel("False Positive Rate")
pyplot.ylabel("True Positive Rate")
pyplot.title("ROC")
pyplot.legend(loc="lower right")
pyplot.savefig(r"./ROC.png")
最終的繪製結果是這樣的(有些醜,我們接著往後看)
再回顧下上一篇文章Dog和Cat的故事:FP、FN、TP、TN、精確率(Precision)、召回率(Recall)、準確率(Accuracy)評價指標詳述
y_true = ["dog", "dog", "dog", "cat", "cat", "cat", "cat"]
y_pred = ["cat", "cat", "dog", "cat", "cat", "cat", "cat"]
dog-0,cat-1,則
y_true=[0,0,0,1,1,1,1]
y_pred=[0.3,0.6,0.5,0.8,0.86,0.73,0.85]
上述分別表示本次測試數據的標籤和結果(認為是該對應類別的置信率),由於數據太少,繪製roc曲線不明顯,此處增加三倍數據。
import seaborn as sns
from sklearn.metrics import roc_auc_score, confusion_matrix, roc_curve, auc
from matplotlib import pyplot
y_true = [0, 0, 0, 1, 1, 1, 1,0, 0, 0, 1, 1, 1, 1,0, 0, 0, 1, 1, 1, 1]
y_pred = [0.3, 0.6, 0.5, 0.8, 0.86, 0.73, 0.85,0.6,0.4,0.3,0.5,0.9,0.8,0.3,0.4,0.5,0.6,0.7,0.9,0.8,0.7]
fpr, tpr, thresholds = roc_curve(y_true, y_pred)
roc_auc = auc(fpr, tpr)
print(round(roc_auc,3))
print("fpr:{},tpr:{},thresholds:{}".format(fpr,tpr,thresholds))
pyplot.plot(fpr, tpr, lw=1, label="TB vs nonTB, area=%0.2f)" % (roc_auc))
pyplot.xlim([0.00, 1.0])
pyplot.ylim([0.00, 1.0])
pyplot.xlabel("False Positive Rate")
pyplot.ylabel("True Positive Rate")
pyplot.title("ROC")
pyplot.legend(loc="lower right")
pyplot.savefig(r"./ROC.png")
這裡是列印出來的AUC值和fpr,tpr,thresholds值
繪製的最後結果是這個樣子的,是不是有一些完美了,接著往後看,我們來寫實戰的。
這裡我們假定一個2分類的深度學習項目為例,如果你用過PyTorch就最好了,沒用過也沒關係,因為最終的形式都是要整理為規整的數據形式,之後的工作直接交給def函數來幹。
def inference():
"""
省略一大段,包括模型的加載,實例化;
數據的加載等等,都忽略,往後看,關注數據部分
"""
"""
創造標籤與預測結果的數據段,分別是GT和PD
"""
GT = torch.FloatTensor()
PD = torch.FloatTensor()
for i in range(130):
pd1 =[[0.8,0.2]]
output_pd1 = torch.FloatTensor(pd1).to(device)
target1 = [[1.0,0.0]]
target1 = torch.FloatTensor(target1)
Target1 = torch.autograd.Variable(target1).long().to(device)
GT = torch.cat((GT, Target1.float().cpu()), 0)
PD = torch.cat((PD, output_pd1.float().cpu()), 0)
for i in range(50):
pd1 =[[1.0,0.0]]
output_pd1 = torch.FloatTensor(pd1).to(device)
target1 = [[1.0,0.0]]
target1 = torch.FloatTensor(target1)
Target1 = torch.autograd.Variable(target1).long().to(device)
GT = torch.cat((GT, Target1.float().cpu()), 0)
PD = torch.cat((PD, output_pd1.float().cpu()), 0)
for i in range(150):
pd1 =[[1.0,0.0]]
output_pd1 = torch.FloatTensor(pd1).to(device)
target1 = [[0.0,1.0]]
target1 = torch.FloatTensor(target1)
Target1 = torch.autograd.Variable(target1).long().to(device)
GT = torch.cat((GT, Target1.float().cpu()), 0)
PD = torch.cat((PD, output_pd1.float().cpu()), 0)
confusion_matrix_roc(GT, PD, "ROC", 2)
上面的數據部分是自己創造了,我很難的好吧,為了精簡的關注與ROC曲線的繪製,又要刪繁就簡,不能拖沓,我就自己創建一批數據吧,那就就for循環來創建吧。
測試數據330個,其中前130label是[1,0],預測pd是置信率[0.8,0.2]
中間50個,label是[1,0],預測pd是置信率[1.0,0.0]
後150個,label是[0,1],預測pd是置信率[1,0]
將他們通過cat按行堆疊在一起,這樣就把def定義的函數
confusion_matrix_roc()
所需要的數據給準備好啦。
此時,是不是在想confusion_matrix_roc是什麼?
在這裡定義的,即可就亮出真身,如下:
import torch
import numpy as np
from matplotlib import pyplot
from sklearn.metrics import roc_auc_score, confusion_matrix, roc_curve, auc
def confusion_matrix_roc(GT, PD, experiment, n_class):
GT = GT.numpy()
PD = PD.numpy()
y_gt = np.argmax(GT, 1)
y_gt = np.reshape(y_gt, [-1])
y_pd = np.argmax(PD, 1)
y_pd = np.reshape(y_pd, [-1])
if n_class > 2:
c_matrix = confusion_matrix(y_gt, y_pd)
print("Confussion Matrix:\n", c_matrix)
list_cfs_mtrx = c_matrix.tolist()
print("List", type(list_cfs_mtrx[0]))
path_confusion = r"./confusion_matrix.txt"
np.savetxt(path_confusion, np.reshape(list_cfs_mtrx, -1), delimiter=',', fmt='%5s')
if n_class == 2:
list_cfs_mtrx = []
tn, fp, fn, tp = confusion_matrix(y_gt, y_pd).ravel()
list_cfs_mtrx.append("TN: " + str(tn))
list_cfs_mtrx.append("FP: " + str(fp))
list_cfs_mtrx.append("FN: " + str(fn))
list_cfs_mtrx.append("TP: " + str(tp))
list_cfs_mtrx.append(" ")
list_cfs_mtrx.append("Accuracy: " + str(round((tp + tn) / (tp + fp + fn + tn), 3)))
list_cfs_mtrx.append("Sensitivity: " + str(round(tp / (tp + fn + 0.01), 3)))
list_cfs_mtrx.append("Specificity: " + str(round(1 - (fp / (fp + tn + 0.01)), 3)))
list_cfs_mtrx.append("False positive rate: " + str(round(fp / (fp + tn + 0.01), 3)))
list_cfs_mtrx.append("Positive predictive value: " + str(round(tp / (tp + fp + 0.01), 3)))
list_cfs_mtrx.append("Negative predictive value: " + str(round(tn / (fn + tn + 0.01), 3)))
path_confusion = r"./confusion_matrix.txt"
np.savetxt(path_confusion, np.reshape(list_cfs_mtrx, -1), delimiter=',', fmt='%5s')
pyplot.figure(1)
pyplot.figure(figsize=(6, 6))
print(PD)
fpr, tpr, thresholds = roc_curve(GT[:, 1],PD[:, 1])
roc_auc = auc(fpr, tpr)
print(PD[:, 1])
pyplot.plot(fpr, tpr, lw=1, label="TB vs nonTB, area=%0.2f)" % (roc_auc))
pyplot.plot(thresholds, tpr, lw=1, label='Thr%d area=%0.2f)' % (1, roc_auc))
pyplot.plot([0, 1], [0, 1], '--', color=(0.6, 0.6, 0.6), label='Luck')
pyplot.xlim([0.00, 1.0])
pyplot.ylim([0.00, 1.0])
pyplot.xlabel("False Positive Rate")
pyplot.ylabel("True Positive Rate")
pyplot.title("ROC")
pyplot.legend(loc="lower right")
pyplot.savefig(r"./ROC.png")
認真看到這裡你就會發現,其實就是我們在上一篇文章裡面介紹的內容和本節中說到內容的集合,到這裡,就一網打盡啦。
最後,需要用到就收藏吧,我就不信你哪天用不到。如果您覺得好,就分享給您的小夥伴,我們一起讓知識的傳播更高效,讓技能獲取更快捷,在AI的路上沒有難題,只有遨遊。
小白CV將在第一時間發布CV/AI新動態,整理好文章
(最近會更加關注秋招,Good Luck)