MaDi's Blog

一個紀錄自己在轉職軟體工程師路上的學習小空間

0%

機器學習-常見的評估指標

用機器學習去做分類問題的時候,會需要透過一些統計指標去輔助,才能正確地檢驗分類的結果,並快速地修正問題,達到更好的分類結果。近期案子上剛好在處理分類的問題,就順手把一些學過的評估指標做個整理,並搭配網站上的資源記錄成簡短的心得以供未來的自己參考。

1. 二分類模型的評估指標

混淆矩陣 Confusion Matrix

分類的結果可以用以下矩陣來表示,分為四種象限:

1
2
3
4
1. True Positive (TP): 實際上是正樣本且被預測為正樣本
2. False Positive (FP): 實際上是負樣本但被誤判為正樣本
3. False Negative (FN): 實際上是正樣本但被誤判為負樣本
4. True Negative (TN): 實際上是負樣本且被預測為負樣本

1, 4點是我們希望的結果,2, 3點則是誤判的結果。

簡單理解:

第一個 True/False 代表預測是否正確

第二個Positive/Negative則是代表預測的結果(答成哪一類)


圖片來源

準確度(Accuracy)

1
準確度(Accuracy) = (TP+TN)/(TP+FP+FN+TN)

準確度是最常用的指標,但在某些情況下會失效

例如: 某類數量佔很多的時候,直接把該類分到一邊,準確度就會大幅提高,但其實根本沒分到類,最常見的例子就是信用卡盜刷

準確度背後的意思是指,整體模型表現裡正確分類的比例是多少

精確度(Precision)與召回率(Recall)

從混淆矩陣繼續延伸可以得到以下兩個指標:

1
精確度(Precision) = TP/(TP+FP)

所有被預測為正確的樣本中,有多少比例是實際正確的。

1
召回率(Recall) = TP/(TP+FN)

所有實際正確的樣本中,有多少比例是被預測為正確的。

這兩個指標都只關注在實際的正樣本,不考慮TN的結果,因為通常TN會是答對的Null Hypothesis,白話而言就是無聊的正確結果。

總結,精確度希望模型能夠預測更準,召回率則是希望正確的樣本都能夠被判斷(偵測)出來。

在不同的情境下,precision和recall的使用時機就不同,端看關注的問題是屬於哪一面。

F1-Score

大多數情況下,我們不會偏廢precision或recall,而是希望兩者分配合理的權重,為了綜合考量precision與recall,所以產生了這個F1-Score的指標。


圖片來源

因為F1-Score的公式中,是固定TP,有不同的分母,符合調和數列的型態,所以公式型態也是採用調和平均。整理之後可得F1-Score長這樣:

F1-Score的值落在0~1之間。

而precision與recall之間的權重也可以透過一個beta值來調整,這就是F1 Measure。F1-Score只是F1 Measure的特例。

當beta=1就是F1-Score,代表precision與recall同等重要。

當beta=0就是precision,反之,當beta趨近於無限大,就是Recall

所以如果希望多看一點precision,就把beta調小一點,如果希望多看一點recall,就把beta調大一點。

ROC 曲線

ROC需要三個元素:

  1. TPR(Sensitivity) = TP/(TP+FN),等同recall
  2. FPR(Specificity) = FP/(FP+TN),所有負樣本被誤判為正樣比的比例
  3. 閥值


圖片來源

二分類的模型中,會設定一個閥值(threshold),當預測的結果大於此閥值,就被認定為正樣本,反之為負樣本。

透過不同的閥值、TPR與FPR,就可以畫出ROC曲線圖,底下的面積就是AUC,AUC愈大愈好。


圖片來源

2. 多分類模型的評估指標

跟二元分類一樣會有多元分類的混淆矩陣。

有三種指標可以觀察:

  1. 整體正確率or錯誤率
  2. 單一類別的正確率or錯誤率
  3. Cohen’s kappa coefficient (Kappa)

Cohen’s kappa coefficient (Kappa)

用來平衡類別之間正確性的一種指標,把數量極大的某個類別消除掉的指標

白話來說,就是避免當單一類別的數量超大的時候,直接把分類的結果分為該類就會達到很高的正確率。

Kappa計算方式:

p0就是百分比混淆矩陣的對角線元素相加。

pc就是把把每類別做加總。(實際第i類別的總和乘上預測第i類別的總和)

舉例來說:

Kappa的值介於-1~1之間,值正的愈大,模型愈好。

3. 總結


圖片來源

4. 程式碼

[Confusion Matrix]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 基本
import pandas as pd

#繪圖
import seaborn as sns
import matplotlib.pyplot as plt

#混淆矩陣
from sklearn.metrics import confusion_matrix

# 建立分類的編號
data = {0:'政黑版', 1:'土木版', 2:'八卦版', 3:'表特版'}

# 假設分類後的結果長這樣
y_true = [1,1,0,3,2,2]
y_pred = [0,1,1,3,3,2]

# 計算混淆矩陣
lbl = list(data.keys())
arr = confusion_matrix(y_true, y_pred, labels=lbl)

# 繪熱圖
df_cm = pd.DataFrame(arr, index = [i for i in lbl], columns = [i for i in lbl])
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei'] # 顯示中文
plt.figure(figsize = (8,5))

sns.heatmap(df_cm, annot=True, cmap="YlGnBu");

plt.ylabel('y_true')
plt.xlabel('y_pred');
plt.tight_layout()

arr

[[0, 1, 0, 0],
[1, 1, 0, 0],
[0, 0, 1, 1],
[0, 0, 0, 1]]

熱圖:

[Accuracy]

1
2
3
4
5
6
7
from sklearn.metrics import accuracy_score

# 答對的比例(0~1)
accuracy_score(y_true, y_pred) # 0.5

# 答對幾個(0~樣本數量)
accuracy_score(y_true, y_pred, normalize=False) #3

[Precision/Recall/F1-Score]

這裡Precision, Recall, F1-Score在python程式碼中有一個參數average可以自由調整,有None,binary,micro, macro, weighted五種可以選擇,預設是binary,但是binary是專屬於二分類使用,而micro, macro, weighted 則是適用於多分類。 None則兩種時機皆可使用,它會回傳每個類別的指標。

在多分類的時候需要特別了解micro,macro,weighted這三種概念才能知道在什麼情境下使用:

  1. micro: 讓所有類別的每個樣本都具有相同的權重,把所有樣本合在一起來計算指標
  2. macro: 讓每個類別具有相同的權重,用算術平均數去計算每個類別的指標。
  3. weighted: 由各類別的數量去計算加權值,解決macro可能遇到的label數量不平衡的問題。

舉前一個例子來說,各個ptt版的預測分類可以由混淆矩陣得到下表:

TP FP FN
0 政黑板 0 1 1
1 土木板 1 1 1
2 八卦板 1 0 1
3 表特板 1 1 0

此處以計算Precision為例,先計算各類別的Precision:

Precision = TP/(TP+FP)

P0 = 0/(0+1) = 0
P1 = 1/(1+1) = 0.5
P2 = 1/(1+0) = 1
P3 = 1/(1+1) = 0.5

這其實就是None會回傳的值。

  • 計算 micro precision:

    把所有樣本考慮在一起來計算,所以回頭看 y_true, y_pred 的資料

    y_true = [1,1,0,3,2,2]
    y_pred = [0,1,1,3,3,2]

    全部樣本中有答對的有3筆,剩下3筆是沒答對的,所以 micro precision = 3/(3+3) = 0.5

  • 計算 macro precision:

    用算術平均數來計算,所以 macro precision = (P0+P1+P2+P3)/4 = 0.5

  • 計算 weighted precision:

    先計算每個類別佔所有樣本中的比例,再分別加權計算,所以 weighted precision = (1/6)xP0 + (1/3)xP1 + (1/3)xP2 + (1/6)xP3 = 0.5833

    同理,Recall, F1-Score也可以這樣計算

    最後,整理一下micro, macro這兩個指標帶給我們的資訊:

    當各類別數量相差甚大的時候:

    1. 想要讓weight集中偏向於樣本數量大者,用micro
    2. 想要讓weight集中偏向於樣本數量小者,用macro

    同樣地,我們可以透過這兩個指標回頭檢查類別

    1. micro<<macro,回頭檢查樣本數量大的類別
    2. macro<<micro,回頭檢查樣本數量小的類別

以下是程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score
from sklearn.metrics import classification_report # 全部指標的report

# 精確度(Precision)
precision_score(y_true, y_pred, average=None) # [0, 0.5, 1, 0.5]
precision_score(y_true, y_pred, average='micro') # 0.5
precision_score(y_true, y_pred, average='macro') # 0.5
precision_score(y_true, y_pred, average='weighted') # 0.58333

# 召回率(Recall)
recall_score(y_true, y_pred, average=None) # [0, 0.5, 0.5, 1]
recall_score(y_true, y_pred, average='micro') # 0.5
recall_score(y_true, y_pred, average='macro') # 0.5
recall_score(y_true, y_pred, average='weighted') # 0.5

# F1-Score
f1_score(y_true, y_pred, average=None) # [0, 0.5, 0.6667, 0.6667]
f1_score(y_true, y_pred, average='micro') # 0.5
f1_score(y_true, y_pred, average='macro') # 0.45833
f1_score(y_true, y_pred, average='weighted') # 0.4999

# 綜合指標的report
print(classification_report(y_true,y_pred))

參考