National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 80 24°C PM2.5 21
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 14

交叉驗證與超參數搜尋

k 折、GridSearchCV 與資料洩漏
Interaction實作 30 minute(s)

Learning Objectives

  • 說明為什麼不能用測試資料挑超參數,並分清訓練、驗證、測試資料的用途
  • 寫出 k 折切分,用 cross_val_score 得到平均與標準差,並用它比較超參數
  • 用 GridSearchCV 搜尋超參數,最後才用測試資料評估一次
  • 認出資料洩漏:前處理或選特徵用到驗證資料時,分數會虛高

第 8 課留下的問題

第 8 課試了幾個 k,看到 k=5 的測試準確率最高(0.809),也留下一個問題:可以用測試資料挑 k 嗎?

不可以。測試資料的用途是估計「模型遇到沒看過的資料時表現如何」。如果你看著測試分數挑 k,就等於讓測試資料參與了決定,這個分數會偏樂觀,也不再有資格回答原本的問題。

所以資料要分三種用途:

資料 用途 使用次數
訓練資料 學模型的參數(權重、樹的分割) 很多次
驗證資料 比較超參數(k、C、樹的深度) 很多次
測試資料 全部決定之後,估計最終表現 一次

但只切一次驗證資料也有問題:切法不同,分數就不同,資料少時差得更多。k 折交叉驗證(k-fold cross-validation)的做法是:把訓練資料分成 k 份,每一份輪流當驗證資料,其他份拿來訓練,得到 k 個分數。這樣每一筆都當過一次驗證資料,也能從 k 個分數看出浮動有多大。

逐步看:k 折怎麼切

先只看編號,不訓練模型。10 筆資料切成 5 折,看每一輪的驗證資料是哪幾筆。

逐步看:親手跑一次交叉驗證

用 students.csv(程式產生的模擬資料,不是任何學校的真實資料)預測是否及格,模型是 k=5 的 k 近鄰。注意 scaler 寫在迴圈裡面:每一折只用該折的訓練資料算平均與標準差。

用 cross_val_score 省下迴圈

上面的迴圈 scikit-learn 已經包好了:

model = make_pipeline(StandardScaler(), KNeighborsClassifier(n_neighbors=5))
scores = cross_val_score(model, X, y, cv=5)
  • make_pipeline 把 scaler 和模型接成一個物件(第 16 課細談)。交叉驗證的每一折都會重新 fit 整個流程,所以 scaler 不會看到驗證資料。
  • cv=5 用在分類器時,預設是 StratifiedKFold:每一折的類別比例和全體相近,而且不洗牌;用在迴歸模型時是一般的 KFold。
  • 分數預設是模型的 score:分類是準確率,迴歸是 R²。要換指標用 scoring,例如 scoring="recall"。

怎麼讀結果:平均代表表現,標準差代表浮動。兩個超參數的平均差距如果比標準差還小,就不要說其中一個比較好;這時可以選比較簡單的那一個。折數常用 5 或 10:折數越多,每次訓練用的資料越多,但也要跑越久。

逐步看:用交叉驗證重新挑 k

這和第 8 課是同一份資料、同一個切分,但這次完全不碰測試資料,只在訓練資料上做 5 折交叉驗證。比較第 8 課的結論:k=5 真的比較好嗎?

超參數一多,用 GridSearchCV

參數是模型從資料學來的(權重、分割點);超參數是訓練之前由你決定的(k、C、樹的深度)。超參數不只一個時,手寫迴圈會很長。GridSearchCV 把你列出的組合全部試過,每一種都做交叉驗證:

search = GridSearchCV(pipe, grid, cv=5)
search.fit(X_train, y_train)
  • 參數名稱用「步驟名稱+兩個底線+參數名稱」指定,例如 knn__n_neighbors。
  • 組合數會相乘:4 個 k、2 種權重、5 折就要訓練 40 次;組合太多時可以改用 RandomizedSearchCV,只隨機試固定次數。
  • 預設 refit=True:找到最好的組合後,用全部訓練資料再訓練一次,search.predict、search.score 用的就是這個模型。

best_score_ 是挑出來的那個組合的分數,因為是「試很多次取最高」,會略為樂觀,所以最後要用測試資料評估一次,而且只用這一次。

逐步看:GridSearchCV

weights="distance" 表示距離越近的鄰居票越重,預設 "uniform" 是每票一樣重。

資料洩漏:驗證資料偷偷參與了訓練

資料洩漏(data leakage)是指驗證或測試資料的資訊,在評估之前就進入了模型。結果是分數看起來很好,真正用的時候卻做不到。

交叉驗證本身擋不住洩漏,要看你在哪裡做前處理:

寫法 問題
先用全部資料 fit scaler,再做交叉驗證 驗證資料參與了平均與標準差的計算
先用全部資料選特徵,再做交叉驗證 驗證資料參與了「哪些特徵有用」的決定
同一個人的多筆紀錄同時出現在訓練與驗證 模型認得這個人,不是學到規律
預測未來時,用未來的資料訓練 模型看到了當時還不存在的資訊

洩漏的嚴重程度差很多。標準化的洩漏通常很小(只偷看了平均與標準差);選特徵的洩漏可以大到把純雜訊變成高分,下面就來試。後兩種要改切分方式:同一個人或同一組的資料用 GroupKFold,時間序列用 TimeSeriesSplit。

逐步看:雜訊也能拿高分

60 筆資料、1000 個特徵,全部是亂數,標籤也是亂數。任何模型都不可能真的預測,正確的估計應該接近 0.5。SelectKBest 依每個特徵和標籤的關聯(預設 F 值)挑出最高的 k 個。

互動練習:k 折與洩漏的對照

上半部用 students.csv 的四個特徵與 k=5 的 k 近鄰,畫出每一折的驗證資料與分數。下半部用純雜訊比較兩種選特徵的寫法(模型也是 k=5 的 k 近鄰,所以數字和上面的逐步範例不同,現象相同)。數字都是在你的瀏覽器裡當場算的。

實作:寫一個 kfold_indices 函數

完成 kfold_indices(n, k):不洗牌,把 0 到 n-1 分成 k 折,回傳串列,每個元素是 (訓練編號串列, 驗證編號串列)。

切不完時,前面幾折多分一筆(和 scikit-learn 的 KFold 相同):7 筆切 3 折,每折的大小是 3、2、2。

你的輸出
預期輸出

小測驗:交叉驗證與資料洩漏

1.

下面程式會印出什麼?

from sklearn.model_selection import KFold
import numpy as np
X = np.arange(7).reshape(-1, 1)
sizes = [len(val) for train, val in KFold(n_splits=3).split(X)]
print(sizes)
2.

你看著測試分數試了 20 個超參數,選最高的那個回報。這個分數會怎樣?

3.

k=5 的平均是 0.776、標準差 0.047;k=41 的平均是 0.777、標準差 0.009。最恰當的結論是?

4.

下面哪一種寫法沒有資料洩漏?

5.

用 GridSearchCV 試 3 個 C 和 4 個 gamma,cv=5,預設設定下總共訓練幾次(含最後重新訓練)?

第 1 次作答

重點整理

  • 訓練資料學參數、驗證資料比較超參數、測試資料最後用一次。用測試資料挑超參數,測試分數就不可信。
  • k 折交叉驗證讓每一筆輪流當驗證資料;看平均,也看標準差。差距小於浮動時,不要說誰比較好。
  • cross_val_score 跑交叉驗證,GridSearchCV 搜尋超參數;分類器的 cv=5 預設用 StratifiedKFold。
  • 資料洩漏:縮放、補值、選特徵都要在每一折內做,把它們放進 Pipeline 就不會出錯。選特徵的洩漏可以讓純雜訊拿到 0.867。
  • 回到第 8 課的問題:用交叉驗證看,k=5 和 k=41 幾乎一樣,那次的 0.809 有一部分是運氣。
  • 下一課處理兩個評估時常被忽略的問題:類別不平衡,以及整體的數字會藏住某些群組的錯誤。
這一課完成了!
Next lesson:資料不平衡與資料偏誤
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。