DHDataHọc
TheoryLesson 7/84 min read+10 XP

Cross-validation và siêu tham số

Bạn sẽ học được

  • Chọn kiểu cross-validation phù hợp với dữ liệu.
  • Chạy GridSearchCV trên pipeline.
  • Hiểu vì sao điểm tìm được bằng grid search bị lạc quan.
  • Dùng nested cross-validation để ước lượng khách quan.
  • Đọc kết quả và tránh tối ưu quá mức.

Khái niệm cốt lõi

Cross-validation chia train thành K fold, huấn luyện trên K−1 fold và đánh giá trên fold còn lại, lặp K lần rồi lấy trung bình.

code
Fold 1: [val] [train] [train] [train] [train]
Fold 2: [train] [val] [train] [train] [train]
...

Lợi ích: mọi dòng dữ liệu đều được dùng để đánh giá đúng một lần, và ta thấy được độ dao động giữa các fold.

Chọn kiểu chia

KiểuDùng khi
KFoldDữ liệu độc lập, lớp cân bằng
StratifiedKFoldPhân loại, đặc biệt khi mất cân bằng
GroupKFoldNhiều dòng cho mỗi đối tượng
TimeSeriesSplitDữ liệu chuỗi thời gian

Với phân loại mất cân bằng, luôn dùng StratifiedKFold. Nếu không, có fold chỉ có vài ca dương và điểm dao động rất mạnh.

Cross-validation cơ bản

code
from sklearn.model_selection import StratifiedKFold, cross_val_score

cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)

scores = cross_val_score(
    model,
    X_train,
    y_train,
    cv=cv,
    scoring="roc_auc",
)
print(scores)
print(f"{scores.mean():.3f} ± {scores.std():.3f}")

Truyền pipeline, không truyền dữ liệu đã tiền xử lý. Mỗi fold phải tự fit lại toàn bộ tiền xử lý.

Độ lệch chuẩn quan trọng: 0,86 ± 0,01 ổn định hơn 0,86 ± 0,06 rất nhiều, dù trung bình bằng nhau.

Tìm siêu tham số

code
from sklearn.model_selection import GridSearchCV

param_grid = {
    "clf__C": [0.01, 0.1, 1, 10],
    "clf__class_weight": [None, "balanced"],
}

search = GridSearchCV(
    model,
    param_grid,
    cv=cv,
    scoring="roc_auc",
    n_jobs=-1,
    refit=True,
)

search.fit(X_train, y_train)
print(search.best_params_)
print(search.best_score_)

Lưu ý cú pháp: tham số của bước trong pipeline cần tiền tố clf__. Viết C thay vì clf__C sẽ báo lỗi.

Số lần huấn luyện: 4 × 2 = 8 tổ hợp, mỗi tổ hợp 5 fold → 40 lần fit. Với dữ liệu lớn, cân nhắc RandomizedSearchCV hoặc giảm lưới.

Vì sao best_score_ bị lạc quan

best_score_ là giá trị cao nhất trong 8 tổ hợp. Chọn cao nhất trong nhiều lần thử luôn thiên lên — kể cả khi mọi tổ hợp tương đương, tổ hợp may mắn nhất sẽ thắng.

Với lưới lớn và tập nhỏ, chênh lệch có thể 2–5 điểm AUC. Đó là lý do không được báo cáo best_score_ như hiệu năng thật.

Cách đúng: dùng validation riêng, hoặc nested CV.

Nested cross-validation

code
from sklearn.model_selection import cross_val_score

inner = GridSearchCV(model, param_grid, cv=cv, scoring="roc_auc")

outer = cross_val_score(
    inner,
    X_train,
    y_train,
    cv=cv,
    scoring="roc_auc",
)

print(f"{outer.mean():.3f} ± {outer.std():.3f}")

Vòng ngoài đánh giá quy trình "tìm siêu tham số rồi huấn luyện", vòng trong tìm siêu tham số. Điểm vòng ngoài là ước lượng khách quan.

Chi phí: 5 fold ngoài × 5 fold trong × 8 tổ hợp = 200 lần fit. Chấp nhận được với dữ liệu vừa; với dữ liệu lớn cần giảm lưới.

Sau khi tìm được siêu tham số

  1. Huấn luyện lại trên toàn bộ train với tham số tốt nhất (refit=True làm việc này).
  2. Đánh giá một lần trên test.
  3. Ghi lại cả điểm validation và test.

Nếu test thấp hơn validation nhiều, quay lại kiểm tra rò rỉ và kích thước mẫu — đừng chỉnh tham số cho đến khi test đẹp.

Lỗi thường gặp

  • Cross-validate dữ liệu đã tiền xử lý: rò rỉ.
  • Dùng KFold cho dữ liệu mất cân bằng: fold thiếu ca dương.
  • Dùng KFold cho dữ liệu thời gian: rò rỉ tương lai.
  • Báo cáo best_score_: lạc quan.
  • Lưới quá lớn: tốn thời gian, tăng nguy cơ chọn may mắn.
  • Chỉnh tham số theo test: test mất giá trị.
  • Bỏ qua độ lệch chuẩn: chọn mô hình không ổn định.

Thực hành

  1. Chạy StratifiedKFold 5 fold trên pipeline.
  2. Chạy GridSearchCV với lưới C bốn giá trị.
  3. So sánh best_score_ với điểm validation riêng.
  4. Chạy nested CV và so sánh.
  5. Thử TimeSeriesSplit trên dữ liệu có cột ngày.

Lỗi thường gặp

Triệu chứngNguyên nhânCách sửa
Điểm CV dao động mạnhFold quá nhỏ hoặc không stratifyStratifiedKFold, tăng K
Lỗi "invalid parameter"Thiếu tiền tố bướcclf__C
best_score_ cao hơn testChọn cực trịDùng nested CV
CV cao bất thườngTiền xử lý ngoài pipelineĐưa vào pipeline
Chạy quá lâuLưới quá lớnGiảm lưới hoặc randomized

Tóm tắt

  • Chọn kiểu CV theo cấu trúc dữ liệu.
  • Luôn cross-validate trên pipeline.
  • best_score_ là cực trị, không phải ước lượng khách quan.
  • Nested CV cho ước lượng đáng tin, đổi lại chi phí tính toán.
  • Chỉ chạm test một lần sau khi đã chốt mọi thứ.

Use ← → to move between lessons