Skip to the content.

接下來介紹幾個常用來處理分類問題的指標

Accuracy Score 準確度

不免俗的先來個數學阿宅的公式

\[accuracy(y,\hat{y}) = \frac{1}{n} \sum_{i=1}^n 1(y_i = \hat{y_i})\]

其中的 $1( \cdot )$ 是 indicator function。

下面進入實戰環節。

from sklearn.metrics import accuracy_score
y_pred = [0, 2, 1, 3]
y_true = [0, 1, 2, 3]
display(accuracy_score(y_true, y_pred))

accuracy_score(y_true, y_pred, normalize=False)

Top-k accuracy score 前 k 高準確度

正確的答案,只要預測結果在前 k 高的答案裡面就算你對,可以想成給你猜 k 次,只要猜對一次就算你答對。

為了滿足數學阿宅的快樂,我們來定義新的符號 $\hat{y}{i,j}$ 是 預測 第 $i$ 個樣本(sample)的 第 $j$ 高分數的預測,特別的來說 $\hat{y}{i,1} = \hat{y}_i$, 下面我們就可以給公式。

\[top-k \quad accuracy(y, \hat{y}) = \frac{1}{n} \sum_{i=1}^n \sum_{j=1}^k 1(y_i = \hat{y}_{i,j})\]

下面進入實戰。

import numpy as np
from sklearn.metrics import top_k_accuracy_score
y_true  = np.array([0, 1, 2, 2])
y_score = np.array([[0.5, 0.2, 0.2],
                    [0.3, 0.4, 0.2],
                    [0.2, 0.4, 0.3],
                    [0.7, 0.2, 0.1]])
display(top_k_accuracy_score(y_true, y_score, k=2))

top_k_accuracy_score(y_true, y_score, k=2, normalize=False)

Balanced accuracy score 平衡的準確度

我們前面談的預測都是在資料很平衡的情況下,那如果資料很不平衡的情況下又會如何?下面舉幾個極端例子來感受一下。

假設你要預測的事件,是去判斷起床後看見的人是外星人嗎?那你大概會無腦的見人就猜他是人嗎?因為幾乎全部見到的都是人,你當然也都猜對了,雖然看上去你的預測超準,但其實你根本沒學會到底要如何去判斷是不是外星人,只是一直在瞎猜罷了,如果你今天到了 MIB 的總部,你預測的準確度恐怕就會變得奇差無比。

那在哪些狀況下可能會碰到不平衡的問題:

如果你還在用之前提到的指標準確度,那你可能會搞不清預測結果的正確性,因為其實你訓練半天的模型啥都沒學會,下面進入實戰。

from sklearn.metrics import balanced_accuracy_score, accuracy_score

y_true = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
y_pred = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
print('準確度: ', accuracy_score(y_true, y_pred), '平衡的準確度: ', balanced_accuracy_score(y_true, y_pred))

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

# 1/3 + 1/3 + 5/6*1/3
balanced_accuracy_score(y_true, y_pred)

1/3 + 1/3 + 5/6*1/3
??balanced_accuracy_score

Cohen’s kappa

這是一種觀察指標,評價 兩個觀察員 的觀察 是否一致的指標,Cohen’s kappa 的值介於 $-1$ 到 $1$ 之間,只要大於 $0.8$ 就會被認定為觀察一致,小於 $0$ 會被認為不一致,下面進入實戰。

他的公式是

\[\frac{p_o - p_e}{1 - p_e}\]
from sklearn.metrics import cohen_kappa_score

y_1 = [2, 1, 0, 2, 2, 0, 0, 1]
y_2 = [0, 2, 0, 2, 2, 0, 0, 1]

cohen_kappa_score(y_1, y_2)

cohen_kappa_score(y_2, y_1)
??cohen_kappa_score

Accuracy 準確率、 Precision 精確率、 Recall 召回率、 F-score

為了要解釋這些概念,我們來個二分類的看病問題例子,

真實 \ 預測 有病positive 沒病 (negative)
有病 TP (true positive
判斷是對的 有病
FN (false negative)
判斷是錯的 沒病
沒病 FP (false positive
判斷是錯的 有病
TN (true negative)
判斷是對的 沒有病

在統計上我們有一些其他的稱呼,

FP (false positive) : 偽陽,型一錯誤

FN (false negative) : 偽陰,型二錯誤

我們下面用這些新概念來解釋

Accuracy 準確率

\[Accuracy = \frac{TP+TN}{TP+FN+FP+TN}\]

Precision 精確率

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

Recall 召回率

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

有的時候在不同任務我們會在乎 Precision,有的時候會更在乎 Recall,那如果都在乎怎麼辦。

F-score

\[f = 1 / \Big (\frac{\frac{1}{Precision} + \frac{1}{Recall}}{2} \Big) = \frac{2*Recall*Precision}{Recall+Precision}\]

如果我們是有偏好的在乎

F-beta score

\[f_{\beta} = \frac{(1+\beta^2)*Recall*Precision}{Recall + \beta^2 * Precision}\]

其中 $\beta^2 = \frac{R_w}{P_w}, R_w + P_w = 1$

上面的公式可以由下面導出來。

\[\frac{1}{f_{\beta}} = \frac{P_w}{Precision} + \frac{R_w}{Recall}\]

一般的 $F-score$ 是取 $P_w = R_w = 0.5$。

下面進入實戰。

from sklearn.metrics import precision_score, recall_score, f1_score, fbeta_score
y_true = [0, 1, 2, 2, 0]
y_pred = [0, 0, 2, 1, 0]

print('precision:')
display(precision_score(y_true, y_pred, average='macro'))
# if imbalance
display(precision_score(y_true, y_pred, average='micro'))

display(precision_score(y_true, y_pred, average='weighted'))

print('recall:')
display(recall_score(y_true, y_pred, average='macro'))
# if imbalance
display(recall_score(y_true, y_pred, average='micro'))
display(recall_score(y_true, y_pred, average='weighted'))

print('f1:')
display(f1_score(y_true, y_pred, average='macro'))
# if imbalance
display(f1_score(y_true, y_pred, average='micro'))
display(f1_score(y_true, y_pred, average='weighted'))

print('f beta:')
display(fbeta_score(y_true, y_pred, average='macro', beta=0.7))
# if imbalance
display(fbeta_score(y_true, y_pred, average='micro', beta=0.7))
display(fbeta_score(y_true, y_pred, average='weighted', beta=0.7))

# 一次算每個類別 precision, recall, f_score
import numpy as np
from sklearn.metrics import precision_recall_fscore_support
y_true = np.array(['cat', 'dog', 'pig', 'cat', 'dog', 'pig'])
y_pred = np.array(['cat', 'pig', 'dog', 'cat', 'cat', 'dog'])

display(precision_recall_fscore_support(y_true, y_pred, average='macro'))

display(precision_recall_fscore_support(y_true, y_pred, average='micro'))

Confusion Matrix

如果我們想要一次比較多個類別,就需要 Confusion Matrix 。

import numpy as np
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
import matplotlib.pyplot as plt
%matplotlib inline

plt.rcParams['figure.figsize'] = [10, 10]

# y_true = np.array(['cat', 'dog', 'pig', 'cat', 'dog', 'pig'])
# y_pred = np.array(['cat', 'pig', 'dog', 'cat', 'cat', 'dog'])
y_true = np.array([0, 1, 2, 0, 1, 2])
y_pred = np.array([0, 2, 1, 0, 0, 1])
target_names = ['cat', 'dog', 'pig']

cm = confusion_matrix(y_true, y_pred)

display(cm)

disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=target_names)
disp.plot()
plt.show()


Classification Report

也可以直接讓 scikit learn 做報告。

from sklearn.metrics import classification_report
y_true = [0, 1, 2, 2, 0]
y_pred = [0, 0, 2, 1, 0]
target_names = ['cat', 'dog', 'pig']

print(classification_report(y_true, y_pred, target_names=target_names))

這邊要特別說明一下 Macro Average 跟 Weighted Average。

Macro Average

他就是每一類的平均,以上面的 precision 為例

\[\frac{0.67+0+1}{3} \sim 0.56\]

Weighted Average

他就是每一類的加權平均,以上面的 precision 為例

\[\frac{2}{5} * 0.67 + \frac{1}{5} * 0 + \frac{2}{5} * 1 \sim 0.67\]

Micro Average

報表裡面沒有但是我們還是要提一下,他就是不考慮類別直接計算全部類別。 以上面的 precision 為例

0 類

1 類

2 類

所以

\[Micro-precision = \frac{2+0+1}{(2+0+1) + (1+1+0)}\]