1. 程式人生 > >關於混淆矩陣、ROC、AUC的問題

關於混淆矩陣、ROC、AUC的問題

相信關於混淆矩陣、ROC和AUC的問題一直困擾著大家,要想搞懂ROC和AUC,首先要明白混淆矩陣是什麼。

混淆矩陣中有著Positive、Negative、True、False的概念,其意義如下:

  • 稱預測類別為1的為Positive(陽性),預測類別為0的為Negative(陰性)。
  • 預測正確的為True(真),預測錯誤的為False(偽)。

對上述概念進行組合,就產生了如下的混淆矩陣:

由此引出True Positive Rate(真陽率)、False Positive(偽陽率)兩個概念:

  • TPRate=\frac{TP}{TP+FN}
  • FPRate=\frac{FP}{FP+TN}

仔細看這兩個公式,發現其實TPRate就是TP除以TP所在的列,FPRate就是FP除以FP所在的列,二者意義如下:

  • TPRate的意義是所有真實類別為1的樣本中,預測類別為1的比例。
  • FPRate的意義是所有真是類別為0的樣本中,預測類別為1的比例。

如果上述概念都弄懂了,那麼ROC曲線和AUC就比較容易理解了:

AUC是一個模型評價指標,只能用於二分類模型的評價,對於二分類模型,還有很多其他評價指標,比如logloss,accuracy,precision。AUC和logloss基本是最常見的模型評價指標。

為什麼AUC和logloss比accuracy更常用呢?因為很多機器學習的模型對分類問題的預測結果都是概率,如果要計算accuracy,需要先把概率轉化成類別,這就需要手動設定一個閾值,如果對一個樣本的預測概率高於這個預測,就把這個樣本放進一個類別裡面,低於這個閾值,放進另一個類別裡面。所以這個閾值很大程度上影響了accuracy的計算。使用AUC或者logloss可以避免把預測概率轉換成類別。

AUC是Area under curve的首字母縮寫。Area under curve是什麼呢,從字面理解,就是一條曲線下面區域的面積。所以我們要先來弄清楚這條曲線是什麼。這個曲線有個名字,叫ROC曲線。ROC曲線是基於樣本的真實類別和預測概率來畫的,具體來說,ROC曲線的x軸是偽陽率(false positive rate),y軸是真陽率(true positive rate)。即ROC曲線的橫軸是FPRate,縱軸是TPRate,當二者相等時,即y=x,如下圖,表示的意義是:

對於不論真實類別是1還是0的樣本,分類器預測為1的概率是相等的。

而我們希望分類器達到的效果是:對於真實類別為1的樣本,分類器預測為1的概率(即TPRate),要大於真實類別為0而預測類別為1的概率(即FPRate)。這樣的ROC曲線是在y=x之上的,因此大部分的ROC曲線長成下面這個樣子:

那麼,最理想的情況下沒有真實類別為1而錯分為0的樣本,TPRate一直為1,於是AUC為1,這便是AUC的極大值。

說了這麼多還是不夠直觀,不妨舉個簡單的例子。

首先對於硬分類器(例如SVM,NB),預測類別為離散標籤,對於8個樣本的預測情況如下:

得到混淆矩陣如下:

此時,TP=3,FP=2,TN=1,FN=2,由TPRate=TP/(TP+FN),FPRate=FP/(FP+TN)

進而算得TPRate=3/4,FPRate=2/4,得到ROC曲線:

最終得到AUC為0.625。

對於LR等預測類別為概率的分類器,依然用上述例子,假設預測結果如下:

這時,需要設定閾值來得到混淆矩陣,不同的閾值會影響得到的TPRate,FPRate,如果閾值取0.5,小於0.5的為0,否則為1,那麼我們就得到了與之前一樣的混淆矩陣。其他的閾值就不再囉嗦了。依次使用所有預測值作為閾值,得到一系列TPRate,FPRate,描點,求面積,即可得到AUC。

AUC的優勢,AUC的計算方法同時考慮了分類器對於正例和負例的分類能力,在樣本不平衡的情況下,依然能夠對分類器作出合理的評價。

例如在反欺詐場景,設非欺詐類樣本為正例,負例佔比很少(假設0.1%),如果使用準確率評估,把所有的樣本預測為正例便可以獲得99.9%的準確率

但是如果使用AUC,把所有樣本預測為正例,TPRate和FPRate同時為1,AUC僅為0.5,成功規避了樣本不均勻帶來的問題。

使用python計算AUC的程式碼:

from sklearn import metrics
def AUC():
    fpr,tpr,thresholds=metrics.roc_curve(act,pred,pos_label=1)
    return metrics.auc(fpr,tpr)

 說了半天,大家可能還是不太清楚,下面咱們通過一個python寫的例子加深下理解。

假設我們通過訓練集訓練了一個二分類模型,在測試集上進行預測每個樣本所屬的類別,輸出了屬於類別”1“的概率。現在假設當P>=0.5時(threshold=0.5),預測的類標籤為”1“。

(1)匯入相關庫

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
#生成測試樣本的數量
parameter=50

(2)隨機生成結果集 

data=pd.DataFrame(index=range(0,parameter),columns=('probability','The true label'))
data['The true label']=np.random.randint(0,2,size=len(data))
data['probability']=np.random.choice(np.arange(0.1,1,0.1),len(data['probability']))

生成資料為:

 (3)計算混淆矩陣

cm=np.arange(4).reshape(2,2)
cm[0,0]=len(data[(data['The true label']==0)&(data['probability']<0.5)]) #TN
cm[0,1]=len(data[(data['The true label']==0)&(data['probability']>=0.5)])#FP
cm[1,0]=len(data[(data['The true label']==1)&(data['probability']<0.5)]) #FN
cm[1,1]=len(data[(data['The true label']==1)&(data['probability']>=0.5)])#TP

(4)計算假正率和真正率

首先,畫出混淆矩陣。

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="red" if cm[i, j] > thresh else "black")
    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')
plt.show()    

生成的混淆矩陣如下所示:

 然後,threshold=0.5上的假正率和真正率容易計算,為: FPR=7/(7+6)=0.54,TPR=4/(4+3)=0.57

ROC曲線和AUC值

ROC曲線是一系列threshold下的(FPR,TPR)數值點的連線。此時的threshold的取值分別為測試資料集中各樣本的預測概率。但,取各個概率的順序是從大到小的。

(1)按概率值排序

首先,按預測概率從大到小的順序排序:

data.sort_values('probability',inplace=True,ascending=False)

排序結果如下:

此時,threshold依次取0.9,0.9,0.8,0.8,0.8,0.8,0.6,0.6...。 比如,當threshold=0.9(第2個0.9),兩個”1“預測正確,FPR=1/11=0,TPR=2/7=0.286。 當threshold=0.8(第3個0.8),三個”0“預測錯誤,兩個”1“預測正確,FPR=3/11=0.231,TPR=2/7=0.286。 

(2)計算全部概率值下的FPR和TPR

TPRandFPR=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['The true label']==0])/float(len(data[data['The true label']==0]))    
    TP=len(data1[data1['The true label']==1])/float(len(data[data['The true label']==1]))     
    TPRandFPR.iloc[j]=[TP,FP]

最後,(FPR,TPR)點矩陣如下:

(3)畫出最終的ROC曲線和計算AUC值

from sklearn.metrics import auc
AUC= auc(TPRandFPR['FP'],TPRandFPR['TP'])
plt.scatter(x=TPRandFPR['FP'],y=TPRandFPR['TP'],label='(FPR,TPR)',color='k')
plt.plot(TPRandFPR['FP'], TPRandFPR['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()

下圖的黑色線即為ROC曲線,測試樣本中的資料點越多,曲線越平滑:

AUC(Area Under roc Cure),顧名思義,其就是ROC曲線小的面積,在此例子中AUC=0.52。AUC越大,說明分類效果越好。

當我們增加測試樣本的數量時(parameter=10000),得到的ROC和AUC如下圖所示:

由圖可以看出此時ROC和y=x基本重合,AUC=0.5,這是因為我們隨機生成的測試資料,基本上和猜沒啥區別了,判斷對和錯的概率各佔一半。

補充:

當然,針對上面混淆矩陣我們可以換一種更形象的圖例進行記憶,如下圖所示:

PS.P和R指標(即精確率和召回率)有時候會出現的矛盾的情況,這樣就需要綜合考慮他們,最常見的方法就是F-Measure(又稱為F-Score)。  F-Measure是Precision和Recall加權調和平均,我們常用的是F1指標,即α=1的情況。

本文旨在初步理解混淆矩陣、ROC和AUC,並通過python例子加深對概念的認識,希望對小夥伴們有幫助。

參考文獻:

 李航. 統計學習方法[M]. 清華大學出版社, 2012.