Mục lục
- Vì sao accuracy không đủ
- Binary Confusion Matrix — ma trận 2×2
- 4 thành phần TP / TN / FP / FN
- Type I và Type II error
- Cost của FP vs FN tuỳ domain
- sklearn confusion_matrix
- ConfusionMatrixDisplay — visualize
- Multi-class Confusion Matrix
- Normalized confusion matrix
- Đọc confusion matrix nhanh
- Imbalanced dataset — vấn đề lộ ra
- Cost-sensitive learning — preview
- Code Python — breast cancer và imbalanced demo
- Bài tập thực hành
- Bài tiếp theo
Vì sao accuracy không đủ
Sau khi train model phân loại (vd Logistic Regression ở Bài 22), câu hỏi tự nhiên: "Model có tốt không?". Cách đo nhanh nhất là accuracy — tỉ lệ sample được predict đúng trên tổng số sample.
Accuracy có 2 hạn chế lớn:
- Không cho biết model sai ở đâu. Một model accuracy 90% có thể sai chủ yếu ở class hiếm (sai 50% class 1, đúng 100% class 0); một model khác cũng accuracy 90% nhưng sai đều ở cả 2 class. Cùng một con số, hai hành vi rất khác — accuracy không phân biệt.
- Misleading trên imbalanced data. Nếu 95% sample là class 0, một model "luôn predict 0" đạt accuracy 95% mà không học gì cả. Trong các bài toán phát hiện gian lận, bệnh hiếm, spam — class quan tâm thường là class thiểu số — accuracy gần như vô dụng.
Confusion matrix giải hai vấn đề đó: nó tách lỗi của model theo từng loại — bao nhiêu sample class 0 bị nhầm thành 1, bao nhiêu sample class 1 bị nhầm thành 0, và ngược lại. Mọi metric phân loại quan trọng (Accuracy, Precision, Recall, F1, Specificity) đều được derive từ confusion matrix.
Sau bài này, bạn sẽ:
- Đọc và vẽ được binary confusion matrix.
- Phân biệt 4 ô TP, TN, FP, FN — và 2 loại error Type I / Type II.
- Hiểu cost của FP và FN khác nhau theo domain.
- Tính và visualize confusion matrix bằng sklearn (cả binary và multi-class).
- Sử dụng normalized confusion matrix để đọc tỉ lệ thay vì count.
Binary Confusion Matrix — ma trận 2×2
Với binary classification, model output 1 trong 2 class — quy ước thường là 0 (negative) và 1 (positive). So sánh prediction với ground truth cho 4 trường hợp, tổng hợp thành ma trận 2×2:
Predicted
0 1
Actual 0 [ TN FP ]
1 [ FN TP ]
Cách đọc:
- Hàng = ground truth (label thật của sample).
- Cột = prediction của model.
- Ô (i, j) = số sample có label thật
ivà bị model predict thànhj. - Đường chéo chính (TN và TP) — predict đúng.
- Ngoài đường chéo (FP và FN) — predict sai.
Tên các ô đặt theo prediction của model là gì + đúng/sai:
- True / False — model predict đúng (True) hay sai (False)?
- Positive / Negative — model predict ra class 1 (Positive) hay class 0 (Negative)?
Nắm quy ước này, đọc tên 4 ô không cần nhớ máy móc: "True Positive" = predict Positive và đúng → label thật cũng là 1.
4 thành phần TP / TN / FP / FN
Định nghĩa và ví dụ với bài toán "chẩn đoán bệnh ung thư" (label 1 = bị bệnh, label 0 = không bị):
- TP (True Positive) — predict 1, actual 1. Model nói "bị bệnh" và đúng là bị bệnh. Bệnh nhân được phát hiện và điều trị kịp thời.
- TN (True Negative) — predict 0, actual 0. Model nói "không bị" và đúng là không bị. Người khoẻ về nhà, không phải xét nghiệm thêm.
- FP (False Positive) — predict 1, actual 0. Model nói "bị bệnh" nhưng thực ra khoẻ. Bệnh nhân bị làm thêm xét nghiệm không cần thiết, lo lắng oan — còn gọi là false alarm.
- FN (False Negative) — predict 0, actual 1. Model nói "không bị" nhưng thực ra đang bị bệnh. Bỏ sót ca bệnh — bệnh nhân về nhà mà không được điều trị — còn gọi là missed detection.
Một số đẳng thức cơ bản từ confusion matrix:
- Tổng sample: \( N = \text{TP} + \text{TN} + \text{FP} + \text{FN} \).
- Số sample positive thật: \( P = \text{TP} + \text{FN} \).
- Số sample negative thật: \( N_{\text{neg}} = \text{TN} + \text{FP} \).
- Số sample model predict positive: \( \text{TP} + \text{FP} \).
- Accuracy: \( (\text{TP} + \text{TN}) / N \).
Các metric Precision, Recall, F1 (Bài 24, 25) đều là tỉ số giữa các ô này. Hiểu rõ 4 ô là điều kiện đủ để đọc mọi metric phân loại còn lại.
Type I và Type II error
Trong thống kê cổ điển (kiểm định giả thuyết), 2 loại sai có tên riêng — và trùng với FP, FN trong ML:
- Type I error = FP. Bác bỏ \( H_0 \) khi \( H_0 \) đúng. Trong khuôn khổ ML phân loại với \( H_0 \): "sample là negative", Type I là khi model predict positive trong khi sample thực ra negative.
- Type II error = FN. Chấp nhận \( H_0 \) khi \( H_0 \) sai. Tức model predict negative trong khi sample thực ra positive.
Mẹo nhớ: Type I là "false alarm" (báo động giả), Type II là "miss" (bỏ sót). Hai loại sai này không cùng cost — đó là lý do tại sao confusion matrix tách FP và FN ra riêng thay vì gộp thành "tổng số lỗi".
Một số khái niệm dùng chung với thống kê:
- Significance level \( \alpha \) — xác suất Type I error chấp nhận được (thường 0.05). Trong ML, tương ứng với "FP rate" cho phép.
- Power = 1 − P(Type II error). Trong ML, tương ứng với recall (Bài 24).
Cost của FP vs FN tuỳ domain
Đây là phần quan trọng nhất khi chọn metric cho bài toán thực: FP và FN không bao giờ có cost bằng nhau. Bằng cách định nghĩa rõ class 1 là gì, cost asymmetry sẽ định hướng metric ưu tiên.
Medical (chẩn đoán bệnh) — class 1 = bị bệnh:
- FN nguy hiểm. Bỏ sót bệnh nhân thực sự bị bệnh → không được điều trị kịp thời → bệnh nặng lên hoặc tử vong.
- FP bất tiện nhưng ít nguy hiểm. Bệnh nhân khoẻ bị nghi ngờ → làm thêm xét nghiệm xác nhận → lo lắng và tốn tiền nhưng không nguy hiểm tính mạng.
- Hệ quả: trong sàng lọc bệnh hiểm nghèo, ưu tiên model có recall cao (giảm FN), chấp nhận precision thấp hơn.
Spam filter — class 1 = spam:
- FP nguy hiểm. Email công việc quan trọng bị filter nhầm thành spam → người dùng không thấy → mất hợp đồng, lỡ deadline.
- FN khó chịu nhưng dễ chấp nhận. Vài email spam lọt vào inbox → người dùng xoá tay.
- Hệ quả: ưu tiên model có precision cao (giảm FP), chấp nhận một số spam lọt qua.
Fraud detection — class 1 = giao dịch gian lận:
- FN nguy hiểm. Bỏ sót giao dịch gian lận → ngân hàng mất tiền trực tiếp.
- FP có cost nhưng kiểm soát được. Giao dịch hợp lệ bị flag → khách hàng bị verify thêm → khó chịu nhưng không mất tiền.
- Hệ quả: tương tự medical — ưu tiên recall, kèm pipeline "verify" để giảm FP ảnh hưởng UX.
Quy tắc đặt câu hỏi:
- "Nếu model nói có (positive) nhưng thực ra không (negative) — hậu quả là gì?" → cost của FP.
- "Nếu model nói không (negative) nhưng thực ra có (positive) — hậu quả là gì?" → cost của FN.
- So sánh 2 cost → quyết định tối ưu hoá precision hay recall.
sklearn confusion_matrix
API cơ bản:
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_true, y_pred)
# Mac dinh: row = actual, col = predicted
# Label order: theo numpy.unique(y_true, y_pred), tang dan
# Voi binary 0/1: cm[0,0]=TN, cm[0,1]=FP, cm[1,0]=FN, cm[1,1]=TP
Lưu ý quan trọng:
- Convention sklearn: hàng = actual, cột = predicted. Khớp với layout đã giới thiệu ở Bước 2.
- Một số sách / slide bài giảng đảo trục. Có tài liệu vẽ hàng = predicted, cột = actual. Khi đọc confusion matrix ở nguồn khác, luôn kiểm tra label trục trước khi diễn giải.
- Order các class. Theo mặc định sklearn sắp xếp tăng dần. Truyền
labels=[1, 0]để đảo thứ tự, hoặclabels=['cat', 'dog', 'bird']để cố định thứ tự cho nhiều class.
Ví dụ binary:
y_true = [0, 1, 1, 0, 1, 1, 0, 0, 1, 0]
y_pred = [0, 1, 0, 0, 1, 1, 1, 0, 1, 0]
cm = confusion_matrix(y_true, y_pred)
print(cm)
# [[4 1] -> TN=4, FP=1
# [1 4]] -> FN=1, TP=4
tn, fp, fn, tp = cm.ravel() # tien khi unpack binary
print(f"TN={tn}, FP={fp}, FN={fn}, TP={tp}")
Method .ravel() chỉ hợp lý cho ma trận 2×2 — multi-class phải truy cập theo index.
Nếu muốn lấy báo cáo có cả Precision, Recall, F1 — dùng classification_report:
from sklearn.metrics import classification_report
print(classification_report(y_true, y_pred, target_names=["khoe", "benh"]))
ConfusionMatrixDisplay — visualize
Đọc ma trận raw bằng print khó hơn nhìn heatmap. sklearn có class wrap sẵn:
import matplotlib.pyplot as plt
from sklearn.metrics import ConfusionMatrixDisplay
# Cach 1: tu model + data (chua predict)
ConfusionMatrixDisplay.from_estimator(
model, X_test, y_test,
display_labels=["khoe", "benh"],
cmap="Blues",
)
plt.show()
# Cach 2: tu y_true va y_pred co san
ConfusionMatrixDisplay.from_predictions(
y_test, y_pred,
display_labels=["khoe", "benh"],
cmap="Blues",
)
plt.show()
# Cach 3: tu ma tran cm tinh san
disp = ConfusionMatrixDisplay(
confusion_matrix=cm,
display_labels=["khoe", "benh"],
)
disp.plot(cmap="Blues")
plt.show()
Tham số đáng nhớ:
normalize—None(count),"true"(normalize theo hàng),"pred"(theo cột),"all"(theo tổng).cmap— colormap matplotlib."Blues"dễ đọc cho người colorblind hơn các palette nhiều màu.values_format— định dạng số trong ô. Vd".2%"cho phần trăm,"d"cho integer count.xticks_rotation— xoay label nhãn cột (hữu ích khi có nhiều class, tên dài).
Output là một matplotlib.figure — có thể save bằng plt.savefig("cm.png", dpi=150).
Multi-class Confusion Matrix
Với \( K \) class, confusion matrix là ma trận \( K \times K \). Cách đọc giữ nguyên:
- Đường chéo chính — predict đúng. Sample class \( i \) được predict đúng là \( i \).
- Off-diagonal — predict sai. Ô \( (i, j) \) với \( i \neq j \) = số sample class \( i \) bị nhầm thành class \( j \).
Khái niệm TP/TN/FP/FN không còn cố định một ô — phải chọn 1 class làm "positive", các class còn lại gộp thành "negative" (one-vs-rest):
- TP của class \( c \) = ô đường chéo \( (c, c) \).
- FN của class \( c \) = tổng hàng \( c \) trừ TP — sample class \( c \) bị nhầm thành class khác.
- FP của class \( c \) = tổng cột \( c \) trừ TP — sample class khác bị nhầm thành \( c \).
- TN của class \( c \) = tổng còn lại — sample không thuộc class \( c \) và cũng không được predict thành \( c \).
Use case kinh điển: MNIST (nhận dạng chữ số 0-9). Confusion matrix 10×10 thường cho thấy các cặp nhầm lẫn cố hữu:
- 4 ↔ 9 — nét cong dễ nhầm.
- 3 ↔ 5, 3 ↔ 8 — nét cong tương tự.
- 1 ↔ 7 — đặc biệt với chữ số viết kiểu châu Âu (có gạch ngang ở 7).
Pattern này không thấy được từ accuracy. Confusion matrix chỉ thẳng vào cặp class hay nhầm — gợi ý cho feature engineering (vd thêm feature về độ cong) hoặc data augmentation (thêm sample chữ số dễ nhầm) để cải thiện.
Normalized confusion matrix
Khi các class có số sample khác nhau, count trong từng ô có thể đánh lừa thị giác — class nhiều sample sẽ "đậm màu" hơn dù tỉ lệ lỗi không cao hơn. Normalize giải vấn đề này.
Ba kiểu normalize trong confusion_matrix và ConfusionMatrixDisplay:
-
normalize="true"— chia theo hàng (theo actual class). Mỗi hàng tổng bằng 1.
Ô \( (i, j) \) = "trong các sample thực sự là class \( i \), bao nhiêu phần trăm được model predict thành class \( j \)?".
Đường chéo của ma trận này = recall của từng class. -
normalize="pred"— chia theo cột (theo predicted class). Mỗi cột tổng bằng 1.
Ô \( (i, j) \) = "trong các sample model predict là class \( j \), bao nhiêu phần trăm thực sự thuộc class \( i \)?".
Đường chéo của ma trận này = precision của từng class. -
normalize="all"— chia tổng số sample. Toàn ma trận tổng bằng 1.
Ô \( (i, j) \) = joint probability \( P(\text{actual}=i, \text{predicted}=j) \).
Khi nào dùng cái nào:
"true": muốn biết "model bắt được bao nhiêu phần trăm của từng class" → debug class nào model bỏ sót nhiều."pred": muốn biết "khi model nói class \( j \), độ tin cậy thế nào" → debug class nào model hay báo nhầm."all": phân tích phân phối lỗi tổng thể.
Trong report cho stakeholder không kỹ thuật, normalized với values_format=".2%" dễ đọc hơn count. Trong debug pipeline, count vẫn cần để biết absolute number sample.
Đọc confusion matrix nhanh
Quy trình 4 bước khi nhận confusion matrix mới:
- Kiểm tra trục. Hàng nào là actual, cột nào là predicted? Class order? Đừng giả định — luôn đọc label trục.
- Nhìn đường chéo. Tỉ lệ giá trị đường chéo so với tổng hàng tương ứng → recall per class. Class nào recall thấp = class bị bỏ sót nhiều.
- Nhìn off-diagonal. Ô nào off-diagonal có giá trị cao? Ô \( (i, j) \) cao = class \( i \) hay bị nhầm thành class \( j \). Tìm pattern: có cặp class nào nhầm hai chiều không (\( i \to j \) và \( j \to i \) đều cao)?
- Đánh giá theo cost. Liên hệ ô FN, FP với cost trong domain (Bước 5). Số nào cần ưu tiên giảm trong iteration tiếp theo?
Câu hỏi cần đặt thêm:
- Có class nào hoàn toàn bị model bỏ sót (cột toàn 0)? → model chưa học class đó, có thể do quá ít sample.
- Có class nào model gán bừa cho mọi thứ (cột rất "dày")? → model bias về class đó, có thể do class đó chiếm đa số trong train data.
- Confusion matrix có gần đối xứng (\( i \to j \approx j \to i \)) không? Nếu có, hai class đó về bản chất khó tách bằng feature hiện tại.
Imbalanced dataset — vấn đề lộ ra
Ví dụ minh hoạ vì sao accuracy không đủ — và vì sao confusion matrix bắt buộc với imbalanced data.
Tình huống: dataset 1000 sample, 950 class 0, 50 class 1 (5% positive). Model "ngu" luôn predict 0:
Predicted
0 1
Actual 0 [ 950 0 ]
1 [ 50 0 ]
- Accuracy = (950 + 0) / 1000 = 95% — nhìn riêng rất "tốt".
- TP = 0 — model không bắt được sample positive nào.
- FN = 50 — bỏ sót tất cả ca cần phát hiện.
- Recall của class 1 = 0 / 50 = 0% — model hoàn toàn vô dụng cho mục tiêu chính.
Trong bài toán phát hiện gian lận, ung thư hiếm, hay churn — class 1 là class bạn quan tâm. Một model "accuracy 95% nhưng recall class 1 = 0%" không có giá trị thực tế. Confusion matrix làm rõ ngay điều này; accuracy đơn lẻ không.
Khi gặp imbalanced data, các metric đáng tin cậy hơn accuracy:
- Precision, Recall, F1 của class thiểu số (Bài 24, 25).
- ROC-AUC, PR-AUC (Bài 26).
- Confusion matrix normalized để nhìn tỉ lệ thay vì count.
Cost-sensitive learning — preview
Khi FP và FN có cost khác nhau rõ rệt, tối ưu accuracy (coi mọi lỗi như nhau) không đúng mục tiêu kinh doanh. Cost-sensitive learning đưa cost vào training và evaluation.
Cost matrix — bảng cost cho từng loại lỗi, vd:
Predicted
0 1
Actual 0 [ 0 1 ] <- FP cost = 1
1 [ 100 0 ] <- FN cost = 100
Mục tiêu: tối thiểu hoá total cost = \( \text{FP} \times 1 + \text{FN} \times 100 \), thay vì tối thiểu hoá tổng lỗi = \( \text{FP} + \text{FN} \). Khi FN đắt gấp 100 lần FP, model sẽ "thà có nhiều false alarm còn hơn bỏ sót".
Trong sklearn, tiếp cận phổ biến nhất là class_weight cho model:
from sklearn.linear_model import LogisticRegression
# Vd dataset 95% class 0 / 5% class 1
model = LogisticRegression(class_weight="balanced")
# Hoac chi dinh tay:
model = LogisticRegression(class_weight={0: 1, 1: 19})
Tham số class_weight="balanced" tự động đặt trọng số tỉ lệ nghịch với tần suất class — class hiếm được weight cao hơn trong loss function, kéo model về phía bắt được class hiếm.
Use case: fraud detection (FN = mất tiền, FP = phiền khách), medical screening (FN = chết người, FP = thêm xét nghiệm), churn prediction (FN = mất khách, FP = ưu đãi không cần thiết). Chi tiết cost-sensitive learning sẽ quay lại ở module Tối ưu và Đánh giá.
Code Python — breast cancer và imbalanced demo
Hai kịch bản: (1) confusion matrix trên dataset cân bằng (breast cancer), (2) confusion matrix lộ vấn đề trên dataset imbalanced 95/5.
Kịch bản 1 — breast cancer:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
from sklearn.metrics import (
confusion_matrix,
ConfusionMatrixDisplay,
classification_report,
)
# 1. Load data
data = load_breast_cancer()
X, y = data.data, data.target
# Quy uoc sklearn: 0 = malignant (ac tinh), 1 = benign (lanh tinh)
# Doi quy uoc cho ngu canh "phat hien ung thu" -> class 1 = malignant
y = 1 - y
class_names = ["benign", "malignant"]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
# 2. Train pipeline (scale + logistic)
model = make_pipeline(
StandardScaler(),
LogisticRegression(max_iter=1000),
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
# 3. Confusion matrix
cm = confusion_matrix(y_test, y_pred)
print(cm)
tn, fp, fn, tp = cm.ravel()
print(f"TN={tn}, FP={fp}, FN={fn}, TP={tp}")
# 4. Visualize
ConfusionMatrixDisplay.from_predictions(
y_test, y_pred,
display_labels=class_names,
cmap="Blues",
)
plt.title("Breast cancer - confusion matrix")
plt.show()
# 5. Bao cao day du
print(classification_report(y_test, y_pred, target_names=class_names))
Quan sát: dataset breast cancer khá cân bằng (~63% benign / 37% malignant) và feature tách rõ — model thường đạt accuracy > 95%. Hãy chú ý FN trong output: dù chỉ 1-2 ca FN, trong context y khoa đó là 1-2 bệnh nhân ung thư bị bỏ sót.
Kịch bản 2 — imbalanced 95/5:
from sklearn.datasets import make_classification
# Tao dataset imbalanced 95/5
X, y = make_classification(
n_samples=2000,
n_features=20,
n_informative=5,
weights=[0.95, 0.05],
random_state=42,
)
print("Class distribution:", np.bincount(y)) # [1900, 100]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y
)
# Model thuong (khong xu ly imbalance)
model_plain = LogisticRegression(max_iter=1000).fit(X_train, y_train)
y_pred_plain = model_plain.predict(X_test)
print("Accuracy plain:", (y_pred_plain == y_test).mean())
print(confusion_matrix(y_test, y_pred_plain))
# Model voi class_weight="balanced"
model_bal = LogisticRegression(max_iter=1000, class_weight="balanced")
model_bal.fit(X_train, y_train)
y_pred_bal = model_bal.predict(X_test)
print("Accuracy balanced:", (y_pred_bal == y_test).mean())
print(confusion_matrix(y_test, y_pred_bal))
Pattern điển hình của output:
- Model "plain" có accuracy cao (~95-96%) nhưng confusion matrix cho thấy hầu hết sample class 1 bị nhầm thành class 0 — TP rất thấp, FN cao.
- Model "balanced" có accuracy thấp hơn (~85-90%) nhưng TP cao hơn nhiều — bắt được phần lớn sample class 1, đổi lại tăng FP.
Lựa chọn giữa hai model không phải dựa vào accuracy, mà dựa vào: FP và FN bên nào nguy hiểm hơn trong bài toán của bạn?.
Bài tập thực hành
Bài 1 — Đọc ma trận bằng tay. Cho confusion matrix (convention sklearn: hàng = actual, cột = predicted, class order [0, 1]):
[[80, 5],
[10, 5]]
Yêu cầu:
- Xác định TP, TN, FP, FN.
- Tính accuracy của model.
- Trong tổng số 15 sample positive, model bắt được bao nhiêu?
- Nếu đây là bài toán phát hiện bệnh, FP và FN cái nào đáng lo hơn? Đề xuất hướng cải thiện.
Bài 2 — Confusion matrix trên breast cancer. Train Logistic Regression trên load_breast_cancer() (giữ nguyên quy ước sklearn 0=malignant, 1=benign — không đảo). In ra:
- Confusion matrix dạng count.
- Confusion matrix normalize theo hàng (
normalize="true"). - Confusion matrix normalize theo cột (
normalize="pred").
Giải thích sự khác biệt giữa 3 dạng và khi nào dùng dạng nào.
Bài 3 — Imbalanced 95/5. Dùng make_classification tạo dataset 2000 sample, tỉ lệ class 95/5. Train 2 phiên bản Logistic Regression:
- Phiên bản 1: mặc định.
- Phiên bản 2:
class_weight="balanced".
So sánh confusion matrix và accuracy của 2 phiên bản. Trong tình huống FN có cost cao gấp 20 lần FP, phiên bản nào nên chọn? Tính total cost = \( \text{FP} \times 1 + \text{FN} \times 20 \) cho cả hai để verify.
Bài 4 — Multi-class với MNIST-like. Dùng load_digits() của sklearn (8×8 ảnh chữ số 0-9). Train Logistic Regression và in confusion matrix 10×10. Quan sát:
- Đường chéo có "đậm" không?
- Cặp chữ số nào hay bị nhầm nhất (off-diagonal cao nhất)?
- Có cặp nào nhầm 2 chiều (\( i \to j \) và \( j \to i \) đều cao)?
Gợi ý đáp án Bài 1: TN=80, FP=5, FN=10, TP=5. Accuracy = (80+5)/100 = 85%. Recall class 1 = 5/15 ≈ 33% — model bỏ sót 10/15 ca positive. Trong y khoa, FN nguy hiểm hơn FP → nên giảm FN bằng cách thay đổi threshold (về sau ở ROC) hoặc dùng class_weight="balanced".
Bài tiếp theo
Bài 24: Accuracy, Precision, Recall — chọn metric nào? — từ 4 ô của confusion matrix derive 3 metric kinh điển: accuracy (đường chéo / tổng), precision (TP / predicted positive), recall (TP / actual positive). Khi nào ưu tiên precision, khi nào ưu tiên recall, và vì sao 2 metric này thường đối nghịch nhau trong thực tế.
Tài liệu tham khảo
- scikit-learn — confusion_matrix API reference
- scikit-learn — ConfusionMatrixDisplay API reference
- scikit-learn — Confusion matrix example
- scikit-learn — Model evaluation: Confusion matrix
- Wikipedia — Confusion matrix
- Wikipedia — Type I and type II errors
- Gareth James et al. — An Introduction to Statistical Learning (Chương 4.4.2: Confusion Matrix)
