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 02

訓練與測試

為什麼要分開,第一次看到過擬合
Interaction實作 30 minute(s)

Learning Objectives

  • 說明為什麼模型表現要看沒看過的資料,什麼是泛化
  • 用 train_test_split 切分資料,說明 test_size、random_state、stratify 的作用
  • 從訓練與測試準確率的差距,判斷過擬合與欠擬合
  • 說明切分只切一次時,測試分數為什麼會浮動

背答案不等於學會

考試前把考古題的答案全部背下來,考古題可以考滿分,但換一份新題目就不一定了。考古題的分數,看不出你到底學會了沒有。

模型也一樣。模型在訓練資料上表現好,可能只是把那些資料記住了。我們真正在意的是它遇到沒看過的資料時準不準,這個能力叫泛化(generalization)。

下面做一個有點極端的實驗:把標籤換成丟銅板的結果,這份資料根本沒有規律可以學。如果模型在這種資料上還能拿高分,那個分數就不可能代表「學到東西」。

逐步看:連丟銅板都能「學」到滿分

資料和標籤都是亂數產生的,兩者完全無關。把前 150 筆拿去訓練,留 50 筆不給模型看。先猜猜看:兩個分數各會是多少?

把一部分資料藏起來

做法很簡單:開始之前先把資料切成兩份。

資料 用途 比喻
訓練資料(training set) 給模型學規則 上課和考古題
測試資料(test set) 模型完全沒看過,只用來評估 正式考試

scikit-learn 的 train_test_split 會先隨機打亂再切,三個參數最常用:

  • test_size:測試資料的比例,預設 0.25;
  • random_state:亂數種子。固定它,每次切法都一樣,別人才能重現你的結果;
  • stratify=y:讓訓練與測試資料裡各類別的比例和原本相同。類別比例懸殊時,少了它,少數類別可能大多被切到其中一邊。

為什麼要隨機? 資料常常有順序,例如前面都是資工系、後面都是護理系。直接切前 75% 和後 25%,兩邊就不是同一種資料了。不過,如果資料有時間順序、要預測的是未來,就不能隨機切,要用過去訓練、未來測試(第 24 課的專題會用到)。

逐步看:train_test_split

回到 students.csv(程式產生的模擬資料,不是任何學校的真實資料)。注意每次切完的形狀,和兩邊的及格比例。

過擬合與欠擬合

模型越複雜,越能貼合訓練資料,但也越可能把資料裡的雜訊也記下來。用決策樹來看:樹的深度越深,規則越細、越複雜。

情況 訓練表現 測試表現 意思
欠擬合(underfitting) 差 差 模型太簡單,連訓練資料的規律都學不到
剛好 不錯 不錯,兩者接近 學到可以推廣的規律
過擬合(overfitting) 很好 明顯比較差 模型太複雜,連雜訊都記住了

判斷時要同時看兩個數字和基準,也就是什麼都不學的簡單猜法(分類時全部猜最多的類別)。接下來把深度從 1 調到 12,看兩條線怎麼走。

逐步看:樹越深,訓練越高,測試呢?

看輸出的三欄:深度、訓練準確率、測試準確率;最後畫成折線圖。注意兩條線之間的距離。

互動練習:曲線越彎,越好嗎?

換一種模型看同一件事:用多項式曲線去貼合資料。次數越高,曲線能彎的地方越多,作用和決策樹的深度一樣,次數 1 就是一條直線。資料是正弦曲線加雜訊的模擬資料,在瀏覽器裡產生。藍點是訓練資料,模型只看得到它們;橘色空心點是測試資料。

測試分數也會浮動

上面測試資料只有 99 筆,一筆就是 1%。深度 2 的 0.808 和深度 3 的 0.798,只差一筆資料,很難說誰比較好。

再做一個實驗:模型不變,只換切分的方式(random_state),看測試準確率會差多少。

逐步看:只換切法,分數差多少

同一份資料、同樣深度 3 的樹,切六次。看最低和最高差多少。

使用測試資料的規矩

從這個實驗可以得到兩個結論:

  1. 差 1~2% 不要過度解讀。 測試資料不多時,那可能只是這次切分的運氣。第 14 課的交叉驗證會多切幾次取平均,得到比較穩定的估計。
  2. 測試資料只能用來做最後的評估。 如果你一邊看測試分數一邊調模型(改深度、換特徵),調到分數最高為止,模型其實就間接「看過」測試資料了,那個分數會偏樂觀,就像先看過考題再考試。需要比較不同設定時,應該從訓練資料裡再切一份驗證資料(validation set)或用交叉驗證,第 14 課會教。

本課的深度實驗為了讓你看到現象,直接畫出了測試分數,不代表可以用這條線來選深度。

實作:自己寫切分與準確率

完成兩個函數:

  • holdout(n, test_ratio, seed):用 np.random.default_rng(seed) 的 permutation(n) 打亂 0 到 n−1,前 int(n * test_ratio) 個當測試資料,其餘當訓練資料,回傳 (train_idx, test_idx);
  • accuracy(y_true, y_pred):回傳猜對的比例,四捨五入到小數 3 位。
你的輸出
預期輸出

小測驗:切分資料

1.

下面程式會印出什麼?

import numpy as np
from sklearn.model_selection import train_test_split
X = np.arange(20).reshape(10, 2)
y = np.arange(10)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
print(X_train.shape, y_test.shape)
2.

train_test_split 的 stratify=y 是做什麼用的?

3.

換一個 random_state 後,測試準確率從 0.78 變成 0.81,模型的設定完全沒動。最恰當的解讀是?

第 1 次作答

小測驗:讀懂兩個分數

1.

訓練準確率 0.99、測試準確率 0.70,全部猜最多類別是 0.72。這是什麼情況?

2.

訓練準確率 0.76、測試準確率 0.75,全部猜最多類別是 0.76。這是什麼情況?

3.

小明反覆調整模型設定,每次都看測試分數,留下最高的那組,回報 0.90。這個 0.90 有什麼問題?

第 1 次作答

重點整理

  • 模型表現要看沒看過的資料,訓練準確率高可能只是把資料背起來。這個能力叫泛化。
  • train_test_split:test_size 預設 0.25;random_state 讓切法可重現;stratify=y 保持類別比例。有時間順序的資料不要隨機切。
  • 欠擬合:訓練和測試都差。過擬合:訓練好、測試明顯比較差。都要和基準比較。
  • 測試資料不多時,只換切法分數就會浮動,差 1~2% 不要過度解讀。
  • 測試資料不能拿來調模型,比較設定要用驗證資料或交叉驗證(第 14 課)。

到這裡你已經知道怎麼誠實地評估模型。下一課開始從頭寫模型,先從最基本的線性迴歸開始。

這一課完成了!
Next lesson:線性迴歸
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。