Mở Đầu

Trong lĩnh vực học máy (machine learning) và thống kê, đường cong ROC (Receiver Operating Characteristic) là một công cụ quan trọng giúp chúng ta đánh giá hiệu suất của các mô hình phân loại nhị phân. Đường cong ROC cho phép chúng ta nhìn nhận mối quan hệ giữa True Positive Rate (TPR) và False Positive Rate (FPR) ở các ngưỡng quyết định (threshold) khác nhau, từ đó lựa chọn ngưỡng tối ưu cho mô hình.

Bài viết dưới đây sẽ cung cấp cho bạn một hướng dẫn chi tiết, từng bước một, về cách vẽ đường cong ROC, bao gồm:

  1. Kiến thức nền tảng về ROC, TPR, FPR, AUC.
  2. Chuẩn bị dữ liệu và mô hình.
  3. Tính toán các giá trị cần thiết.
  4. Vẽ ROC bằng Python (sử dụng thư viện scikit‑learn, matplotlib, seaborn) và R (sử dụng pROC, ggplot2).
  5. Phân tích và giải thích kết quả.
  6. Một số lưu ý, lỗi thường gặp và cách khắc phục.
  7. Các biến thể và ứng dụng mở rộng (multiclass ROC, PR curve, cost‑sensitive ROC…).

Mục tiêu cuối cùng là giúp bạn không chỉ biết cách vẽ mà còn hiểu sâu về ý nghĩa và cách sử dụng đường cong ROC trong các bài toán thực tế.

1. Kiến Thức Cơ Bản Về Đường Cong ROC

1.1. Định Nghĩa

  • True Positive (TP): Số mẫu dương thực sự được mô hình dự đoán là dương.
  • False Positive (FP): Số mẫu âm thực sự nhưng mô hình dự đoán là dương.
  • True Negative (TN): Số mẫu âm thực sự được mô hình dự đoán là âm.
  • False Negative (FN): Số mẫu dương thực sự nhưng mô hình dự đoán là âm.

Từ đó, ta có:

  • True Positive Rate (TPR) – còn gọi là Recall hoặc Sensitivity:

    \text{TPR} = \frac{TP}{TP + FN}

  • False Positive Rate (FPR):

    \text{FPR} = \frac{FP}{FP + TN}

1.2. Ý Nghĩa CủA ROC

  • Trục hoành (x‑axis) của ROC là FPR (từ 0 → 1).
  • Trục tung (y‑axis) là TPR (từ 0 → 1).
  • Mỗi điểm trên đường cong tương ứng với một ngưỡng quyết định (threshold) khác nhau, xác định cách mô hình chuyển đổi xác suất dự đoán thành nhãn lớp (0/1).

1.3. Diện tích Dưới Đường Cong (AUC)

  • AUC (Area Under the Curve) là giá trị số nằm trong khoảng (0, 1).
  • AUC = 0.5 → mô hình ngẫu nhiên.
  • AUC → 1.0 → mô hình hoàn hảo.
  • AUC thường được dùng làm tiêu chí so sánh các mô hình.

2. Chuẩn Bị Dữ Liệu Và Mô Hình

2.1. Dữ Liệu

Bạn cần một bộ dữ liệu đánh dấu nhị phân (có nhãn 0 và 1). Ví dụ phổ biến:

  • Breast Cancer Wisconsin (dự đoán ung thư là lành tính hay ác tính).
  • Titanic (dự đoán sống/thảm tử).
  • Credit Card Fraud (giao dịch gian lận hay không).

Dữ liệu cần được chia thành train set và test set (hoặc dùng cross‑validation). Đảm bảo rằng tập test chưa từng được mô hình “nhìn” trong quá trình huấn luyện.

2.2. Mô Hình Phân Loại

Bạn có thể dùng bất kỳ mô hình nào trả về xác suất (probability) cho lớp dương, ví dụ:

  • Logistic Regression
  • Random Forest
  • Gradient Boosting (XGBoost, LightGBM)
  • Neural Networks

Lưu ý: Đối với một số mô hình chỉ trả về nhãn (0/1) mà không có xác suất, bạn cần cấu hình hoặc sử dụng hàm predict_proba (scikit‑learn) hoặc predict với type = "prob" (R).

3. Tính Toán Các Giá Trị Cần Thiết

3.1. Thu Thập Xác Suất Dự Đoán

Sau khi huấn luyện mô hình, dùng tập test để dự đoán xác suất cho lớp dương:

# Python (scikit-learn)
y_proba = model.predict_proba(X_test):, 1 # cột 1 là lớp 1 (positive)
# R (caret)
y_proba <- predict(model, X_test, type = "prob"), "Positive"

3.2. Tính TPR, FPR Cho Mỗi Ngưỡng

Thư viện scikit‑learn cung cấp hàm roc_curve:

from sklearn.metrics import roc_curve, auc fpr, tpr, thresholds = roc_curve(y_test, y_proba)
roc_auc = auc(fpr, tpr)

Trong R, hàm roc của gói pROC thực hiện tương tự:

library(pROC)
roc_obj <- roc(response = y_test, predictor = y_proba)
auc(roc_obj) # giá trị AUC

Kết quả trả về:

  • fpr: mảng các giá trị False Positive Rate.
  • tpr: mảng các giá trị True Positive Rate.
  • thresholds: các ngưỡng tương ứng (được sắp xếp giảm dần).

4. Vẽ Đường Cong ROC

4.1. Sử Dụng Python (Matplotlib + Seaborn)

import matplotlib.pyplot as plt
import seaborn as sns plt.figure(figsize=(8, 6))
sns.set_style("whitegrid") # Vẽ đường ROC
plt.plot(fpr, tpr, color='darkorange', lw=2, label='ROC curve (AUC = %0.4f)' % roc_auc) # Đường chéo ngẫu nhiên
plt.plot(0, 1, 0, 1, color='navy', lw=2, linestyle='--', label='Random guess') plt.xlim(0.0, 1.0)
plt.ylim(0.0, 1.05)
plt.xlabel('False Positive Rate (FPR)')
plt.ylabel('True Positive Rate (TPR)')
plt.title('Receiver Operating Characteristic (ROC) Curve')
plt.legend(loc="lower right")
plt.show()

4.1.1. Thêm Ngưỡng Trên Đồ Thị

Nếu muốn hiển thị các ngưỡng trên đường cong:

for i, thresh in enumerate(thresholds::len(thresholds)//10): # 10 điểm mẫu plt.annotate(f'{thresh:.2f}', xy=(fprilen(fpr)//10, tprilen(tpr)//10), textcoords='offset points', xytext=(0,10), ha='center')

4.2. Sử Dụng R (ggplot2 + pROC)

library(ggplot2)
library(pROC) roc_obj <- roc(y_test, y_proba, quiet = TRUE) # Dữ liệu cho ggplot
roc_data <- data.frame( FPR = rev(1 - roc_obj$specificities), TPR = rev(roc_obj$sensitivities), Threshold = rev(roc_obj$thresholds)
) ggplot(roc_data, aes(x = FPR, y = TPR)) + geom_line(color = "steelblue", size = 1.2) + geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "gray") + labs( title = "Receiver Operating Characteristic (ROC) Curve", subtitle = paste0("AUC = ", round(auc(roc_obj), 4)), x = "False Positive Rate (FPR)", y = "True Positive Rate (TPR)" ) + theme_minimal()

4.2.1. Đánh Dấu Ngưỡng

# Chọn 5 ngưỡng đại diện
sample_idx <- round(seq(1, nrow(roc_data), length.out = 5))
roc_data$Label <- ifelse(row.names(roc_data) %in% sample_idx, round(roc_data$Thresholdsample_idx, 2), NA) ggplot(roc_data, aes(x = FPR, y = TPR)) + geom_line(color = "steelblue", size = 1.2) + geom_text(aes(label = Label), vjust = -0.5, size = 3, na.rm = TRUE) + geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "gray") + labs( title = "ROC Curve with Threshold Annotations", subtitle = paste0("AUC = ", round(auc(roc_obj), 4)), x = "False Positive Rate (FPR)", y = "True Positive Rate (TPR)" ) + theme_minimal()

5. Phân Tích Kết Quả

5.1. Đọc Đồ Thị ROC

Cách Vẽ Đường Cong Roc
Cách Vẽ Đường Cong Roc
  • Điểm gần góc trái trên (FPR ≈ 0, TPR ≈ 1) → mô hình tốt.
  • Đường chéo (đường 45 độ) → mô hình ngẫu nhiên.
  • Khoảng cách từ đường chéo càng lớn → mô hình càng mạnh.

5.2. Chọn Ngưỡng Tối Ưu

Có nhiều tiêu chí:

  1. Youden’s J statistic:

    J = \text{TPR} – \text{FPR}

    Ngưỡng tối ưu là giá trị cho J lớn nhất.

  2. Cost‑Sensitive: Nếu chi phí FP và FN khác nhau, tối ưu hoá hàm chi phí tổng thể.

  3. Closest to (0,1): Ngưỡng minim hoá khoảng cách Euclid tới điểm (0,1).

# Youden's J trong Python
J = tpr - fpr
ix = np.argmax(J)
optimal_threshold = thresholdsix
print('Optimal threshold (Youden):', optimal_threshold)

5.3. So Sánh Nhiều Mô Hình

Bạn có thể vẽ nhiều đường ROC trên cùng một đồ thị để so sánh:

# Giả sử có 3 mô hình
for name, model in models.items(): y_proba = model.predict_proba(X_test):,1 fpr, tpr, _ = roc_curve(y_test, y_proba) auc_score = auc(fpr, tpr) plt.plot(fpr, tpr, lw=2, label=f'{name} (AUC = {auc_score:.3f})')

6. Những Lưu Ý Thường Gặp

Vấn đề Nguyên nhân Giải pháp
ROC Curve quá “đường thẳng” Dữ liệu mất cân bằng nghiêm trọng (ví dụ 99% lớp âm) Sử dụng Precision‑Recall (PR) curve hoặc balanced sampling
AUC > 1 Nhầm lẫn trong việc truyền y_true và y_score (đảo ngược) Kiểm tra thứ tự tham số của hàm roc_curve
Cạnh tranh giữa TPR và FPR Ngưỡng quá thấp → TPR cao nhưng FPR cũng cao Chọn ngưỡng dựa trên mục tiêu kinh doanh (chi phí FP vs FN)
Không có predict_proba Mô hình chỉ trả về nhãn Dùng decision_function (SVM) hoặc predict + calibrate (Platt scaling)
Đường ROC “cắt” trục Dữ liệu có giá trị dự đoán duy nhất (ví dụ tất cả 0.5) Đảm bảo mô hình học được đặc trưng (có variance)

7. Các Biến Thể và Ứng Dụng Nâng Cao

7.1. ROC Cho Nhiều Lớp (Multiclass)

Có ba cách phổ biến:

  1. One‑vs‑Rest: Vẽ ROC cho mỗi lớp so với các lớp còn lại, sau đó trung bình (macro‑average hoặc micro‑average).
  2. One‑vs‑One: Vẽ ROC cho mỗi cặp lớp.
  3. Probability‑based macro‑average: Trung bình các curve (tích hợp AUC).
from sklearn.metrics import roc_auc_score
roc_auc_ovo = roc_auc_score(y_test, y_proba, multi_class='ovo')
roc_auc_ovr = roc_auc_score(y_test, y_proba, multi_class='ovr')

7.2. Precision‑Recall Curve (PR Curve)

Khi dữ liệu mất cân bằng, PR curve cung cấp thông tin chi tiết hơn:

from sklearn.metrics import precision_recall_curve, average_precision_score precision, recall, pr_thresholds = precision_recall_curve(y_test, y_proba)
ap = average_precision_score(y_test, y_proba)

7.3. Cost‑Sensitive ROC

Nếu chi phí FP (có thể là 10x) và FN (1x) khác nhau, bạn có thể vẽ cost curve hoặc điều chỉnh ngưỡng dựa trên:

\text{Cost} = c_{FP} \times FP + c_{FN} \times FN

7.4. Calibration Curve (Reliability Diagram)

Đôi khi mô hình có AUC cao nhưng không được calibrated (xác suất không phản ánh tần suất thực tế). Sử dụng calibration_curve để kiểm tra và CalibratedClassifierCV để hiệu chỉnh.

8. Thực Hành: Một Dự Án Mini

Bước 1: Tải Dữ Liệu

from sklearn.datasets import load_breast_cancer
data = load_breast_cancer()
X, y = data.data, data.target

Bước 2: Chia Train/Test

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, random_state=42, stratify=y)

Bước 3: Huấn Luyện Logistic Regression

from sklearn.linear_model import LogisticRegression
model = LogisticRegression(max_iter=1000, solver='lbfgs')
model.fit(X_train, y_train)

Bước 4: Dự Đoán Xác Suất và Vẽ ROC

y_proba = model.predict_proba(X_test):,1
fpr, tpr, thresholds = roc_curve(y_test, y_proba)
roc_auc = auc(fpr, tpr) import matplotlib.pyplot as plt
plt.plot(fpr, tpr, label=f'LogReg (AUC = {roc_auc:.3f})')
plt.plot(0,1,0,1,'k--')
plt.xlabel('FPR')
plt.ylabel('TPR')
plt.title('ROC Curve - Breast Cancer')
plt.legend()
plt.show()

Bước 5: Tìm Ngưỡng Tối Ưu

J = tpr - fpr
ix = np.argmax(J)
optimal_thresh = thresholdsix
print(f'Optimal threshold (Youden) = {optimal_thresh:.4f}')

Kết quả thực tế sẽ cho thấy AUC > 0.95, ngưỡng tối ưu khoảng 0.33 (tùy dataset). Bạn có thể tiếp tục thử Random Forest, XGBoost và so sánh.

9. Tổng Kết

  • Đường cong ROC là công cụ mạnh mẽ để đánh giá mô hình phân loại nhị phân ở mọi ngưỡng quyết định.
  • Việc vẽ ROC không chỉ là tạo một hình ảnh đẹp mà còn là quá trình tính toán TPR, FPR, xác định ngưỡng tối ưu, và so sánh AUC giữa các mô hình.
  • Khi dữ liệu mất cân bằng, PR curve hoặc cost‑sensitive ROC có thể cung cấp góc nhìn bổ sung.
  • Thực hành với các thư viện scikit‑learn, matplotlib, seaborn (Python) hoặc pROC, ggplot2 (R) sẽ giúp bạn nhanh chóng tạo ra các biểu đồ chuẩn và hiểu sâu về hiệu suất mô hình.

Hy vọng bài viết này đã cung cấp cho bạn một hướng dẫn toàn diện từ lý thuyết đến thực hành, giúp bạn tự tin vẽ và giải thích đường cong ROC trong bất kỳ dự án học máy nào. Chúc bạn thành công và luôn đạt được AUC cao!

Rate this post
Mục nhập này đã được đăng trong Blog. Đánh dấu trang permalink.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *