ROC曲線及AUC
ROC曲線
意義
ROC曲線指受試者工作特徵曲線 / 接收器操作特性曲線(receiver operating characteristic curve),是反映敏感性和特異性連續變數的綜合指標,是用構圖法揭示敏感性和特異性的相互關係,它通過將連續變數設定出多個不同的臨界值,從而計算出一系列敏感性和特異性,再以敏感性為縱座標、(1-特異性)為橫座標繪製成曲線,曲線下面積越大,診斷準確性越高。在ROC曲線上,最靠近座標圖左上方的點為敏感性和特異性均較高的臨界值。
例子
如上圖(圖1,引用自維基百科),ROC曲線的橫座標為false positive rate(FPR)1-特異性,縱座標為true positive rate(TPR)敏感性。
上圖(圖2,引用自豆瓣)為混淆矩陣以及ROC曲線各個引數的意義。
TruePositives 為在事先確定好的閾值的情況下,分類器將實際為Yes的樣本正確預測為Yes,換個說法就是一個人找醫生看病,醫生按自己的經驗診斷後認定這個人患有疾病,而且這個人確實患有該種疾病,正確的正例;
FalsePositives 即分類器將實際為No的樣本錯誤的預測為Yes,誤診,錯誤的正例;
FalseNegatives 即分類器將實際為Yes的樣本錯誤預測為No,可以形容為漏診,錯誤的負例;
TrueNegatives 即分類器將實際為No的樣本正確預測為No,良心醫生,告訴看病的人確實沒病,趕緊回家吧,正確的負例。
綜上所述,我們期望的是所有的預測都可以完美的符合實際情況,即tp rate=1且fp rate=0。所以結合起來ROC曲線越靠左上越符合我們的期望,但是僅看ROC曲線無法區分不同分類器的好壞,所以引入了人AUC值,詳細介紹在後面。
圖1中的虛線為一個隨機猜測的結果對照,即只猜對了一半,簡單的說就是二選一毫無根據的瞎蒙。
(資料探勘概念與技術 中文第三版 p237/261 p243/268)
AUC值
AUC(Area Under Curve)被定義為ROC曲線下的面積,顯然這個面積的數值不會大於1。又由於ROC曲線一般都處於y=x這條直線的上方,所以AUC的取值範圍在0.5和1之間。使用AUC值作為評價標準是因為很多時候ROC曲線並不能清晰的說明哪個分類器的效果更好,而作為一個數值,對應AUC更大的分類器效果更好。
ROC曲線畫法
基本思想
ROC曲線的垂直軸表示TPR,水平軸表示FPR,從左下角開始(TPR=FPR=0),檢查列表頂部元素的實際類編號。若為正確分類的正元組,則TP增加,從而TPR增加,在圖中向上移動並繪製一個點。若把一個負元組分類為正,則FP和FPR增加,在圖中向右移動並繪製一個點。
步驟
- 統計資料標籤值ground_truth(及y)中分類為0和分類為1的資料數目:
pos_num=sum(ground_truth==1);neg_num=sum(ground_truth); - 對利用模型求出的預測值predict由低到高進行排序;對應資料原來所在位置進行索引記錄,用於重新排序ground_truth.利用函式sort實現,sort詳情請檢視help文件:
[pre,Index]=sort(predict); ground_truth=ground_truth(Index); - 對ground_truth和predict遍歷i=1:n,n是測試集數目。其目的是隨著predict中概率的增加,隨著增加判斷正負樣本的閾值;也就是說取遍歷到的predict值為閾值,大於閾值的假設預測為正樣本(閾值右邊),小於閾值的假設預測為負樣本(閾值左邊)。
所以同時我們可得到真正TP 和假正FP值:TP=sum(ground_truth(i:n)==1);FP=sum(ground_truth(i:n)==0);
這時我們就可以求取TPR 和FPR了:TPR=TP/pos_num; FPR=FP/neg_num; 把求取到的值儲存起來(x(i),y(i)),因為這就是我們要在圖上畫的點。 - 返回曲線與座標軸間的面積auc。我們的目的是測量資料的準確率,這個面積就是一個量度,auc越大,準確率越高。
auc=auc+(y(i)+y(i-1))*(x(i-1)-x(i))/2;
實現ROC曲線的程式碼如下:
% predict - 分類器對測試集的分類結果
% ground_truth - 測試集的正確標籤,這裡只考慮二分類,即0和1
% auc - 返回ROC曲線的曲線下的面積
function auc = plot_roc( predict, ground_truth )
%初始點為(1.0, 1.0)
%計算出ground_truth中正樣本的數目pos_num和負樣本的數目neg_num
pos_num = sum(ground_truth==1);
neg_num = sum(ground_truth==0);
m=size(ground_truth,1);
[pre,Index]=sort(predict);
ground_truth=ground_truth(Index);
x=zeros(m+1,1);
y=zeros(m+1,1);
auc=0;
x(1)=1;y(1)=1;
for i=2:m
TP=sum(ground_truth(i:m)==1);FP=sum(ground_truth(i:m)==0);
x(i)=FP/neg_num;
y(i)=TP/pos_num;
auc=auc+(y(i)+y(i-1))*(x(i-1)-x(i))/2;
end;
x(m+1)=0;y(m+1)=0;
auc=auc+y(m)*x(m)/2;
plot(x,y);
end