DS

[Tech Blog #30 | Data Science] K-Fold Cross-Validation & GridSearchCV: Tối Ưu Hóa Siêu Tham Số Chuẩn Chuyên Nghiệp

0 views
[Tech Blog #30 | Data Science] K-Fold Cross-Validation & GridSearchCV: Tối Ưu Hóa Siêu Tham Số Chuẩn Chuyên Nghiệp

1. Đặt vấn đề: Cái bẫy của một lần chia Train/Test "ăn may"

Khi mới học Machine Learning, quy trình quen thuộc của hầu hết mọi người là:

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model.fit(X_train, y_train)
print(model.score(X_test, y_test)) # Ra kết quả 91%

Bạn vui mừng đem mô hình đi báo cáo. Nhưng khi đổi sang random_state=100 và chạy lại, độ chính xác bất ngờ tụt dốc thảm hại xuống còn 76%!
Tại sao lại có sự chênh lệch khủng khiếp này?

Nguyên nhân là: Một lần bốc thăm ngẫu nhiên duy nhất hoàn toàn có thể "vô tình" gom toàn bộ những mẫu dữ liệu dễ đoán nhất vào tập Test.
Độ chính xác 91% ban đầu chỉ là một cú "ăn may" ngẫu nhiên của thuật toán bốc thăm.

Để đánh giá một mô hình khách quan 100%, không phụ thuộc vào may rủi, các Data Scientist chuyên nghiệp bắt buộc phải sử dụng kỹ thuật K-Fold Cross-Validation (Kiểm định chéo K-lần) kết hợp cùng GridSearchCV (Dò tìm siêu tham số).


2. Giải mã K-Fold Cross-Validation: Xoay vòng kiểm thử

Ý tưởng của K-Fold Cross-Validation giống như việc một học sinh làm 5 đề thi thử khác nhau, lấy điểm trung bình để phản ánh đúng thực lực thay vì chỉ làm 1 đề duy nhất:

TẬP DỮ LIỆU BAN ĐẦU ĐƯỢC CHIA THÀNH K = 5 PHẦN (FOLDS) BẰNG NHAU:

Lần 1: [ Fold 1: TEST ] [ Fold 2: Train ] [ Fold 3: Train ] [ Fold 4: Train ] [ Fold 5: Train ] ──► Điểm Score 1 = 85%
Lần 2: [ Fold 1: Train ] [ Fold 2: TEST ] [ Fold 3: Train ] [ Fold 4: Train ] [ Fold 5: Train ] ──► Điểm Score 2 = 82%
Lần 3: [ Fold 1: Train ] [ Fold 2: Train ] [ Fold 3: TEST ] [ Fold 4: Train ] [ Fold 5: Train ] ──► Điểm Score 3 = 88%
Lần 4: [ Fold 1: Train ] [ Fold 2: Train ] [ Fold 3: Train ] [ Fold 4: TEST ] [ Fold 5: Train ] ──► Điểm Score 4 = 84%
Lần 5: [ Fold 1: Train ] [ Fold 2: Train ] [ Fold 3: Train ] [ Fold 4: Train ] [ Fold 5: TEST ] ──► Điểm Score 5 = 86%

===> ĐIỂM SỐ ĐÁNH GIÁ CHÍNH THỨC = TRUNG BÌNH CỘNG (85% ± 2.1%)

Biến thể Stratified K-Fold (Bắt buộc cho bài toán Phân loại):

Nếu dữ liệu của bạn bị mất cân bằng (ví dụ: 90% Không gian lận, 10% Gian lận), K-Fold thông thường có thể vô tình tạo ra một Fold chứa 0% ca gian lận!
Stratified K-Fold đảm bảo mỗi Fold đều giữ nguyên vẹn tỷ lệ phân bố nhãn (10% - 90%) giống hệt như tập dữ liệu gốc.


3. Phân biệt: Parameters vs. Hyperparameters

Khái niệmParameters (Tham số nội tại)Hyperparameters (Siêu tham số)
Bản chấtLà các con số mà mô hình tự học được từ dữ liệu.Là các "nút vặn" cấu hình do kỹ sư dữ liệu tự tay cài đặt trước.
Cách xác địnhThuật toán tự động tối ưu qua hàm mất mát (Gradient Descent / OLS).Con người phải thử nghiệm nhiều giá trị khác nhau để chọn ra cấu hình tốt nhất.
Ví dụ thực tế- Hệ số góc ww và bias bb trong Hồi quy ([Tech Blog #06]).<br>- Điểm ngưỡng rẽ nhánh trong Cây ([Tech Blog #14]).- Số người hàng xóm KK trong KNN ([Tech Blog #18]).<br>- Độ sâu max_depth trong Cây quyết định.<br>- Số lượng cây n_estimators trong Random Forest ([Tech Blog #26]).

4. Bảng so sánh: GridSearchCV vs. RandomizedSearchCV

Khi cần tìm ra bộ "nút vặn" (Hyperparameters) tối ưu nhất cho mô hình:

Tiêu chíGridSearchCV (Dò lưới vét cạn)RandomizedSearchCV (Dò ngẫu nhiên)
Cơ chế hoạt độngThử nghiệm tất cả mọi tổ hợp có thể có trong danh sách bạn cung cấp.Bốc thăm ngẫu nhiên một số lượng tổ hợp cố định (ví dụ thử 20 tổ hợp ngẫu nhiên).
Thời gian tính toán🐢 Rất lâu (Nếu có 4 tham số, mỗi tham số 4 giá trị →44=256\rightarrow 4^4 = 256 lần train).⚡ Rất nhanh, kiểm soát được thời gian chạy qua tham số n_iter.
Khả năng tìm nghiệm tốt nhấtĐảm bảo tìm ra tổ hợp tốt nhất trong phạm vi lưới đã định nghĩa.Có thể bỏ lỡ nghiệm tối ưu tuyệt đối nhưng thường tìm được nghiệm tốt 95% chỉ với 1/10 thời gian.
Khi nào nên dùng?Không gian tham số nhỏ (dưới 50 tổ hợp), mô hình nhẹ (KNN, Logistic).Không gian tham số khổng lồ (hàng nghìn tổ hợp), mô hình nặng (Random Forest, XGBoost).

5. Thực hành thực chiến: Tối ưu hóa Random Forest bằng GridSearchCV trong Python

Đoạn mã Python dưới đây sử dụng StratifiedKFold và GridSearchCV của Scikit-Learn để tự động dò tìm cấu hình siêu tham số tốt nhất cho mô hình phân loại:

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split, StratifiedKFold, GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, accuracy_score

# 1. Tạo tập dữ liệu mô phỏng bài toán Phê duyệt Tín dụng
np.random.seed(42)
n_samples = 800

X = pd.DataFrame({
    "income": np.random.uniform(10, 100, n_samples),
    "credit_score": np.random.uniform(400, 850, n_samples),
    "debt_ratio": np.random.uniform(0.1, 0.8, n_samples)
})
# Quy luật có thêm 10% nhiễu
noise = np.random.rand(n_samples) < 0.10
y = (((X["credit_score"] > 600) & (X["debt_ratio"] < 0.45)) ^ noise).astype(int)

# 2. BƯỚC SỐNG CÒN: Tách riêng tập Test cuối cùng (Hold-out Test Set)
# Tập Test này TUYỆT ĐỐI KHÔNG được tham gia vào quá trình Cross-Validation / GridSearch
X_train_val, X_test, y_train_val, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 3. Định nghĩa Không gian Siêu tham số cần dò tìm (Parameter Grid)
param_grid = {
    "n_estimators": [50, 100, 150],       # Thử 3 mức số lượng cây
    "max_depth": [3, 5, 8, None],          # Thử 4 mức độ sâu của cây
    "min_samples_split": [2, 5, 10]        # Thử 3 mức số mẫu tối thiểu để tách nhánh
}
# Tổng số tổ hợp cần thử: 3 x 4 x 3 = 36 tổ hợp
# Với K-Fold = 5, hệ thống sẽ tự động huấn luyện: 36 x 5 = 180 mô hình!

# 4. Khởi tạo K-Fold phân tầng (Stratified K-Fold)
cv_strategy = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)

# 5. Khởi tạo và thực thi GridSearchCV
rf_base = RandomForestClassifier(random_state=42)

grid_search = GridSearchCV(
    estimator=rf_base,
    param_grid=param_grid,
    cv=cv_strategy,
    scoring="f1",      # Đánh giá bằng F1-score (đã học ở bài 10) thay vì Accuracy
    n_jobs=-1,         # Sử dụng toàn bộ nhân CPU để chạy song song
    verbose=1
)

print("Đang tiến hành dò tìm siêu tham số tối ưu...")
grid_search.fit(X_train_val, y_train_val)

# 6. Trích xuất kết quả tối ưu nhất
print("\n--- KẾT QUẢ DÒ TÌM TỐI ƯU (GRID SEARCH RESULTS) ---")
print(f"Cấu hình siêu tham số tốt nhất (Best Params): {grid_search.best_params_}")
print(f"Điểm F1-Score trung bình trên 5 Folds: {grid_search.best_score_ * 100:.2f}%")

# 7. Đánh giá khách quan mô hình tốt nhất trên tập Test độc lập (Hold-out Test Set)
best_model = grid_search.best_estimator_
y_pred_final = best_model.predict(X_test)

print("\n--- ĐÁNH GIÁ TRÊN TẬP TEST ĐỘC LẬP (UNSEEN DATA) ---")
print(f"Test Accuracy: {accuracy_score(y_test, y_pred_final) * 100:.2f}%")
print("\nBáo cáo phân loại chi tiết:")
print(classification_report(y_test, y_pred_final, target_names=["Từ chối (0)", "Duyệt (1)"]))

6. Câu hỏi phỏng vấn thực tế (Interview Q&A)

Câu 1 (Mức độ: Entry / Junior)

Câu hỏi: "Phân biệt sự khác nhau giữa Parameter và Hyperparameter trong Machine Learning? Cho ví dụ cụ thể."

Gợi ý trả lời:
*"Điểm khác biệt cơ bản nằm ở nguồn gốc xác định:

  • Parameters (Tham số): Là các giá trị cấu thành nội tại của mô hình, được thuật toán tự động học và điều chỉnh từ dữ liệu huấn luyện thông qua quá trình tối ưu hàm mất mát. Ví dụ: Các trọng số ww và bias bb trong hồi quy, hoặc ngưỡng rẽ nhánh tại các nút của Decision Tree.
  • Hyperparameters (Siêu tham số): Là các cấu hình bên ngoài do chính kỹ sư dữ liệu chỉ định trước khi quá trình huấn luyện bắt đầu nhằm điều khiển hành vi của thuật toán. Ví dụ: Số lượng cây n_estimators trong Random Forest, tốc độ học learning_rate trong Gradient Boosting, hoặc số láng giềng KK trong KNN."*

Câu 2 (Mức độ: Junior / Mid-level)

Câu hỏi: "Tại sao chúng ta vẫn cần phải giữ lại một tập Test độc lập (Hold-out Test Set) nếu đã sử dụng 5-Fold Cross-Validation trên tập Train?"

Gợi ý trả lời:
"Lý do là để phòng ngừa hiện tượng Rò rỉ thông tin tối ưu hóa (Optimization Data Leakage / Overfitting on Validation Set):
Khi chúng ta sử dụng GridSearchCV với 5-Fold Cross-Validation để thử nghiệm 50 tổ hợp siêu tham số khác nhau, chúng ta đang chọn ra tổ hợp tham số nào có điểm số cao nhất trên các Folds đó. Vô hình trung, các siêu tham số này đã được 'tối ưu hóa quá mức' để khớp tốt với tập dữ liệu Cross-Validation đó.
Do đó, điểm số tốt nhất từ Cross-Validation vẫn có thể hơi lạc quan. Việc giữ lại một tập Hold-out Test Set hoàn toàn biệt lập (chưa từng được mô hình hay thuật toán GridSearch nhìn thấy một lần nào) là bước chốt chặn cuối cùng để kiểm chứng năng lực thực tế của mô hình trên dữ liệu tương lai ngoài đời thực."


7. Key Takeaways (Ghi nhớ nhanh)

  1. Một lần train/test là không đủ: Luôn sử dụng K-Fold Cross-Validation (thường K=5K=5 hoặc 1010) để có con số đánh giá thực lực khách quan, loại bỏ yếu tố ăn may.
  2. Luôn dùng Stratified K-Fold cho bài toán phân loại: Đảm bảo mỗi Fold đều duy trì tỷ lệ nhãn giống hệt tập dữ liệu gốc, ngăn ngừa tình trạng Fold rỗng nhãn.
  3. Parameters do máy học, Hyperparameters do người chỉnh: Đừng đoán mò siêu tham số, hãy để GridSearchCV hoặc RandomizedSearchCV tìm kiếm tự động.
  4. Quy tắc 3 tập dữ liệu vàng: Tách riêng Train (để học), Validation / K-Fold (để dò tìm siêu tham số), và Hold-out Test (để đánh giá khách quan bước cuối cùng).
0Claps