分類模型評價指標說明


分類模型評價指標說明

分類涉及到的指標特別容易搞混,不是這個率就是那個率,最后都分不清誰是誰,這份文檔就是為此給大家梳理一下。

混淆矩陣

混淆矩陣很重要,很多指標都是源於混淆矩陣,這個務必要弄懂。

例子

為了解釋混淆矩陣,先來看看下面這個二分類的例子。

例:有20個病人來醫院檢查,是否患病的預測值和真實值如下表所示。

病號 預測值 真實值 病號 預測值 真實值
1 1 1 11 0 0
2 0 0 12 0 0
3 1 1 13 0 0
4 0 0 14 1 1
5 0 0 15 0 0
6 1 1 16 1 0
7 0 0 17 1 1
8 0 0 18 0 0
9 0 1 19 0 0
10 0 0 20 0 1

其中,1表示患病,0表示不患病。

本文檔默認用0和1來作為二分類符號。

你也可以用其他符號來表示,如1表示患病,-1表示不患病。只要能區分就行。

這樣就出現4種結果:

  • 預測為1,實際也為1,包括病號1,3,6,14,17,一共5個樣本;
  • 預測為1,實際為0,包括病號16,只有1個樣本;
  • 預測為0,實際為1,包括病號9,20,只有2個樣本;
  • 預測為0,實際也為0,包括病號2,4,5,7,8,10,11,12,13,15,18,19,一共12個樣本。

我們把各個結果的數量填到下面這個表格中

這就是病患例子的混淆矩陣。

混淆矩陣定義

二分類混淆矩陣的一般定義只是將1和0叫做正例和負例,把4種結果的樣本數量用符號來表示,用什么符號呢?

如果我們用P(Positive)代表1,用N(Negative)代表0,那這四種結果分別是PP,PN,NP,NN,但這樣表示有點問題,譬如,PN的意思是預測為1實際為0還是預測為0實際為1?需要規定好了,還得記住,好麻煩。

干脆再引入符號T(True)代表預測正確,F(False)表示預測錯誤,那么之前的P和N代表預測是1還是0,T和F表示預測是否正確。

四種情況可以分別表示為

  • TP:預測為1,預測正確,即實際也為1;
  • FP:預測為1,預測錯誤,即實際為0;
  • FN:預測為0,預測錯誤,即實際為1;
  • TN:預測為0,預測正確,即實際也為0。

混淆矩陣的定義如下:

混淆矩陣代碼

采用sklearn.metrics中的confusion_matrix函數計算混淆矩陣,數據用的還是之前那個病患檢查的樣本。

from sklearn.metrics import confusion_matrix

# 真實值
y_true = [1,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,0,1]
# 預測值
y_pred = [1,0,1,0,0,1,0,0,0,0,0,0,0,1,0,1,1,0,0,0]

c_matrix = confusion_matrix(y_true, y_pred)
print(c_matrix)

代碼輸出

[[12  1]
 [ 2  5]]

有了混淆矩陣,就可以定義一些指標了。

正確率

准確率(Accuracy)的定義很簡單,就是猜對的樣本占總樣本的比例,公式如下:

\[\text{Accuracy} = \frac{猜對的樣本量}{樣本總量} = \frac{TP+TN}{TP+FP+FN+TN} \]

正樣本是實際為正例的樣本,負樣本是實際為負例的樣本。

計算正確率可以調用sklearn.metrics的accuracy_score函數,代碼如下:

from sklearn.metrics import accuracy_score

# 真實值
y_true = [1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1]
# 預測值
y_pred = [1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0]

mc = accuracy_score(y_true, y_pred)
print('Accuracy: %.2f'%mc)

結果為

Accuracy: 0.85

正確率作為評價指標有一個很致命的缺點,就是樣本不平衡時正確率無法反映模型結果的好壞。

舉個例子,預估某個網站上某一天廣告的點擊率,假如一天有1000個人瀏覽,實際有50個人點擊廣告,假如分類器預測沒有人會點擊,那么這個模型結果的正確率是多少呢?

我們算一下:分類器預測正確的有950個樣本,一共有1000個樣本,根據定義\(\text{Accuracy} = \frac{950}{1000} = 0.95\),正確率為95%!!!

一個點擊的人都沒有預測對,正確率都能有95%,那這個指標對模型的評價不合理。

那樣本不平衡的時候怎么辦呢?

細心想想,樣本不平衡的問題是正負樣本在數量上有很大差距,數量少的那方被重視程度低,比較吃虧,要解決這個問題,把正負樣本分開評價不就好啦,大家河水不犯井水。

按照這個思路,引入下面兩個概念:真陽率和假陽率。

真陽率和假陽率

真陽率

真陽率(True Positive Rate, TPR)的定義是:正樣本中猜對的比例。公式如下

\[TPR = \frac{TP}{TP+FN} \]

假陽率

假陽率(False Positive Rate, FPR)的定義是:負樣本中猜錯的比例。公式如下

\[FPR = \frac{FP}{TN+FP} \]

真陽率和假陽率的公式比較

\[\begin{aligned} TPR &= \frac{TP}{TP+FN} \\ FPR &= \frac{FP}{TN+FP} \end{aligned} \]

TPR公式的分母是正樣本數量,FPR公式的分母是負樣本數量,這就遵循了正負樣本分開評價的思路。

TPR公式的分子是TP,說明這個指標關注正確率;FPR公式的分子是FP,說明這個指標關注錯誤率。

通常,這兩個指標不單獨使用,那要怎么用呢?

那就不得不介紹ROC/AUC的概念了。

ROC/AUC

例子

還是那個病患事例,不同在於預測值不是0和1的離散值,而是一個0到1的連續值,叫做置信度(confidence score),可以理解為”概率“,越接近1,結果越可能為1;越接近0,結果越可能為0。

病號 置信度 真實值 病號 置信度 真實值
1 0.8 1 11 0.8 0
2 0.2 0 12 0.1 0
3 0.4 1 13 0.2 0
4 0.1 0 14 0.9 1
5 0.4 0 15 0.3 0
6 0.8 1 16 0.6 0
7 0.3 0 17 0.8 1
8 0.2 0 18 0.2 0
9 0.6 1 19 0.2 0
10 0.5 0 20 0.4 1

預測值是置信度的話,要怎么算TPR和FPR呢?

很簡單,給個閾值就行,不小於這個閾值就設為1,小於設為0。

注意,在實際的做法中,一般不用卡閾值的方法,而是按照置信度排序,然后取前N條樣本,其實效果等同取閾值。

但閾值設多大好呢?

這就很關鍵了,因為閾值的大小會影響TPR和FPR。

閾值對TPR和FPR的影響

假如病患例子的閾值設為0.9,閾值判決后的預測結果如下表。

病號 預測值 真實值 病號 預測值 真實值
1 0 1 11 0 0
2 0 0 12 0 0
3 0 1 13 0 0
4 0 0 14 1 1
5 0 0 15 0 0
6 0 1 16 0 0
7 0 0 17 0 1
8 0 0 18 0 0
9 0 1 19 0 0
10 0 0 20 0 1

可以算出TP=1,TN=13,FP=0,FN=6,那么

\[\begin{aligned} TPR &= \frac{TP}{TP+FN} = \frac{1}{1+6} \approx 0.14 \\ FPR &= \frac{FP}{TN+FP} = 0 \end{aligned} \]

這結果TPR和FPR都很低,FPR低是好事,說明負樣本的預測錯誤率低,但TPR也低就不好了,因為正樣本的預測正確率不高。

那換個閾值再試試,閾值設為0.1,就是全部猜作正例,不列詳細計算過程了,直接給出結果

\[\begin{aligned} TPR &= 1 \\ FPR &= 1 \end{aligned} \]

這結果剛好相反,TPR和FPR都很高,正樣本的預測正確率上來了,負樣本的預測錯誤率也變大了。

通過上面的比較,能看出來:閾值設得越高,TPR和FPR越低;閾值設得越低,TPR和FPR越高。

ROC曲線

上一節我們知道了TPR和FPR會隨閾值變化而變化,你要是把所有閾值對應的TPR和FPR求出來,畫個直角坐標系,以FPR為橫軸,TPR為縱軸,把不同閾值下的(FPR,TPR)坐標點標上並連起來,你就能看到TPR和FPR的整個變化曲線,而這條曲線就稱為ROC(Receiver Operating Characteristic)曲線。

Receiver Operating Characteristic這名字挺奇怪的,可能是因為最早出現在雷達信號檢測領域,用於評價接收器(Receiver)偵測敵機的能力。

嘗試畫出病患事例的ROC曲線,先求不同閾值下的FPR和TPR,置信度從大到小(重復的不算)排列為[0.9, 0.8, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1],一共有8個閾值,如果手算TPR和FPR那太費勁了,幸好sklearn.metrics模塊有現成的roc_curve函數來算,代碼如下:

import pandas as pd
from sklearn.metrics import roc_curve

# 置信度
y_score = [0.8, 0.2, 0.4, 0.1, 0.4, 0.8, 0.3, 0.2, 0.6, 0.5,
           0.8, 0.1, 0.2, 0.9, 0.3, 0.6, 0.8, 0.2, 0.2, 0.4]
# 真實值
y_true = [1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1]

# 計算TPR和FPR
fpr, tpr, thresholds = roc_curve(y_true, y_score)

# 把fpr,tpr,thresholds用DataFrame表格保存,方便顯示
result = pd.DataFrame([thresholds,tpr,fpr], index=
                      ['threshold','TPR','FPR'])
print(result)

結果如下

             0         1         2         3         4         5         6  \
threshold  1.9  0.900000  0.800000  0.600000  0.500000  0.400000  0.300000   
TPR        0.0  0.142857  0.571429  0.714286  0.714286  1.000000  1.000000   
FPR        0.0  0.000000  0.076923  0.153846  0.230769  0.307692  0.461538   

                  7    8  
threshold  0.200000  0.1  
TPR        1.000000  1.0  
FPR        0.846154  1.0

上面結果有兩點需要注意:

  • roc_curve函數結果的第一列沒有什么實際意義,只是畫ROC曲線圖一般都會有原點(0,0),它直接幫用戶給加上了。
  • 關於第一列的threshold為什么是1.9?根據官方API的解釋,它是用max(y_score) + 1算的,為什么要這么算?官方API沒有說明,所以我也不知道這腦洞是怎么來的。

接下來,就是根據FPR和TPR結果畫ROC曲線,畫出來如下圖。

畫圖代碼如下:

import matplotlib.pyplot as plt

plt.figure()
# 畫散點圖,標出點的位置
plt.scatter(fpr, tpr)
# 畫ROC曲線圖
plt.plot(fpr, tpr, color='darkorange', lw=2, label='ROC curve')

plt.xlim([-0.05, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver Operating Characteristic')
plt.legend(loc="lower right")
plt.show()

如果樣本多了之后,畫出來的ROC曲線會平滑得多。

ROC曲線的用處

當你需要評價多個分類模型結果時,ROC曲線能幫你看出這些模型的優劣。

下面給出了A和B兩個分類模型的ROC曲線圖,哪一個模型的結果比較好呢?

很顯然是模型A,為什么呢?

因為模型A的ROC曲線要比模型B的往左上凸,這樣的話,如果固定FPR,模型A的TPR大於模型B;如果固定TPR,模型A的FPR要小於模型B。怎么樣都是模型A比模型B強。

模型C是有特殊意義的,如果拋硬幣來做二分類預測(取任一類的概率是0.5),最后畫出來的ROC曲線圖就跟C很接近。

可以做個實驗:用概率為0.5取0或1來預測真實值,看看算出來的TPR和FPR的結果。

先構造一個1000樣本的真實值列表。

from sklearn.metrics import confusion_matrix
import random

# 構造真實值,正例有100個,負例有900個,用shuffle隨機打亂順序
y_true = [1]*100+[0]*900
random.shuffle(y_true)

用概率為0.5取0或1做預測,並計算TPR和FPR。

import numpy as np
# 隨機生成1000個0和1的預測值
y_pred = np.random.randint(0,2,size=1000)

# 計算TPR和FPR
tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()
print('FPR: %.2f'%(fp/(tn+fp)))
print('TPR: %.2f'%(tp/(tp+fn)))

結果如下

FPR: 0.50
TPR: 0.53

由於預測值是隨機的,每次出來結果會有不同,但基本都圍繞在點(FPR,TRP)=(0.5,0.5)附近,也就是說,按概率為0.5取0或1的方式做預測,勢必經過(0.5,0.5),其ROC曲線就會表現為一條往右上的對角線。

某個模型全面碾壓的情況不太多,大多數情況會如下圖所示,兩個模型的ROC曲線是相交的。

那哪個模型的結果比較好呢?

需要分情況。比如,如果限定FPR要小於相交點,無疑模型A好於模型B。

AUC

如果沒有特定的限制,那怎么選模型呢?有一招,直接算ROC曲線下的面積,稱為AUC(Area Under Curve)。

AUC越大,模型結果越好,下面算算醫患事例的AUC,用sklearn.metrics的roc_auc_score函數。

from sklearn.metrics import roc_auc_score

# 置信度
y_score = [0.8, 0.2, 0.4, 0.1, 0.4, 0.8, 0.3, 0.2, 0.6, 0.5,
           0.8, 0.1, 0.2, 0.9, 0.3, 0.6, 0.8, 0.2, 0.2, 0.4]
# 真實值
y_true = [1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1]

# 計算AUC
auc = roc_auc_score(y_true, y_score)
print('AUC: %.2f'%auc)

結果是

AUC: 0.89

AUC能評價二分類模型結果,其實是有概率解釋的,AUC的概率含義是:隨機從樣本集中取一對正負樣本,正樣本得分(置信度)大於負樣本的概率。實際上可以理解為,模型把正樣本(按照置信度)排在負樣本前面的概率。

具體的解釋參考下面鏈接:

https://tracholar.github.io/machine-learning/2018/01/26/auc.html#auc對正負樣本比例不敏感

精准率和召回率

在信息檢索、Web搜索領域,時常會關心“檢索的信息有多少是用戶感興趣的”“用戶感興趣的信息有多少被檢索出來”,為滿足這樣的評價需求,有了精准率和召回率這兩個指標。

精准率

精准率(Precision)的定義是:預測為正的樣本中猜對的比例。公式如下

\[\text{Precision} = \frac{TP}{TP+FP} \]

這個指標反映的是你預測正樣本預測有多准,關鍵在,因此Precision也被稱為查准率。

召回率

召回率(Recall)的定義是:實際為正的樣本中被猜對的比例。公式如下

\[\text{Recall} = \frac{TP}{TP+FN} \]

看定義,召回率是有點不好理解,舉個例子吧。

假如患病的為正樣本,不患病的為負樣本,100個人里面有10個病患,醫生檢查出了病患中的8個,那這個結果的召回率是多少?

按照定義,先看實際為正的樣本,也就是患病的人,共有10個,這里面醫生猜對的有8個,那么\(\text{Recall} = \frac{8}{10} = 0.8\)。由此可知,召回率關注的是病患(正樣本)是不是都找全了,關鍵在,因此Recall也被稱為查全率。

兩者公式比較

\[\begin{aligned} \text{Precision} &= \frac{TP}{TP+FP} \\ \text{Recall} &= \frac{TP}{TP+FN} \end{aligned} \]

Precision和Recall公式的分子都是TP,這表示兩者都關心有多少猜對的正樣本。

差別在於分母:Precision的是TP+FP,即預測為1(Positive)的樣本;Recall的是TP+FN,即實際為1的樣本(FN表示預測為0但沒猜對,實際是1)。

它們的關注點都是跟1有關的樣本,根本沒有考慮TN(預測為0,實際為0)。

精准率和召回率的關系

還是用那個病患事例(預測值是置信度的情況)說明。

病號 置信度 真實值 病號 置信度 真實值
1 0.8 1 11 0.8 0
2 0.2 0 12 0.1 0
3 0.4 1 13 0.2 0
4 0.1 0 14 0.9 1
5 0.4 0 15 0.3 0
6 0.8 1 16 0.6 0
7 0.3 0 17 0.8 1
8 0.2 0 18 0.2 0
9 0.6 1 19 0.2 0
10 0.5 0 20 0.4 1

和TPR/FPR一樣,需要對置信度卡閾值判定0和1后,才能計算Precision和Recall。

下面先看看閾值的大小對Precision和Recall的影響。

閾值對精准率和召回率的影響

閾值設為0.9,講TPR/FPR的時候算過,為TP=1,TN=13,FP=0,FN=6,那么

\[\begin{aligned} Precision &= \frac{TP}{TP+FP} = \frac{1}{1+0} = 1 \\ Recall &= \frac{TP}{TP+FN} = \frac{1}{1+6} \approx 0.14 \end{aligned} \]

這結果Precision很高,Recall很低,說明猜正樣本猜得很准,預測為正樣本的都猜對了,只是猜得不全,還有好多正樣本沒猜到。

如果閾值為0.1,就是全部猜作正樣本,不列詳細計算過程了,直接給出結果

\[\begin{aligned} Precision &= 0.35 \\ Recall &= 1 \end{aligned} \]

這結果剛好相反,Precision很低,Recall很高,說明正樣本都找全了,就是猜得不怎么准。

通過上面的比較,能看出來閾值對Precision和Recall的影響:

  • 把閾值設得高,預測正樣本的把握確實要大,但會漏掉好多正樣本;

  • 把閾值設得低,正樣本都能找到,但是預測正樣本的准度就不怎么樣了。

舉個現實的例子:

  • 沒有99.99%的概率(閾值設得高)會賺錢就不投資,當然投了基本都賺,但會失去很多賺大錢的機會;
  • 熱點項目不管能不能賺錢(閾值設得低)都投,當然很可能把大魚(如初創的google,facebook)都逮到,但會有好多投資的項目是賠錢的。

P-R曲線

Precision和Recall是一對矛盾體,一方大了另一方就小,隨着閾值的變動此起彼伏。

和ROC曲線一樣,算出不同閾值下的Precision和Recall,以Recall為橫軸,以Precision為縱軸,也可以畫出一條曲線圖,稱為P-R(精確率-召回率)曲線。

嘗試把病患事例的PR曲線圖畫出來,先算不同閾值下的Precision和Recall,調用sklearn.metrics中的precision_score和recall_score函數來算,代碼如下:

# 閾值划分函數
def binary_by_thres(x,t):
    if x >= t:
        return 1
    else:
        return 0

from sklearn.metrics import precision_score,recall_score

# 閾值列表
thresholds = [0.1,0.2,0.3,0.4,0.5,0.6,0.8,0.9]
# 置信度
y_score = [0.8, 0.2, 0.4, 0.1, 0.4, 0.8, 0.3, 0.2, 0.6, 0.5,
           0.8, 0.1, 0.2, 0.9, 0.3, 0.6, 0.8, 0.2, 0.2, 0.4]
# 真實值
y_true = [1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1]

precision = []
recall = []

for t in thresholds:
    # 根據閾值t把預測值划分為0和1
    y_thres = list( map(binary_by_thres, y_score, [t]*len(y_score)) )
    precision.append( precision_score(y_thres, y_true) )
    recall.append( recall_score(y_thres, y_true) )

result = pd.DataFrame([thresholds,precision,recall], index=
                      ['threshold','precision','recall'])
print(result)

結果如下:

              0         1         2         3         4         5         6  \
threshold  0.10  0.200000  0.300000  0.400000  0.500000  0.600000  0.800000   
precision  0.35  0.388889  0.538462  0.636364  0.625000  0.714286  0.800000   
recall     1.00  1.000000  1.000000  1.000000  0.714286  0.714286  0.571429   

                  7  
threshold  0.900000  
precision  1.000000  
recall     0.142857

畫個直角坐標系,以Recall為橫軸,Precision為縱軸,看看不同閾值下的(Recall,Precision)坐標點的P-R曲線變化,畫出的圖如下:

上圖有兩點需要注意:

  • 最后一個(Recall,Precision)坐標點規定是(0,1),跟閾值無關。官方API解釋說是為了畫圖從縱軸開始。

  • 畫圖代碼計算Precision和Recall用的是sklearn.metrics中的precision_recall_curve函數,它的計算結果如下,和之前用precision_score和recall_score函數計算的結果不同,少了閾值為0.1,0.2,0.3的情況。

                      0         1         2         3         4    5
    threshold  0.400000  0.500000  0.600000  0.800000  0.900000  NaN
    precision  0.636364  0.625000  0.714286  0.800000  1.000000  1.0
    recall     1.000000  0.714286  0.714286  0.571429  0.142857  0.0
    

    對這個的解釋:首先這三種情況的Recall都是1,都在Recall=1的直線上,畫階梯圖時考不考慮這三個點對最終的圖沒有影響,所以precision_recall_curve函數就懶得輸出了吧。

畫圖所用代碼如下:

from sklearn.metrics import precision_recall_curve
import matplotlib.pyplot as plt

# 置信度
y_score = [0.8, 0.2, 0.4, 0.1, 0.4, 0.8, 0.3, 0.2, 0.6, 0.5,
           0.8, 0.1, 0.2, 0.9, 0.3, 0.6, 0.8, 0.2, 0.2, 0.4]
# 真實值
y_true = [1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1]

# 計算precision和recall
precision, recall, thresholds = precision_recall_curve(y_true, y_score)

# 規定畫布的大小
plt.figure(figsize=(12,8))

# 畫填充圖
plt.fill_between(recall, precision, alpha=0.2, color='b', step='post')
# 畫散點圖,凸顯坐標點位置
plt.scatter(recall, precision, alpha=0.8, color='r')

plt.xlabel('Recall')
plt.ylabel('Precision')
plt.ylim([0.0, 1.05])
plt.xlim([0.0, 1.05])
plt.show()

如果樣本多了之后,畫出來的P-R曲線會平滑得多。

P-R曲線的用處

和ROC曲線一樣,P-R曲線能評價多個模型結果的優劣。

下面給出了兩個分類模型的P-R曲線圖,哪一個模型的結果比較好呢?

顯然是紫色的模型B,為什么呢?

因為模型B的PR曲線要比模型A的往右上凸。

如果固定Recall,模型B的Precision大於模型A;如果固定Precision,模型B的Recall還是大於模型A。怎么樣都是模型B比模型A強。

當然,絕大多數情況如下圖所示,兩個模型的PR曲線是相交的。

那哪個模型的結果比較好呢?跟ROC曲線一樣,需要分情況討論。

如,Recall大於交點時,模型A比模型C好。

實際工作中,如果是做搜索,在保證召回率的情況下要盡量提升准確率,那就更願意選模型A;如果做疾病監測、反垃圾郵件等,則是保精確率的條件下提升召回率,那更更傾向於選模型C。

那P-R曲線有沒有像ROC曲線中的AUC那樣的評價指標呢?

有的,P-R曲線下的面積其實是AP(Average Precision)。

AP

原始計算方式

AP(Average Precision)英文的意思就是平均精准度,為什么P-R曲線下的面積就是平均精准度呢?

先來看P-R曲線下面積的計算公式

\[\sum_{t} P(t) \Delta R(t) \]

其中,\(t\)是閾值,\(P(t)\)是對應閾值\(t\)的Precision,\(R(t)\)是對應閾值\(t\)的Recall,\(\Delta R(t)=R(t)-R(t-1)\)

把公式變一下形式

\[\sum_{t} \Delta R(t) P(t) \]

而且\(\sum_t \Delta R(t) = 1\)

上面公式就是加權平均值的計算形式,每個\(P(t)\)對應的權值是Recall的變化量\(\Delta R(t)\)

根據上面的說明,我們可以求病患事例的AP,先列出之前算出的threshold,precision,recall。

                  0         1         2         3         4    5
threshold  0.400000  0.500000  0.600000  0.800000  0.900000  NaN
precision  0.636364  0.625000  0.714286  0.800000  1.000000  1.0
recall     1.000000  0.714286  0.714286  0.571429  0.142857  0.0

\[\begin{aligned} AP =& 1.0 \times (0.142857 - 0.0) + 0.8 \times (0.571429 - 0.142857) + 0.714286 \times (0.714286 - 0.571429) \\ &+ 0.625 \times (0.714286 - 0.714286) + 0.636364 \times (1-0.714286) \\ =& 0.769573 \end{aligned} \]

用代碼來驗證一下結果:

from sklearn.metrics import average_precision_score

# 置信度
y_score = [0.8, 0.2, 0.4, 0.1, 0.4, 0.8, 0.3, 0.2, 0.6, 0.5,
           0.8, 0.1, 0.2, 0.9, 0.3, 0.6, 0.8, 0.2, 0.2, 0.4]
# 真實值
y_true = [1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1]

# 計算average precision
ap = average_precision_score(y_true, y_score)
print('Average Precision:%.6f' % ap)

輸出為

Average Precision:0.769573

其他計算方式

實際上,原始的AP計算方式用的不多,常用的是PASCAL VOC CHALLENGE的計算方法,它有兩種計算方式:

  • 11-point Interpolated Average Precision

    給Recall設定一組閾值,[0, 0.1, 0.2, … , 1],對於Recall大於等於每一個閾值,都有一個對應的最大precision,這樣我們就計算出了11個precision,11-point Interpolated Average Precision即為這11個precision的平均值。

    還是算算病患事例的11-point Interpolated Average Precision吧。

    之前通過precision_score和recall_score算得的病患事例Precision和Recall如下:

                  0         1         2         3         4         5         6  \
    threshold  0.10  0.200000  0.300000  0.400000  0.500000  0.600000  0.800000   
    precision  0.35  0.388889  0.538462  0.636364  0.625000  0.714286  0.800000   
    recall     1.00  1.000000  1.000000  1.000000  0.714286  0.714286  0.571429   
    
                      7  
    threshold  0.900000  
    precision  1.000000  
    recall     0.142857
    

    先算閾值0的情況。

    按照定義,Recall大於等於閾值0對應的Precision都算,有哪些呢?全部。然后從中挑選一個最大的,那肯定就是1了。

    這就算完了閾值為0的情況,其他的閾值也是依葫蘆畫瓢,不詳細去算了,直接給吧。

    Recall大於等於的閾值 最大Precision
    0 1
    0.1 1
    0.2 0.8
    0.3 0.8
    0.4 0.8
    0.5 0.8
    0.6 0.714286
    0.7 0.714286
    0.8 0.636364
    0.9 0.636364
    1 0.636364

    把上面11個最大Precision求平均,就得到11-point Interpolated Average Precision,為0.776151。

  • PASCAL VOC CHALLENGE 2010版計算方法

    PASCAL VOC CHALLENGE自2010年后就換了另一種計算方法,跟11-point Interpolated Average Precision的區別不是特別大,差異在於給Recall設定閾值改為\([\frac{1}{M},\frac{2}{M},\cdots,\frac{M-1}{M},1]\),M為正樣本的個數。

    老規矩,拿病患事例來說明,病患事例數據有7個正樣本,M=7。

    那閾值就確定了,為\([\frac{1}{7},\frac{2}{7},\cdots,\frac{6}{7},1]\)

    跟11-point Interpolated Average Precision一樣算閾值的最大Precision,結果如下:

    Recall大於等於的閾值 最大Precision
    \(\frac{1}{7}\) 1
    \(\frac{2}{7}\) 1
    \(\frac{3}{7}\) 1
    \(\frac{4}{7}\) 0.8
    \(\frac{5}{7}\) 0.714286
    \(\frac{6}{7}\) 0.636364
    1 0.636364

    對最大Precision求平均,得0.826716。

AP的參考鏈接:

https://www.bbsmax.com/A/MAzAOw159p/

http://blog.sina.com.cn/s/blog_9db078090102whzw.html

F1分數

如果Precision和Recall兩個指標都要求高,可以用F1分數來評價模型。

F1分數(F1 score)的計算公式

\[F1 = \frac{2(Precision*Recall)}{Precision+Recall} \]

F1分數采用的是調和平均數(Harmonic Average)。

什么是調和平均數?其實就是倒數的平均數,看下面公式

\[\frac{1}{y} = \frac{1}{N}(\frac{1}{x_1} + \frac{1}{x_2} + \cdots +\frac{1}{x_N}) \]

F1分數公式變換一下形式就能看出來是調和平均數

\[\begin{aligned} & F1 = \frac{2(Precision*Recall)}{Precision+Recall} \\ \Rightarrow \quad& \frac{1}{F1} = \frac{1}{2} (\frac{1}{Precision}+\frac{1}{Recall}) \end{aligned} \]

那為什么要用調和平均數?直接求算術平均數不行嗎?

那我們舉個極端的例子,\(Precision=0,Recall=1\),現實中絕對不會出現這種情況,這只是為了凸顯算術平均數和調和平均數之間的差異。

那么有

\[算術平均值:Mean = \frac{1}{2}(Precision+Recall)=0.5 \]

\[調和平均值:\frac{1}{F1} = \frac{1}{2} (\frac{1}{Precision}+\frac{1}{Recall}) = +\infin \Rightarrow F1=0 \]

這說明:調和平均比算術平均更關注值較小的數,就像馬雲的財富和你的財富算術平均一下,你也是億萬富翁,如果是用調和平均,那馬雲的財富水平也會和你的相當。

所以,F1分數如果比較大,那\(Precision\)\(Recall\)都不會小,這樣就能平衡地看待兩者。

計算病患例子的F1分數,代碼如下:

# 閾值划分函數
def binary_by_thres(x,t):
    if x >= t:
        return 1
    else:
        return 0

import pandas as pd
from sklearn.metrics import f1_score

# 閾值列表
thresholds = [0.1,0.2,0.3,0.4,0.5,0.6,0.8,0.9]
# 置信度
y_score = [0.8, 0.2, 0.4, 0.1, 0.4, 0.8, 0.3, 0.2, 0.6, 0.5,
           0.8, 0.1, 0.2, 0.9, 0.3, 0.6, 0.8, 0.2, 0.2, 0.4]
# 真實值
y_true = [1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1]

fscore = []

for t in thresholds:
    # 根據閾值t把預測值划分為0和1
    y_thres = list( map(binary_by_thres, y_score, [t]*len(y_score)) )
    # 計算F1分數
    fscore.append( f1_score(y_true, y_thres) )

result = pd.DataFrame([thresholds,fscore], index=['threshold','f1_score'])
print(result)

輸出為

                  0     1    2         3         4         5         6     7
threshold  0.100000  0.20  0.3  0.400000  0.500000  0.600000  0.800000  0.90
f1_score   0.518519  0.56  0.7  0.777778  0.666667  0.714286  0.666667  0.25

根據均值不等式(高中知識):\(\frac{2}{\frac{1}{a}+\frac{1}{b}} \le \sqrt{ab}\),當且僅當\(a=b\)時取等號。

那么,\(F1 = \frac{2}{\frac{1}{Precision}+\frac{1}{Recall}} \le \sqrt{Precision \cdot Recall}\),當且僅當\(Precision = Recall\)取等號。

所以,只有當\(Precision = Recall\)時F1分數取最大值。

在PR曲線圖中,往右上的對角線與PR曲線的交點就是F1分數的最大點。

Matthews相關系數

Matthews相關性系數(Matthews Correlation Coefficient, MCC)跟之前的指標關系不大,所以放最后講。

它的公式如下

\[MCC= \frac{TP \cdot TN - FP \cdot FN}{\sqrt{(TP + FP)(TP + FN)(TN + FP)(TN + FN)}} \]

乍看起來讓人有點蒙,不知道怎么來的,下面我就來解釋一下。

Matthews相關系數既然叫相關系數,我們第一聯想到的會是什么呢?

就是概率論里面學的Pearson相關系數,先回歸一下Pearson相關系數的知識。

Pearson相關系數計算公式如下:

\[\rho = \frac{E\{[X-E(X)][Y-E(Y)]\}}{\sqrt{Var(X)Var(Y)}} = \frac{E(XY)-E(X)E(Y)}{\sqrt{Var(X)Var(Y)}} \]

其中,\(X\)\(Y\)是兩個變量,\(E(\cdot)\)\(Var(\cdot)\)分別代表均值和方差。

Pearson相關系數的用處在於衡量\(X\)\(Y\)之間的線性關系,取值范圍是[-1,1]。

  • \(\rho\)越接近1,越正相關,\(X\)\(Y\)越趨近於同向變化;
  • \(\rho\)越接近-1,越負相關,\(X\)\(Y\)越趨近於反向變化;
  • \(\rho\)越接近0,相關性越弱,\(X\)\(Y\)之間的線性關系越小。

那Pearson相關系數和Matthews相關系數之間有什么關系呢?

其實Matthews相關系數就是特殊的Pearson相關系數,Matthews相關系數針對的是\(X\)\(Y\)都是0-1分布的情況。

在實際中,只知道\(X\)\(Y\)的樣本,只能通過樣本來求均值和方差。

現在假定\(X\)是二分類的預測值,\(Y\)是二分類的真實值,兩者的取值都是0和1。

先復習一下樣本均值和樣本方差的知識。

\(X_1,X_2,\cdots,X_N\)是來自總體\(X\)的一個樣本,\(x_1,x_2,\cdots,x_N\)是對應的觀察值。

樣本均值的觀察值計算公式:

\[\bar{x} = \frac{1}{N} \sum_{i=1}^N x_i \]

樣本方差的觀察值計算公式:

\[s^2 = \frac{1}{N} (\sum_{i=1}^N x_i^2 - N\bar{x}^2) \]

概率論的書上計算樣本方差時除以的是\(N-1\),從無偏性來考慮書上確實是對的,但實際應用中\(N\)都比較大,所以常常直接除以\(N\),其實對結果影響不大。

對於符合0-1分布的樣本X,假設樣本觀察值取1的數量為\(N_1\),樣本總量為\(N\)

那么X的樣本均值和樣本方差的觀察值分別是

\[\bar{x} = \frac{N_1}{N} \]

\[s^2 = \frac{1}{N} (\sum_{i=1}^N x_i^2 - N\bar{x}^2) = \frac{1}{N} [N_1 - N(\frac{N_1}{N})^2] = \frac{N_1}{N} (1-\frac{N_1}{N}) \]

\(X\)\(Y\)有關的樣本均值和樣本方差如下

\[E(X) = \frac{TP+FP}{N}, \quad (TP+FP)是X=1的樣本數 \\ E(Y) = \frac{TP+FN}{N}, \quad (TP+FN)是Y=1的樣本數 \\ E(XY) = \frac{TP}{N}, \quad TP是XY=1的樣本數 \\ Var(X) = \frac{TP+FP}{N}(1-\frac{TP+FP}{N}) = \frac{TP+FP}{N} \cdot \frac{TN+FN}{N} \\ Var(Y) = \frac{TP+FN}{N}(1-\frac{TP+FN}{N}) = \frac{TP+FN}{N} \cdot \frac{TN+FP}{N} \]

其中\(N=TP+FP+TN+FN\)

把這些結果代入Pearson相關系數

\[MCC = \frac{E(XY) - E(X)E(Y)}{\sqrt{Var(X)Var(Y)}} = \frac{\frac{TP}{N} - \frac{TP+FP}{N} \cdot \frac{TP+FN}{N}}{\sqrt{\frac{TP+FP}{N} \cdot \frac{TN+FN}{N} \cdot\frac{TP+FN}{N} \cdot \frac{TN+FP}{N}}} \\ = \frac{TP \cdot N - (TP+FP)(TP+FN)}{\sqrt{(TP+FP)(TN+FN)(TP+FN)(TN+FP)}} \\ = \frac{TP(TP+FP+TN+FN) - (TP+FP)(TP+FN)}{\sqrt{(TP+FP)(TN+FN)(TP+FN)(TN+FP)}} \\ = \frac{TP \cdot TN - FP \cdot FN}{\sqrt{(TP+FP)(TN+FN)(TP+FN)(TN+FP)}} \]

這就推出了Matthews相關系數。

從Pearson相關系數的含義可以很方便地去理解Matthews相關系數的意義:

Matthews相關系數的作用是衡量都服從0-1分布的\(X\)\(Y\)的線性關系。

  • \(MCC=1\),表示\(X\)預測是1,真實值\(Y\)確實是1,\(X\)預測是0,真實值\(Y\)也確實是0,兩者同向變化,說明預測全是對的;
  • \(MCC=-1\),表示\(X\)預測是1,真實值\(Y\)卻是0,\(X\)預測是0,真實值\(Y\)卻是1,兩者反向變化,說明預測全是錯的;
  • \(MCC=0\),表示\(X\)\(Y\)沒有線性關系,預測有時候是對的,有時候是錯的,而且對的和錯的一樣多,相當於你拋硬幣瞎猜。

計算Matthews相關系數可以調用sklearn.metrics的matthews_corrcoef函數,代碼如下:

from sklearn.metrics import matthews_corrcoef

# 真實值
y_true = [1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1]
# 預測值
y_pred = [1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0]

# 計算Matthews相關系數
mc = matthews_corrcoef(y_true, y_pred)
print('Matthews Correlation Coefficient: %.2f' % mc)

結果為

Matthews Correlation Coefficient: 0.66

對Matthews相關系數的理解啟發於https://stats.stackexchange.com/questions/59343/relationship-between-the-phi-matthews-and-pearson-correlation-coefficients


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM