packages <- c("readr", "dplyr", "caret", "pROC", "pscl", "MASS", "ggplot2")
new_packages <- packages[!(packages %in% rownames(installed.packages()))]
if (length(new_packages) > 0) install.packages(new_packages)
library(readr)
library(dplyr)
library(caret)
library(pROC)
library(pscl)
library(MASS)
library(ggplot2)Đánh giá mô hình phân loại nhị phân bằng R
Confusion Matrix, ROC/AUC, AIC, BIC và Pseudo R-square
1 1. Mục tiêu phân tích
Bài thực hành này sử dụng bộ dữ liệu Breast Cancer Wisconsin Diagnostic - WDBC. Đây là bộ dữ liệu phân loại nhị phân, tức là biến kết quả chỉ có hai nhóm:
Benign: u lành tính.Malignant: u ác tính.
Trong bài này, ta đặt Malignant là lớp dương. Điều này rất quan trọng vì các chỉ số như Sensitivity/Recall và Specificity luôn phụ thuộc vào việc ta chọn nhóm nào là lớp dương.
Mục tiêu phân tích gồm ba phần lớn:
- Xây dựng mô hình phân loại bằng hồi quy logistic.
- Đánh giá khả năng dự báo bằng Confusion Matrix, Accuracy, Sensitivity, Specificity, ROC Curve và AUC.
- So sánh, lựa chọn mô hình bằng AIC, BIC và Pseudo R-square.
1.1 Giải thích bản chất
Ta không chỉ cần biết mô hình dự đoán đúng hay sai. Ta cần biết mô hình sai theo kiểu nào.
Ví dụ trong bối cảnh y tế, nếu bệnh nhân thật sự bị u ác tính nhưng mô hình dự đoán là u lành tính thì đó là lỗi nghiêm trọng. Vì vậy, ngoài Accuracy, ta bắt buộc phải xem thêm Sensitivity/Recall.
2 2. Cài và nạp package
2.1 Giải thích
Đoạn code này dùng để kiểm tra xem máy đã có đủ package cần thiết chưa. Nếu thiếu package nào thì R sẽ tự cài package đó.
Ý nghĩa từng package:
readr: đọc dữ liệu từ đường link online.dplyr: xử lý, biến đổi dữ liệu.caret: chia dữ liệu train/test và tính ma trận nhầm lẫn.pROC: vẽ ROC Curve và tính AUC.pscl: tính Pseudo R-square cho mô hình logistic.MASS: dùng hàmstepAIC()để lựa chọn biến theo AIC hoặc BIC.ggplot2: hỗ trợ vẽ biểu đồ nếu cần mở rộng.
2.2 Vì sao cần làm bước này?
Trong R, mỗi nhóm công việc thường cần một package riêng. Nếu không nạp package, các hàm như read_csv(), confusionMatrix(), roc() hoặc stepAIC() sẽ không chạy được.
3 3. Đọc dữ liệu online
url <- "https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data"
feature_base <- c(
"radius", "texture", "perimeter", "area", "smoothness",
"compactness", "concavity", "concave_points", "symmetry",
"fractal_dimension"
)
var_names <- c(
"id", "diagnosis",
paste0(feature_base, "_mean"),
paste0(feature_base, "_se"),
paste0(feature_base, "_worst")
)
data_raw <- read_csv(url, col_names = var_names, show_col_types = FALSE)
data <- data_raw %>%
mutate(
diagnosis = factor(
ifelse(diagnosis == "M", "Malignant", "Benign"),
levels = c("Benign", "Malignant")
),
y = ifelse(diagnosis == "Malignant", 1, 0)
)
dim(data_raw)[1] 569 32
table(data$diagnosis)
Benign Malignant
357 212
3.1 Giải thích
Bước này đọc dữ liệu trực tiếp từ đường link online. Bộ dữ liệu gốc không có tên cột, nên ta phải tự đặt tên cột bằng var_names.
Trong dữ liệu gốc:
Mnghĩa làMalignant, tức u ác tính.Bnghĩa làBenign, tức u lành tính.
Ta chuyển M thành Malignant, B thành Benign để kết quả dễ đọc hơn.
Sau đó, ta tạo thêm biến y:
y = 1nếu làMalignant.y = 0nếu làBenign.
3.2 Vì sao cần tạo biến y?
Mô hình hồi quy logistic trong R có thể chạy với biến nhị phân dạng 0/1. Vì vậy, ta mã hóa biến chẩn đoán thành y để mô hình hiểu rằng đây là bài toán dự báo xác suất xảy ra biến cố.
Ở đây, biến cố là:
Bệnh nhân thuộc nhóm u ác tính.
Nói cách khác, mô hình sẽ ước lượng xác suất:
[ P(y = 1) = P() ]
3.3 Cách đọc kết quả
Lệnh:
id="u08ij3"
dim(data_raw)cho biết dữ liệu có bao nhiêu dòng và bao nhiêu cột.
Lệnh:
id="xovput"
table(data$diagnosis)cho biết số quan sát thuộc nhóm Benign và số quan sát thuộc nhóm Malignant.
Nếu hai nhóm quá lệch nhau, ví dụ 95% là Benign và 5% là Malignant, thì Accuracy có thể gây hiểu nhầm. Khi đó ta càng cần xem thêm Sensitivity và Specificity.
4 4. Chọn biến đầu vào và chia train/test
predictor_vars <- paste0(feature_base, "_mean")
set.seed(123)
train_index <- createDataPartition(data$diagnosis, p = 0.70, list = FALSE)
train <- data[train_index, ]
test <- data[-train_index, ]
nrow(train)[1] 399
nrow(test)[1] 170
prop.table(table(train$diagnosis))
Benign Malignant
0.6265664 0.3734336
prop.table(table(test$diagnosis))
Benign Malignant
0.6294118 0.3705882
4.1 Giải thích
Trong bộ dữ liệu WDBC, mỗi đặc trưng có ba nhóm đo lường:
_mean: giá trị trung bình._se: sai số chuẩn._worst: giá trị nghiêm trọng nhất hoặc lớn nhất.
Ở đây ta chọn nhóm biến _mean để mô hình vừa đủ mạnh nhưng vẫn dễ giải thích. Nếu đưa cả 30 biến vào ngay từ đầu, mô hình có thể phức tạp, khó diễn giải và dễ gặp vấn đề tương quan mạnh giữa các biến.
Dòng:
id="jw3if2"
set.seed(123)giúp kết quả chia dữ liệu có thể lặp lại. Nếu không đặt set.seed(), mỗi lần chạy R có thể chia train/test khác nhau, làm kết quả thay đổi.
Ta chia dữ liệu thành:
train: 70% dữ liệu dùng để huấn luyện mô hình.test: 30% dữ liệu dùng để kiểm tra mô hình.
4.2 Vì sao phải chia train/test?
Nếu ta huấn luyện và đánh giá mô hình trên cùng một tập dữ liệu, kết quả thường quá lạc quan. Mô hình có thể học rất tốt dữ liệu đã thấy, nhưng chưa chắc dự đoán tốt dữ liệu mới.
Vì vậy:
- Tập
traindùng để học quy luật. - Tập
testdùng để kiểm tra khả năng dự báo trên dữ liệu mới.
4.3 Cách đọc kết quả
Hai dòng:
id="8yj8ud"
prop.table(table(train$diagnosis))
prop.table(table(test$diagnosis))cho biết tỷ lệ Benign và Malignant trong tập train và test.
Nếu tỷ lệ hai nhóm trong train và test gần giống nhau thì cách chia dữ liệu là hợp lý. Hàm createDataPartition() của caret giúp giữ tỷ lệ nhóm tương đối cân bằng giữa train và test.
5 5. Chuẩn hóa dữ liệu
center_values <- sapply(train[predictor_vars], mean)
scale_values <- sapply(train[predictor_vars], sd)
train_scaled <- train
test_scaled <- test
train_scaled[predictor_vars] <- as.data.frame(
scale(train[predictor_vars], center = center_values, scale = scale_values)
)
test_scaled[predictor_vars] <- as.data.frame(
scale(test[predictor_vars], center = center_values, scale = scale_values)
)
train_model <- train_scaled %>% dplyr::select(y, all_of(predictor_vars))
test_model <- test_scaled %>% dplyr::select(y, diagnosis, all_of(predictor_vars))
summary(train_model) y radius_mean texture_mean perimeter_mean
Min. :0.0000 Min. :-2.0283 Min. :-2.0178 Min. :-1.9854
1st Qu.:0.0000 1st Qu.:-0.6949 1st Qu.:-0.7204 1st Qu.:-0.6934
Median :0.0000 Median :-0.2105 Median :-0.1176 Median :-0.2188
Mean :0.3734 Mean : 0.0000 Mean : 0.0000 Mean : 0.0000
3rd Qu.:1.0000 3rd Qu.: 0.5053 3rd Qu.: 0.6259 3rd Qu.: 0.5240
Max. :1.0000 Max. : 3.9738 Max. : 4.7998 Max. : 3.9862
area_mean smoothness_mean compactness_mean concavity_mean
Min. :-1.4604 Min. :-2.231652 Min. :-1.4677 Min. :-1.1183
1st Qu.:-0.6780 1st Qu.:-0.703782 1st Qu.:-0.7650 1st Qu.:-0.7521
Median :-0.2932 Median :-0.007494 Median :-0.2287 Median :-0.3698
Mean : 0.0000 Mean : 0.000000 Mean : 0.0000 Mean : 0.0000
3rd Qu.: 0.3915 3rd Qu.: 0.577415 3rd Qu.: 0.4922 3rd Qu.: 0.5594
Max. : 5.2847 Max. : 4.540585 Max. : 4.5479 Max. : 4.3309
concave_points_mean symmetry_mean fractal_dimension_mean
Min. :-1.2589 Min. :-2.6782 Min. :-1.8074
1st Qu.:-0.7359 1st Qu.:-0.6878 1st Qu.:-0.6932
Median :-0.4186 Median :-0.0695 Median :-0.1603
Mean : 0.0000 Mean : 0.0000 Mean : 0.0000
3rd Qu.: 0.6855 3rd Qu.: 0.5310 3rd Qu.: 0.5013
Max. : 3.9226 Max. : 4.3782 Max. : 4.9893
5.1 Giải thích
Chuẩn hóa dữ liệu nghĩa là đưa các biến định lượng về cùng một thang đo. Sau chuẩn hóa, mỗi biến thường có:
- Trung bình xấp xỉ 0.
- Độ lệch chuẩn xấp xỉ 1.
Công thức chuẩn hóa là:
[ z = ]
Trong đó:
- (x): giá trị ban đầu.
- ({x}): trung bình của biến.
- (s): độ lệch chuẩn của biến.
- (z): giá trị sau chuẩn hóa.
5.2 Vì sao cần chuẩn hóa?
Các biến trong dữ liệu có đơn vị và độ lớn rất khác nhau. Ví dụ:
area_meancó thể có giá trị rất lớn.smoothness_meancó thể có giá trị rất nhỏ.
Nếu không chuẩn hóa, các biến có thang đo lớn dễ gây ảnh hưởng mạnh trong quá trình ước lượng, đặc biệt khi ta so sánh hệ số hoặc lựa chọn biến.
5.3 Vì sao dùng trung bình và độ lệch chuẩn của tập train để chuẩn hóa cả test?
Đây là điểm rất quan trọng.
Ta chỉ được phép học thông tin từ tập train. Tập test phải được xem như dữ liệu mới, chưa từng biết trước.
Vì vậy:
- Trung bình và độ lệch chuẩn được tính từ
train. - Sau đó áp dụng chính các giá trị đó để chuẩn hóa
test.
Nếu ta tính trung bình và độ lệch chuẩn từ toàn bộ dữ liệu trước khi chia train/test, mô hình đã vô tình nhìn thấy thông tin từ tập test. Đây gọi là data leakage, tức rò rỉ dữ liệu.
5.4 Cách đọc kết quả
Lệnh:
id="h2v0r1"
summary(train_model)cho ta xem phân bố của các biến sau chuẩn hóa. Các biến đầu vào thường sẽ có giá trị quanh 0. Nếu có biến nào quá bất thường, ta cần kiểm tra lại dữ liệu.
6 6. Xây dựng mô hình hồi quy logistic và lựa chọn biến
model_full <- glm(y ~ ., data = train_model, family = binomial(link = "logit"))
model_aic <- MASS::stepAIC(model_full, direction = "both", trace = FALSE)
model_bic <- MASS::stepAIC(
model_full,
direction = "both",
k = log(nrow(train_model)),
trace = FALSE
)
formula(model_full)y ~ radius_mean + texture_mean + perimeter_mean + area_mean +
smoothness_mean + compactness_mean + concavity_mean + concave_points_mean +
symmetry_mean + fractal_dimension_mean
formula(model_aic)y ~ texture_mean + perimeter_mean + area_mean + smoothness_mean +
concavity_mean + symmetry_mean
formula(model_bic)y ~ texture_mean + area_mean + smoothness_mean + concavity_mean +
symmetry_mean
6.1 Giải thích
Ở bước này, ta xây dựng ba mô hình:
model_full: mô hình đầy đủ, sử dụng tất cả biến_meanđã chọn.model_aic: mô hình được chọn biến theo tiêu chuẩn AIC.model_bic: mô hình được chọn biến theo tiêu chuẩn BIC.
Mô hình hồi quy logistic được dùng vì biến phụ thuộc y chỉ có hai giá trị: 0 và 1.
Mô hình logistic không dự báo trực tiếp nhãn Benign hay Malignant. Nó dự báo xác suất bệnh nhân thuộc nhóm Malignant:
[ P(y = 1) ]
Sau đó, ta dùng một ngưỡng phân loại, thường là 0.5:
- Nếu xác suất ≥ 0.5, dự đoán là
Malignant. - Nếu xác suất < 0.5, dự đoán là
Benign.
6.2 Bản chất của hồi quy logistic
Hồi quy tuyến tính thông thường có thể cho kết quả nhỏ hơn 0 hoặc lớn hơn 1, nên không phù hợp để dự báo xác suất.
Hồi quy logistic dùng hàm logit:
[ () = _0 + _1X_1 + _2X_2 + … + _kX_k ]
Trong đó:
- (p): xác suất thuộc nhóm
Malignant. - (): odds, tức tỷ số giữa khả năng xảy ra và không xảy ra biến cố.
- (_j): hệ số của biến độc lập.
Nếu hệ số (_j > 0), khi biến đó tăng thì xác suất thuộc nhóm Malignant có xu hướng tăng.
Nếu hệ số (_j < 0), khi biến đó tăng thì xác suất thuộc nhóm Malignant có xu hướng giảm.
6.3 Vì sao cần lựa chọn biến?
Không phải cứ đưa nhiều biến vào mô hình là tốt. Mô hình quá nhiều biến có thể:
- Khó giải thích.
- Dễ bị nhiễu.
- Dự báo kém trên dữ liệu mới.
- Có thể bị đa cộng tuyến nếu các biến liên hệ mạnh với nhau.
Vì vậy, ta dùng AIC và BIC để tìm mô hình cân bằng giữa:
- Độ phù hợp với dữ liệu.
- Độ đơn giản của mô hình.
6.4 Cách đọc kết quả
Ba dòng:
id="bbv26i"
formula(model_full)
formula(model_aic)
formula(model_bic)cho biết mỗi mô hình giữ lại những biến nào.
Nếu model_bic có ít biến hơn model_aic, điều đó là bình thường vì BIC phạt mô hình phức tạp mạnh hơn AIC.
7 7. AIC, BIC và Pseudo R-square
pseudo_r2_table <- function(model) {
r2 <- pscl::pR2(model)
tibble(
McFadden = unname(r2["McFadden"]),
Cox_Snell = unname(r2["r2ML"]),
Nagelkerke = unname(r2["r2CU"])
)
}
model_summary <- bind_rows(
tibble(
Model = "Full model",
AIC = AIC(model_full),
BIC = BIC(model_full),
Variables = paste(attr(terms(model_full), "term.labels"), collapse = ", ")
) %>% bind_cols(pseudo_r2_table(model_full)),
tibble(
Model = "Stepwise AIC",
AIC = AIC(model_aic),
BIC = BIC(model_aic),
Variables = paste(attr(terms(model_aic), "term.labels"), collapse = ", ")
) %>% bind_cols(pseudo_r2_table(model_aic)),
tibble(
Model = "Stepwise BIC",
AIC = AIC(model_bic),
BIC = BIC(model_bic),
Variables = paste(attr(terms(model_bic), "term.labels"), collapse = ", ")
) %>% bind_cols(pseudo_r2_table(model_bic))
)fitting null model for pseudo-r2
fitting null model for pseudo-r2
fitting null model for pseudo-r2
model_summary# A tibble: 3 × 7
Model AIC BIC Variables McFadden Cox_Snell Nagelkerke
<chr> <dbl> <dbl> <chr> <dbl> <dbl> <dbl>
1 Full model 119. 163. radius_mean, texture_m… 0.816 0.660 0.900
2 Stepwise AIC 113. 141. texture_mean, perimete… 0.812 0.658 0.897
3 Stepwise BIC 114. 138. texture_mean, area_mea… 0.806 0.655 0.893
7.1 Giải thích
Bảng model_summary dùng để so sánh ba mô hình theo các tiêu chí:
- AIC.
- BIC.
- McFadden Pseudo R-square.
- Cox & Snell Pseudo R-square.
- Nagelkerke Pseudo R-square.
- Danh sách biến được giữ lại trong mô hình.
7.2 Bản chất của AIC và BIC
AIC và BIC đều dùng để so sánh mô hình. Cả hai đều có cùng tư tưởng:
Mô hình tốt là mô hình vừa khớp dữ liệu tốt, vừa không quá phức tạp.
AIC có dạng tổng quát:
[ AIC = -2(L) + 2k ]
BIC có dạng tổng quát:
[ BIC = -2(L) + k(n) ]
Trong đó:
- (L): likelihood, tức mức độ mô hình phù hợp với dữ liệu.
- (k): số tham số trong mô hình.
- (n): số quan sát.
AIC và BIC càng thấp càng tốt.
BIC thường phạt số biến mạnh hơn AIC, đặc biệt khi cỡ mẫu lớn. Vì vậy, BIC thường chọn mô hình gọn hơn.
7.3 Bản chất của Pseudo R-square
Trong hồi quy tuyến tính, R-square cho biết mô hình giải thích được bao nhiêu phần trăm biến thiên của biến phụ thuộc.
Nhưng trong hồi quy logistic, biến phụ thuộc chỉ là 0/1, nên không dùng R-square truyền thống theo cùng một nghĩa được. Vì vậy ta dùng Pseudo R-square.
Các chỉ số trong bảng gồm:
McFadden: thường được dùng nhiều trong logistic regression. Giá trị càng cao càng tốt.Cox_Snell: đo mức cải thiện của mô hình so với mô hình rỗng.Nagelkerke: phiên bản điều chỉnh của Cox & Snell để dễ diễn giải hơn vì có thể tiến gần 1.
7.4 Cách đọc kết quả
Khi bảng hiện ra, ta đọc như sau:
- Mô hình nào có AIC thấp nhất thì tốt nhất theo tiêu chuẩn AIC.
- Mô hình nào có BIC thấp nhất thì tốt nhất theo tiêu chuẩn BIC.
- Mô hình nào có Pseudo R-square cao hơn thì cải thiện tốt hơn so với mô hình rỗng.
- Nếu hai mô hình có kết quả gần nhau, nên ưu tiên mô hình ít biến hơn để dễ giải thích.
8 8. Tự động xác định mô hình tốt theo AIC và BIC
best_by_aic <- model_summary %>% dplyr::slice_min(AIC, n = 1)
best_by_bic <- model_summary %>% dplyr::slice_min(BIC, n = 1)
best_by_aic# A tibble: 1 × 7
Model AIC BIC Variables McFadden Cox_Snell Nagelkerke
<chr> <dbl> <dbl> <chr> <dbl> <dbl> <dbl>
1 Stepwise AIC 113. 141. texture_mean, perimete… 0.812 0.658 0.897
best_by_bic# A tibble: 1 × 7
Model AIC BIC Variables McFadden Cox_Snell Nagelkerke
<chr> <dbl> <dbl> <chr> <dbl> <dbl> <dbl>
1 Stepwise BIC 114. 138. texture_mean, area_mea… 0.806 0.655 0.893
8.1 Giải thích
Đoạn code này tự động tìm mô hình có AIC thấp nhất và mô hình có BIC thấp nhất.
8.2 Cách đọc kết quả
Nếu best_by_aic là Stepwise AIC, nghĩa là mô hình được chọn biến theo AIC đang cân bằng tốt nhất giữa độ khớp và độ phức tạp theo tiêu chuẩn AIC.
Nếu best_by_bic là Stepwise BIC, nghĩa là mô hình được chọn biến theo BIC đang được ưu tiên theo hướng gọn hơn.
Trong nhiều bài thực hành, ta thường chọn mô hình theo BIC nếu muốn mô hình dễ giải thích, ít biến hơn. Ta chọn theo AIC nếu muốn ưu tiên khả năng dự báo và chấp nhận mô hình có thể nhiều biến hơn.
9 9. Ma trận nhầm lẫn, Accuracy, Sensitivity, Specificity và AUC
evaluate_model <- function(model, test_data, cutoff = 0.50) {
prob <- predict(model, newdata = test_data, type = "response")
pred_class <- factor(
ifelse(prob >= cutoff, "Malignant", "Benign"),
levels = c("Benign", "Malignant")
)
truth <- factor(
ifelse(test_data$y == 1, "Malignant", "Benign"),
levels = c("Benign", "Malignant")
)
cm <- caret::confusionMatrix(
data = pred_class,
reference = truth,
positive = "Malignant"
)
roc_obj <- pROC::roc(
response = truth,
predictor = prob,
levels = c("Benign", "Malignant"),
direction = "<"
)
metrics <- tibble(
Accuracy = unname(cm$overall["Accuracy"]),
Sensitivity_Recall = unname(cm$byClass["Sensitivity"]),
Specificity = unname(cm$byClass["Specificity"]),
AUC = as.numeric(pROC::auc(roc_obj))
)
list(
confusion_matrix = cm$table,
metrics = metrics,
roc = roc_obj,
probability = prob,
prediction = pred_class,
truth = truth
)
}
eval_full <- evaluate_model(model_full, test_model)
eval_aic <- evaluate_model(model_aic, test_model)
eval_bic <- evaluate_model(model_bic, test_model)
eval_full$confusion_matrix Reference
Prediction Benign Malignant
Benign 101 4
Malignant 6 59
eval_full$metrics# A tibble: 1 × 4
Accuracy Sensitivity_Recall Specificity AUC
<dbl> <dbl> <dbl> <dbl>
1 0.941 0.937 0.944 0.979
eval_aic$confusion_matrix Reference
Prediction Benign Malignant
Benign 100 6
Malignant 7 57
eval_aic$metrics# A tibble: 1 × 4
Accuracy Sensitivity_Recall Specificity AUC
<dbl> <dbl> <dbl> <dbl>
1 0.924 0.905 0.935 0.976
eval_bic$confusion_matrix Reference
Prediction Benign Malignant
Benign 101 6
Malignant 6 57
eval_bic$metrics# A tibble: 1 × 4
Accuracy Sensitivity_Recall Specificity AUC
<dbl> <dbl> <dbl> <dbl>
1 0.929 0.905 0.944 0.977
9.1 Giải thích
Hàm evaluate_model() dùng để đánh giá một mô hình trên tập test.
Bên trong hàm có các bước:
- Dự báo xác suất bằng
predict(..., type = "response"). - Chuyển xác suất thành nhãn dự báo bằng ngưỡng 0.5.
- So sánh nhãn dự báo với nhãn thực tế.
- Tạo ma trận nhầm lẫn.
- Tính Accuracy, Sensitivity, Specificity.
- Tạo ROC object và tính AUC.
9.2 Bản chất của xác suất dự báo
Dòng:
id="fpdu1m"
prob <- predict(model, newdata = test_data, type = "response")trả về xác suất một quan sát thuộc nhóm Malignant.
Ví dụ:
- Nếu
prob = 0.90, mô hình cho rằng xác suất u ác tính là 90%. - Nếu
prob = 0.20, mô hình cho rằng xác suất u ác tính là 20%.
Sau đó ta dùng ngưỡng 0.5:
prob >= 0.5: dự đoánMalignant.prob < 0.5: dự đoánBenign.
9.3 Bản chất của Confusion Matrix
Ma trận nhầm lẫn so sánh giữa:
- Nhãn mô hình dự đoán.
- Nhãn thực tế.
Vì ta chọn Malignant là lớp dương, nên có bốn trường hợp:
| Trường hợp | Ý nghĩa |
|---|---|
| True Positive, TP | Thực tế là Malignant, mô hình dự đoán đúng là Malignant |
| False Negative, FN | Thực tế là Malignant, nhưng mô hình dự đoán sai là Benign |
| True Negative, TN | Thực tế là Benign, mô hình dự đoán đúng là Benign |
| False Positive, FP | Thực tế là Benign, nhưng mô hình dự đoán sai là Malignant |
Trong bài toán y tế, False Negative thường rất nguy hiểm vì mô hình bỏ sót ca ác tính.
9.4 Công thức các chỉ số
Accuracy:
[ Accuracy = ]
Accuracy cho biết tỷ lệ dự đoán đúng trên toàn bộ tập test.
Sensitivity/Recall:
[ Sensitivity = Recall = ]
Sensitivity cho biết trong tất cả ca thật sự ác tính, mô hình phát hiện đúng được bao nhiêu ca.
Specificity:
[ Specificity = ]
Specificity cho biết trong tất cả ca thật sự lành tính, mô hình nhận diện đúng được bao nhiêu ca.
9.5 Cách đọc kết quả
Nếu kết quả cho thấy:
Accuracycao: mô hình dự đoán đúng nhiều quan sát nói chung.Sensitivity_Recallcao: mô hình ít bỏ sót caMalignant.Specificitycao: mô hình ít báo nhầm caBenignthànhMalignant.AUCcao: mô hình phân biệt tốt giữa hai nhóm.
Trong bối cảnh y tế, ta thường ưu tiên Sensitivity/Recall hơn Accuracy, vì bỏ sót u ác tính có thể nguy hiểm hơn việc cảnh báo nhầm.
10 10. So sánh chỉ số đánh giá trên tập test
eval_table <- bind_rows(
tibble(Model = "Full model") %>% bind_cols(eval_full$metrics),
tibble(Model = "Stepwise AIC") %>% bind_cols(eval_aic$metrics),
tibble(Model = "Stepwise BIC") %>% bind_cols(eval_bic$metrics)
)
eval_table# A tibble: 3 × 5
Model Accuracy Sensitivity_Recall Specificity AUC
<chr> <dbl> <dbl> <dbl> <dbl>
1 Full model 0.941 0.937 0.944 0.979
2 Stepwise AIC 0.924 0.905 0.935 0.976
3 Stepwise BIC 0.929 0.905 0.944 0.977
10.1 Giải thích
Bảng eval_table gom các chỉ số đánh giá của cả ba mô hình vào cùng một bảng để dễ so sánh.
10.2 Cách đọc kết quả
Khi chọn mô hình cuối cùng, không nên chỉ nhìn một chỉ số duy nhất. Ta nên đọc theo thứ tự:
- Mô hình có
Sensitivity_Recallcó đủ cao không? - Mô hình có
AUCcao không? - Mô hình có
AccuracyvàSpecificityổn không? - Mô hình có quá nhiều biến không?
- AIC/BIC của mô hình có tốt không?
Nếu một mô hình có AUC rất cao nhưng giữ quá nhiều biến, còn mô hình khác có AUC gần tương đương nhưng ít biến hơn, ta thường ưu tiên mô hình ít biến hơn.
11 11. ROC Curve
plot(eval_bic$roc, main = "ROC Curve - Logistic Regression, Stepwise BIC")
auc_value <- as.numeric(pROC::auc(eval_bic$roc))
legend("bottomright", legend = paste("AUC =", round(auc_value, 4)), bty = "n")11.1 Giải thích
ROC Curve là đường cong thể hiện khả năng phân biệt hai nhóm của mô hình khi thay đổi ngưỡng phân loại.
Ở các phần trước, ta dùng ngưỡng 0.5. Nhưng thực tế, ta có thể thay đổi ngưỡng này:
- Ngưỡng thấp hơn, ví dụ 0.3: mô hình dễ dự đoán
Malignanthơn, Sensitivity có thể tăng nhưng False Positive cũng có thể tăng. - Ngưỡng cao hơn, ví dụ 0.7: mô hình thận trọng hơn khi dự đoán
Malignant, Specificity có thể tăng nhưng Sensitivity có thể giảm.
ROC Curve cho ta cái nhìn tổng quát về mô hình ở nhiều ngưỡng khác nhau, không chỉ riêng ngưỡng 0.5.
11.2 Bản chất của AUC
AUC là diện tích dưới đường ROC.
Có thể hiểu đơn giản:
AUC đo khả năng mô hình xếp một ca ác tính có xác suất cao hơn một ca lành tính.
Cách diễn giải thường dùng:
| AUC | Ý nghĩa tương đối |
|---|---|
| 0.5 | Mô hình gần như đoán ngẫu nhiên |
| 0.6 - 0.7 | Khả năng phân biệt yếu |
| 0.7 - 0.8 | Khả năng phân biệt chấp nhận được |
| 0.8 - 0.9 | Khả năng phân biệt tốt |
| > 0.9 | Khả năng phân biệt rất tốt |
11.3 Cách đọc kết quả
Nếu đường ROC càng áp sát góc trên bên trái thì mô hình càng tốt.
Nếu AUC càng gần 1 thì mô hình càng có khả năng phân biệt tốt giữa Malignant và Benign.
12 12. Kiểm tra tác động của việc thay đổi ngưỡng phân loại
eval_bic_cutoff_03 <- evaluate_model(model_bic, test_model, cutoff = 0.30)
eval_bic_cutoff_05 <- evaluate_model(model_bic, test_model, cutoff = 0.50)
eval_bic_cutoff_07 <- evaluate_model(model_bic, test_model, cutoff = 0.70)
cutoff_table <- bind_rows(
tibble(Cutoff = 0.30) %>% bind_cols(eval_bic_cutoff_03$metrics),
tibble(Cutoff = 0.50) %>% bind_cols(eval_bic_cutoff_05$metrics),
tibble(Cutoff = 0.70) %>% bind_cols(eval_bic_cutoff_07$metrics)
)
cutoff_table# A tibble: 3 × 5
Cutoff Accuracy Sensitivity_Recall Specificity AUC
<dbl> <dbl> <dbl> <dbl> <dbl>
1 0.3 0.906 0.952 0.879 0.977
2 0.5 0.929 0.905 0.944 0.977
3 0.7 0.929 0.857 0.972 0.977
12.1 Giải thích
Đây là bước mở rộng rất quan trọng để hiểu bản chất phân loại.
Mô hình logistic trả về xác suất, còn nhãn phân loại phụ thuộc vào ngưỡng. Vì vậy, cùng một mô hình nhưng nếu đổi ngưỡng, Confusion Matrix có thể thay đổi.
12.2 Cách đọc kết quả
Nếu giảm cutoff từ 0.5 xuống 0.3:
- Mô hình dễ dự đoán
Malignanthơn. - Sensitivity thường tăng.
- Specificity có thể giảm.
Nếu tăng cutoff từ 0.5 lên 0.7:
- Mô hình khó dự đoán
Malignanthơn. - Specificity thường tăng.
- Sensitivity có thể giảm.
Trong bài toán y tế, nếu mục tiêu là không bỏ sót ca ác tính, ta có thể cân nhắc dùng ngưỡng thấp hơn 0.5. Tuy nhiên, điều này có thể làm tăng số ca báo động giả.
13 13. Gợi ý viết kết luận cuối bài
Sau khi chạy toàn bộ code, có thể viết kết luận theo mẫu sau. Cần thay các phần trong ngoặc vuông bằng kết quả thực tế sau khi chạy R.
Bộ dữ liệu WDBC được sử dụng để xây dựng mô hình phân loại nhị phân giữa hai nhóm u lành tính và u ác tính. Mô hình hồi quy logistic được xây dựng trên tập huấn luyện 70% và đánh giá trên tập kiểm tra 30%.
Kết quả so sánh AIC và BIC cho thấy mô hình [tên mô hình] có chỉ số [AIC/BIC] thấp nhất, cho thấy mô hình này đạt sự cân bằng tốt giữa độ phù hợp và độ phức tạp. Các chỉ số Pseudo R-square cũng cho thấy mô hình cải thiện rõ rệt so với mô hình rỗng.
Trên tập test, mô hình đạt Accuracy = [giá trị], Sensitivity/Recall = [giá trị], Specificity = [giá trị] và AUC = [giá trị]. Vì
Malignantđược chọn là lớp dương, Sensitivity/Recall phản ánh khả năng phát hiện đúng các ca u ác tính. Đây là chỉ số đặc biệt quan trọng trong bối cảnh y tế vì bỏ sót ca ác tính có thể gây hậu quả nghiêm trọng.Nhìn chung, mô hình có khả năng phân biệt tốt giữa hai nhóm
BenignvàMalignant. Nếu ưu tiên diễn giải và mô hình gọn, có thể chọn mô hình theo BIC. Nếu ưu tiên khả năng dự báo và chấp nhận nhiều biến hơn, có thể cân nhắc mô hình theo AIC.
14 14. Tóm tắt bản chất các chỉ số
| Nhóm chỉ số | Chỉ số | Ý nghĩa | Cách đánh giá |
|---|---|---|---|
| Confusion Matrix | Accuracy | Tỷ lệ dự đoán đúng toàn bộ | Càng cao càng tốt, nhưng dễ gây hiểu nhầm nếu lệch lớp |
| Confusion Matrix | Sensitivity/Recall | Tỷ lệ phát hiện đúng ca Malignant |
Rất quan trọng nếu sợ bỏ sót ca bệnh |
| Confusion Matrix | Specificity | Tỷ lệ nhận diện đúng ca Benign |
Quan trọng nếu muốn giảm báo động giả |
| ROC/AUC | ROC Curve | Đánh giá mô hình ở nhiều ngưỡng phân loại | Đường càng gần góc trên trái càng tốt |
| ROC/AUC | AUC | Khả năng phân biệt hai nhóm | Càng gần 1 càng tốt |
| Model Selection | AIC | So sánh mô hình, có phạt số biến | Càng thấp càng tốt |
| Model Selection | BIC | So sánh mô hình, phạt số biến mạnh hơn AIC | Càng thấp càng tốt |
| Pseudo R-square | McFadden, Cox & Snell, Nagelkerke | Mức cải thiện so với mô hình rỗng | Càng cao càng tốt, nhưng không hiểu giống hệt R-square tuyến tính |