AUC(Area under Curve):Roc曲線下的面積,介於0.1和1之間。Auc作為數值可以直觀的評價分類器的好壞,值越大越好。
首先AUC值是一個概率值,當你隨機挑選一個正樣本以及負樣本,當前的分類算法根據計算得到的Score值將這個正樣本排在負樣本前面的概率就是AUC值,AUC值越大,當前分類算法越有可能將正樣本排在負樣本前面,從而能夠更好地分類。
1. 什么是ROC曲線?
ROC曲線是Receiver operating characteristic curve的簡稱,中文名為“受試者工作特征曲線”。ROC曲線源於軍事領域,橫坐標為假陽性率(False positive rate,FPR),縱坐標為真陽性率(True positive rate,TPR).
假陽性率 FPR = FP/N ---N個負樣本中被判斷為正樣本的個數占真實的負樣本的個數
真陽性率 TPR = TP/P ---P個正樣本中被預測為正樣本的個數占真實的正樣本的個數
2. 如何繪制ROC曲線?
ROC曲線是通過不斷移動分類器的“截斷點”來生成曲線上的一組關鍵點的,“截斷點”指的就是區分正負預測結果的閾值。
通過動態地調整截斷點,從最高的得分開始,逐漸調整到最低得分,每一個截斷點都會對應一個FPR和TPR,在ROC圖上繪制出每個截斷點對應的位置,再連接所有點就得到最終的ROC曲線。
ROC曲線一定程度上可以反映分類器的分類效果,但是不夠直觀,我們希望有這么一個指標,如果這個指標越大越好,越小越差,於是,就有了AUC。AUC實際上就是ROC曲線下的面積。AUC直觀地反映了ROC曲線表達的分類能力。
- AUC=1,完美分類器,采用這個預測模型時,不管設定什么閾值都能得出完美預測。絕大多數預測的場合,不存在完美分類器。
- 0.5<AUC<10,優於隨機猜測。這個分類器(模型)妥善設定閾值的話,能有預測價值。
- AUC=0.5,跟隨機猜測一樣(例:丟銅板),模型沒有預測價值。
- AUC<0.5,比隨機猜測還差;但只要總是反預測而行,就優於隨機猜測,因此不存在 AUC<0.5AUC<0.5 的情況。
3. 如何計算AUC?
(1)適合數據量少
AUC是一個模型評價指標,只能用於二分類模型的評價,對於二分類模型,還有很多其他評價指標,比如logloss,accuracy,precision。為什么AUC和logloss比accuracy更常用呢?因為很多機器學習的模型對分類問題的預測結果都是概率,如果要計算accuracy,需要先把概率轉化成類別,這就需要手動設置一個閾值,如果一個樣本的預測概率高於這個預測,就把這個樣本放進一個類別里面,低於這個閾值,放進另一個類別里面。所以這個閾值很大程度上影響了accuracy的計算,使用AUC或logloss可以避免把預測概率轉換成類別。
AUC是Area under curve的首字母縮寫,從字面上理解,就是ROC曲線下的面積大小,該值能夠量化地反映基於ROC曲線衡量出的模型性能。由於ROC曲線一般都處於y=x這條直線的上方(如果不是的話,只要把模型預測的概率反轉成1-p就可以得到一個更好的分類器),所以AUC的取值一般在0.5-1之間。AUC越大,說明分類器越可能把真正的正樣本排在前面,分類性能越好。
舉例:5個樣本,真實的類別(標簽)是
y | 1 | 1 | 0 | 0 | 1 |
p | 0.5 | 0.6 | 0.55 | 0.4 | 0.7 |
如文章一開始多說,我們需要選定閾值才能把概率轉化為類別,選定不同的閾值會得到不同的結果。如果我們選定的閾值為0.1,那5個樣本被分進1的類別,如果選定0.3,結果仍然一樣。如果選了0.45作為閾值,那么只有樣本4被分進0,其余都進入1類。一旦得到了類別,我們就可以計算相應的真、偽陽性率,當我們把所有計算得到的不同真、偽陽性率連起來,就畫出了ROC曲線。
python代碼如下:
from sklearn import metrics def aucfun(act,pred): fpr,tpr,thresholds = metrics.roc_curve(act,pred,pos_label=1) return metrics.auc(fpr,tpr)
(2)適合數據量大,時間復雜度O(N*M)
一個關於AUC的很有趣的性質是,它和Wilcoxon-Mann-Witney Test是等價的。而Wilcoxon-Mann-Witney Test就是測試任意給一個正類樣本和一個負類樣本,正類樣本的score有多大的概率大於負類樣本的score。有了這個定義,我們就得到了另外一中計 算AUC的辦法:得到這個概率。我們知道,在有限樣本中我們常用的得到概率的辦法就是通過頻率來估計。這種估計隨着樣本規模的擴大而逐漸逼近真實值。這和上面的方法中,樣本數越多,計算的AUC越准確類似,也和計算積分的時候,小區間划分的越細,計算的越准確是同樣的道理。具體來說就是統計一下所有的 M×N(M為正類樣本的數目,N為負類樣本的數目)個正負樣本對中,有多少個組中的正樣本的score大於負樣本的score。當二元組中正負樣本的 score相等的時候,按照0.5計算。然后除以MN。實現這個方法的復雜度為O(n^2)。n為樣本數(即n=M+N)
(3)適合數據量大,時間復雜度O(M+N)
第三種方法實際上和上述第二種方法是一樣的,但是復雜度減小了。它也是首先對score從大到小排序,然后令最大score對應的sample 的rank為n,第二大score對應sample的rank為n-1,以此類推。然后把所有的正類樣本的rank相加,再減去M-1種兩個正樣本組合的情況。得到的就是所有的樣本中有多少對正類樣本的score大於負類樣本的score。然后再除以M×N。
詳細解釋如下: 隨機抽取一個樣本,對應每一潛在可能值X都對應有一個判定位正樣本的概率P。
對一批已知正負的樣本集合進行分類。
按概率從高到矮排序,對於正樣本中概率最高的,排序為rank_1,比它概率小的有M-1個正樣本(M為正樣本個數),(rank_1-M)個負樣本。
正樣本概率第二高的,排序為rank_2,比它概率小的有M-2個正樣本,(rank_2-M+1)個負樣本。
以此類推,正樣本中概率最小的,排序為rank_M,比它概率小的有0個正樣本,rank_M-1個負樣本。
總共有M*N個正負樣本對(N為負樣本個數)。把所有比較中,正樣本概率大於負樣本概率的例子都算上,得到公式(rank_1-M+rank_2-M+1...+rank_M-1)/(M*N)就是正樣本概率大於負樣本概率的可能性了。化簡后得:【離散情況下】
4. ROC曲線相比P-R曲線有什么特點?
當正負樣本的分布發生變化時,ROC曲線的形狀能夠基本保持不變,而P-R曲線的形狀一般會發生較劇烈的變化。ROC能夠盡量降低不同測試集帶來的干擾,更加客觀的衡量模型本身的性能。如果研究者希望更多地看到模型在特定數據集上的表現,P-R曲線能夠更直觀地反映其性能。
5. ROC實現
(1)pandas實現roc
隨機生成樣本和結果
import pandas as pd import matplotlib.pyplot as plt import numpy as np %matplotlib inline import warnings warnings.filterwarnings("ignore") #測試樣本數量 parameter = 30 #隨機生成結果集 data = pd.DataFrame(index=range(0,parameter),columns=('probability','label')) data['label'] = np.random.randint(0,2,size=len(data)) data['probability'] = np.random.choice(np.arange(0.1,1.0,0.1),len(data['probability'])) data.columns
計算混淆矩陣
#計算混淆矩陣 cm = np.arange(4).reshape(2,2) cm[0,0] = len(data.query('label==0 and probability<0.5')) #TN cm[0,1] = len(data.query('label==0 and probability>=0.5')) #FP cm[1,0] = len(data.query('label==1 and probability<0.5')) #FN cm[1,1] = len(data.query('label==1 and probability>=0.5')) #TP cm
畫出混淆矩陣
import itertools classes = [0,1] plt.figure() plt.imshow(cm,interpolation='nearest',cmap=plt.cm.Blues) plt.title('Confusion matrix') tick_marks=np.arange(len(classes)) plt.xticks(tick_marks,classes,rotation=0) plt.yticks(tick_marks,classes) thresh = cm.max()/2 for i,j in itertools.product(range(cm.shape[0]),range(cm.shape[1])): plt.text(j,i,cm[i,j],horizontalalignment='center',color = 'white' if cm[i,j]>thresh else 'black') plt.tight_layout() plt.ylabel('True label') plt.xlabel('Predicted label')
ROC曲線是一系列threshold下的(FPR,TPR)數值點的連線。此時的threshold的取值分別為測試數據集中各樣本的預測概率。但,取各個概率的順序是從大到小的。
#按預測概率從大到小的順序排序 data.sort_values('probability',inplace=True,ascending=False) data.head()
閾值分別取0.9,0.9,0.8,0.8,...比如,當threshold=0.9(第三個0.9),兩個“0”預測錯誤,一個“1”預測正確,
FPR=1/13,TPR=1/17
#計算全部概率值下的FPR,TPR TFRandFPR = pd.DataFrame(index=range(len(data)),columns=('TP','FP')) for j in range(len(data)): data1 = data.head(n=j+1) FP=len(data1[data1['label']==0] [data1['probability']>=data1.head(len(data1))['probability']])/float(len(data[data['label']==0])) TP=len(data1[data1['label']==1] [data1['probability']>=data1.head(len(data1))['probability']])/float(len(data[data['label']==1])) TFRandFPR.iloc[j] = [TP,FP]
from sklearn.metrics import auc AUC = auc(TFRandFPR['FP'],TFRandFPR['TP']) plt.scatter(x=TFRandFPR['FP'],y=TFRandFPR['TP'],label='(FPR,TPR)',color='k') plt.plot(TFRandFPR['FP'],TFRandFPR['TP'],'k',label='AUC=%0.2f'%AUC) plt.legend(loc='lower right') plt.title('Receiver Operating Characteristic') plt.plot([(0,0),(1,1)],'r--') plt.xlim([-0.01,1.01]) plt.ylim([-0.01,01.01]) plt.ylabel('True Positive Rate') plt.xlabel('False Positive Rate') plt.show()
在此例子中AUC=0.58,AUC越大,說明分類效果越好。
(2)直接計算直方圖面積
def roc_auc(labels,preds,n_bins=1500): pos_len = sum(labels) neg_len = len(labels) - pos_len total_case = pos_len * neg_len pos_hist = [0 for i in range(n_bins)] neg_hist = [0 for i in range(n_bins)] bin_width = 1.0 / float(n_bins) for i in range(len(labels)): nth_bin = int(preds[i]/bin_width) if labels[i]==1: pos_hist[nth_bin] += 1 else: neg_hist[nth_bin] += 1 accumulated_neg = 0 satisfied_pair = 0 for i in range(n_bins): satisfied_pair += (pos_hist[i]*accumulated_neg + pos_hist[i]*neg_hist[i]*0.5) accumulated_neg += neg_hist[i] return round(satisfied_pair/float(total_case),2) N = int(input()) # labels,probs = [],[] labels , preds = [1,0,1,1,0,1,0,0,1,0] , [0.90,0.70,0.60,0.55,0.52,0.40,0.38,0.35,0.31,0.10] # for i in range(N): # label,pred = map(float,input().split()) # labels.append(label) # preds.append(pred) res = roc_auc(labels, preds) print(res)
6. 總結
- ROC曲線反映了分類器的分類能力,結合考慮了分類器輸出概率的准確性
- AUC量化了ROC曲線的分類能力,越大分類效果越好,輸出概率越合理
- AUC常用作CTR的離線評價,AUC越大,CTR的排序能力越強
7. 大牛的見解
[1]From 機器學習和統計里面的auc怎么理解?
[2]From 機器學習和統計里面的auc怎么理解?
[3]From 精確率、召回率、F1 值、ROC、AUC 各自的優缺點是什么?
[4]From 多高的AUC才算高?
參考文獻:
【2】AUC的概率解釋
【4】ROC曲線-閾值評價標准
【6】ROC曲線與AUC值