Các phương pháp đánh giá một mô hình phân lớp dữ liệu
1. Giới thiệu
y_pred
– là vector dự đoán đầu ra với mỗi phần tử là class được dự đoán của một điểm dữ liệu trong tập kiểm thử. Ta cần so sánh giữa vector dự đoán y_pred
này với vector class thật của dữ liệu, được mô tả bởi vector y_true
.0, 1, 2
. Trong bài toán thực tế, các class có thể có nhãn bất kỳ, không nhất thiết là số, và không nhất thiết bắt đầu từ 0
. Chúng ta hãy tạm giả sử các class được đánh số từ 0
đến C-1
trong trường hợp có C
lớp dữ liệu. Có 10 điểm dữ liệu trong tập kiểm thử với các nhãn thực sự được mô tả bởi y_true = [0, 0, 0, 0, 1, 1, 1, 2, 2, 2]
. Giả sử bộ phân lớp chúng ta đang cần đánh giá dự đoán nhãn cho các điểm này là y_pred = [0, 1, 0, 2, 1, 1, 0, 2, 1, 2]
.2. Accuracy
from __future__ import print_function
import numpy as np
def acc(y_true, y_pred):
correct = np.sum(y_true == y_pred)
return float(correct)/y_true.shape[0]
y_true = np.array([0, 0, 0, 0, 1, 1, 1, 2, 2, 2])
y_pred = np.array([0, 1, 0, 2, 1, 1, 0, 2, 1, 2])
print('accuracy = ', acc(y_true, y_pred))
accuracy = 0.6
from sklearn.metrics import accuracy_score
print('accuracy = ',accuracy_score(y_true, y_pred))
accuracy = 0.6
3. Confusion matrix
Total: 10 | Predicted | Predicted | Predicted |
| as: 0 | as: 1 | as: 2 |
-----------|-----------|-----------|-----------|---
True: 0 | 2 | 1 | 1 | 4
-----------|-----------|-----------|-----------|---
True: 1 | 1 | 2 | 0 | 3
-----------|-----------|-----------|-----------|---
True: 2 | 0 | 1 | 2 | 3
-----------|-----------|-----------|-----------|---
i
, cột thứ j
là số lượng điểm lẽ ra thuộc vào class i
nhưng lại được dự đoán là thuộc vào class j
. Như vậy, nhìn vào hàng thứ nhất (0
), ta có thể thấy được rằng trong số bốn điểm thực sự thuộc lớp 0
, chỉ có hai điểm được phân loại đúng, hai điểm còn lại bị phân loại nhầm vào lớp 1
và lớp 2
.i
, hàng thứ j
là số lượng điểm lẽ ra thuộc vào class i
nhưng lại được dự đoán là thuộc vào class j
. Khi đó ta sẽ được confusion matrix là ma trận chuyển vị của confusion matrix như cách tôi đang làm. Tôi chọn cách này vì đây chính là cách thư viện sklearn sử dụng.def my_confusion_matrix(y_true, y_pred):
N = np.unique(y_true).shape[0] # number of classes
cm = np.zeros((N, N))
for n in range(y_true.shape[0]):
cm[y_true[n], y_pred[n]] += 1
return cm
cnf_matrix = my_confusion_matrix(y_true, y_pred)
print('Confusion matrix:')
print(cnf_matrix)
print('nAccuracy:', np.diagonal(cnf_matrix).sum()/cnf_matrix.sum())
Confusion matrix:
[[ 2. 1. 1.]
[ 1. 2. 0.]
[ 0. 1. 2.]]
Accuracy: 0.6
normalized_confusion_matrix = cnf_matrix/cnf_matrix.sum(axis = 1, keepdims = True)
print('nConfusion matrix (with normalizatrion:)')
print(normalized_confusion_matrix)
Confusion matrix (with normalizatrion:)
[[ 0.5 0.25 0.25 ]
[ 0.33333333 0.66666667 0. ]
[ 0. 0.33333333 0.66666667]]
from sklearn.metrics import confusion_matrix
cnf_matrix = confusion_matrix(y_true, y_pred)
print('Confusion matrix:')
print(cnf_matrix)
Confusion matrix:
[[2 1 1]
[1 2 0]
[0 1 2]]
import matplotlib.pyplot as plt
import itertools
def plot_confusion_matrix(cm, classes,
normalize=False,
title='Confusion matrix',
cmap=plt.cm.Blues):
"""
This function prints and plots the confusion matrix.
Normalization can be applied by setting `normalize=True`.
"""
if normalize:
cm = cm.astype('float') / cm.sum(axis=1, keepdims = True)
plt.imshow(cm, interpolation='nearest', cmap=cmap)
plt.title(title)
plt.colorbar()
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes, rotation=45)
plt.yticks(tick_marks, classes)
fmt = '.2f' if normalize else 'd'
thresh = cm.max() / 2.
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
plt.text(j, i, format(cm[i, j], fmt),
horizontalalignment="center",
color="white" if cm[i, j] > thresh else "black")
plt.tight_layout()
plt.ylabel('True label')
plt.xlabel('Predicted label')
# Plot non-normalized confusion matrix
class_names = [0, 1, 2]
plt.figure()
plot_confusion_matrix(cnf_matrix, classes=class_names,
title='Confusion matrix, without normalization')
# Plot normalized confusion matrix
plt.figure()
plot_confusion_matrix(cnf_matrix, classes=class_names, normalize=True,
title='Normalized confusion matrix')
plt.show()
0
được phân loại không thực sự tốt nhưng trong unnormalized confusion matrix, nó vẫn có màu đậm như hai ô còn lại trên đường chéo chính.4. True/False Positive/Negative
4.1. True/False Positive/Negative
| Predicted | Predicted |
| as Positive | as Negative |
------------------|---------------------|---------------------|
Actual: Positive | True Positive (TP) | False Negative (FN) |
------------------|---------------------|---------------------|
Actual: Negative | False Positive (FP) | True Negative (TN) |
------------------|---------------------|---------------------|
| Predicted | Predicted |
| as Positive | as Negative |
------------------|--------------------|--------------------|
Actual: Positive | TPR = TP/(TP + FN) | FNR = FN/(TP + FN) |
------------------|--------------------|--------------------|
Actual: Negative | FPR = FP/(FP + TN) | TNR = TN/(FP + TN) |
------------------|--------------------|--------------------|
-
Việc biết một cột của confusion matrix này sẽ suy ra được cột còn lại vì tổng các hàng luôn bằng 1 và chỉ có hai lớp dữ liệu.
-
Với các bài toán có nhiều lớp dữ liệu, ta có thể xây dựng bảng True/False Positive/Negative cho mỗi lớp nếu coi lớp đó là lớp Positive, các lớp còn lại gộp chung thành lớp Negative, giống như cách làm trong one-vs-rest. Bạn có thể xem thêm ví dụ tại đây.
4.2. Receiver Operating Characteristic curve
0
hay 1
, hoặc cũng có thể là các giá trị thể hiện xác suất để dữ liệu đầu vào thuộc vào lớp 1
. Khi sử dụng thư viện sklearn Logistic Regression, ta có thể lấy được các giá trị xác xuất này bằng phương thức predict_proba()
. Mặc định, ngưỡng được sử dụng là 0.5, tức là một điểm dữ liệu x
sẽ được dự đoán rơi vào lớp 1
nếu giá trị predict_proba(x)
lớn hơn 0.5 và ngược lại.1
là lớp Positive, lớp 0
là lớp Negative, câu hỏi đặt ra là làm thế nào để tăng mức độ báo nhầm (FPR) để giảm mức độ bỏ sót (FNR)? Chú ý rằng tăng FNR đồng nghĩa với việc giảm TPR vì tổng của chúng luôn bằng 1.0
, tức Negative, và cả TNF và FNR đều tăng lên, tức TPR và FPR giảm xuống.scores
.# generate simulated data
n0, n1 = 20, 30
score0 = np.random.rand(n0)/2
label0 = np.zeros(n0, dtype = int)
score1 = np.random.rand(n1)/2 + .2
label1 = np.ones(n1, dtype = int)
scores = np.concatenate((score0, score1))
y_true = np.concatenate((label0, label1))
print('True labels:')
print(y_true)
print('nScores:')
print(scores)
True labels:
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1]
Scores:
[ 0.16987517 0.27608323 0.10851568 0.13395249 0.24878687 0.29100097
0.21036182 0.48215779 0.01930099 0.30927599 0.26581374 0.15141354
0.26298063 0.10405583 0.30773121 0.39830016 0.04868077 0.17290186
0.28717646 0.3340749 0.4174846 0.27292017 0.68740357 0.62108568
0.20781968 0.43056031 0.67816027 0.47037842 0.23118192 0.68862749
0.24559788 0.58645887 0.69637251 0.5247967 0.24265087 0.60485646
0.54800088 0.69565411 0.20509934 0.39638029 0.30860676 0.6267616
0.42360257 0.5507021 0.50313701 0.67614457 0.60108083 0.25201502
0.27830655 0.58669514]
1
có score
cao hơn. Thư viện sklearn sẽ giúp chúng ta tính các thresholds cũng như FPR và TPR tương ứng:from sklearn.metrics import roc_curve, auc
fpr, tpr, thresholds = roc_curve(y_true, scores, pos_label = 1)
print('Thresholds:')
print(thresholds)
Thresholds:
[ 0.69637251 0.50313701 0.48215779 0.4174846 0.39830016 0.39638029
0.30927599 0.30860676 0.28717646 0.27830655 0.27608323 0.27292017
0.26298063 0.25201502 0.24878687 0.23118192 0.21036182 0.20509934
0.01930099]
print('False Positive Rate:')
print(fpr)
False Positive Rate:
[ 0. 0. 0.05 0.05 0.1 0.1 0.2 0.2 0.35 0.35 0.4 0.4
0.5 0.5 0.55 0.55 0.6 0.6 1. ]
print('True Positive Rate:')
tpr
True Positive Rate:
array([ 0.03333333, 0.53333333, 0.53333333, 0.66666667, 0.66666667,
0.7 , 0.7 , 0.73333333, 0.73333333, 0.76666667,
0.76666667, 0.8 , 0.8 , 0.83333333, 0.83333333,
0.93333333, 0.93333333, 1. , 1. ])
threshold = 0.69637251
, fpr = 0
và tpr = 0.03
. Đây không phải là một ngưỡng tốt vì mặc dụ False Positive Rate thấp, True Positive Rate cũng rất thấp. Chúng ta luôn muốn rằng FPR thấp và TPR cao.import matplotlib.pyplot as plt
from itertools import cycle
plt.figure()
lw = 2
plt.plot(fpr, tpr, color='darkorange',
lw=lw, label='ROC curve (area = %0.2f)' % auc(fpr, tpr))
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()
Hình 2: Ví dụ về Receiver Operating Characteristic curve và Area Under the Curve. |
4.3. Area Under the Curve
5. Precision và Recall
5.1 Định nghĩa
from __future__ import print_function
import numpy as np
# confusion matrix to precision + recall
def cm2pr_binary(cm):
p = cm[0,0]/np.sum(cm[:,0])
r = cm[0,0]/np.sum(cm[0])
return (p, r)
# example of a confusion matrix for binary classification problem
cm = np.array([[100., 10], [20, 70]])
p,r = cm2pr_binary(cm)
print("precition = {0:.2f}, recall = {1:.2f}".format(p, r))
precition = 0.83, recall = 0.91
5.2. Precision-Recall curve và Average precision
. Precision-Recall curve được vẽ bằng cách vẽ từng điểm có toạ độ (Rn,Pn)
trên trục toạ độ và nối chúng với nhau. AP được xác định bằng:AP=∑n(Rn−Rn−1)Pn
và chiều cao Pn
, đây cũng gần với cách tính tích phân dựa trên cách tính diện tích của từng hình chữ nhật nhỏ. (Nếu bạn đọc còn nhớ khái niệm diện tích hình thang cong thì sẽ tưởng tượng ra.)
5.3. F1-score
. F1
càng cao, bộ phân lớp càng tốt. Khi cả recall và precision đều bằng 1 (tốt nhất có thể), F1=1
. Khi cả recall và precision đều thấp, ví dụ bằng 0.1, F1=0.1
. Dưới đây là một vài ví dụ về F1
precision
|
recall
|
F1
|
1
|
1
|
1
|
0.1
|
0.1
|
0.1
|
0.5
|
0.5
|
0.5
|
1
|
0.1
|
0.182
|
0.3
|
0.8
|
0.36
|
Trường hợp tổng quát của Như vậy, một bộ phân lớp với precision = recall = 0.5 tốt hơn một bộ phân lớp khác với precision = 0.3, recall = 0.8 theo cách đo này.
score:Fβ=(1+β2)precision⋅recallβ2⋅precision+recall
khi β=1
. Khi β>1
, recall được coi trọng hơn precision, khi β<1
, precision được coi trọng hơn. Hai đại lượng β
thường được sử dụng là β=2
và β=0.5
.
5.4. Precision-recall cho bài toán phân lớp nhiều lớp
5.4.1. Micro-average
tp1, fp1, fn1 = 10, 5, 3
tp2, fp2, fn2 = 17, 7, 10
tp3, fp3, fn3 = 25, 2, 4
from __future__ import print_function
def PR(tp, fp, fn):
P = float(tp)/(tp + fp)
R = float(tp)/(tp + fn)
return (P, R)
(P1, R1) = PR(tp1, fp1, fn1)
(P2, R2) = PR(tp2, fp2, fn2)
(P3, R3) = PR(tp3, fp3, fn2)
print('(P1, R1) = (%.2f, %.2f)'%(P1, R1))
print('(P2, R2) = (%.2f, %.2f)'%(P2, R2))
print('(P3, R3) = (%.2f, %.2f)'%(P3, R3))
(P1, R1) = (0.67, 0.77)
(P2, R2) = (0.71, 0.63)
(P3, R3) = (0.93, 0.71)
lần lượt là TP, FP, FN của class c
.
total_tp = tp1 + tp2 + tp3
total_fp = fp1 + fp2 + fp3
total_fn = fn1 + fn2 + fn3
micro_ap = float(total_tp)/(total_tp + total_fp)
micro_ar = float(total_tp)/(total_tp + total_fn)
print('(micro_ap, micro_ar) = (%.2f, %.2f)' % (micro_ap, micro_ar))
(micro_ap, micro_ar) = (0.79, 0.75)
5.4.2. Macro-average
macro_ap = (P1 + P2 + P3)/3
macro_ar = (R1 + R2 + R3)/3
print('(micro_ap, micro_ar) = (%.2f, %.2f)' % (macro_ap, macro_ar))
(micro_ap, micro_ar) = (0.77, 0.70)
6. Tóm tắt
-
Accuracy là tỉ lệ giữa số điểm được phân loại đúng và tổng số điểm. Accuracy chỉ phù hợp với các bài toán mà kích thước các lớp dữ liệu là tương đối như nhau.
-
Confusion matrix giúp có cái nhìn rõ hơn về việc các điểm dữ liệu được phân loại đúng/sai như thế nào.
-
True Positive (TP): số lượng điểm của lớp positive được phân loại đúng là positive.
-
True Negative (TN): số lượng điểm của lớp negative được phân loại đúng là negative.
-
False Positive (FP): số lượng điểm của lớp negative bị phân loại nhầm thành positive.
-
False Negative (FN): số lượng điểm của lớp positiv bị phân loại nhầm thành negative
-
True positive rate (TPR), false negative rate (FNR), false positive rate (FPR), true negative rate (TNR):
| Predicted | Predicted |
| as Positive | as Negative |
------------------|--------------------|--------------------|
Actual: Positive | TPR = TP/(TP + FN) | FNR = FN/(TP + FN) |
------------------|--------------------|--------------------|
Actual: Negative | FPR = FP/(FP + TN) | TNR = TN/(FP + TN) |
------------------|--------------------|--------------------|
-
Khi kích thước các lớp dữ liệu là chênh lệch (imbalanced data hay skew data), precision và recall thường được sử dụng:
với TPc,FPc,FNc
lần lượt là TP, FP, FN của class c
.
-
Micro-average precision, macro-average recall là trung bình cộng của các precision, recall cho từng lớp. Micro-average (macro-average) F1 scores cũng được tính dựa trên các micro-average (macro-average) precision, recall tương ứng.
7. Tài liệu tham khảo
Hits: 0