🗺️ AI 學習與考證地圖
中級科目三程式實戰 · 過擬合調校

訓練滿分、驗證掉三成:
過擬合的森林,該從哪裡修剪?

training accuracy 1.00、validation accuracy 0.72——中間裂開一條 0.28 的縫。題目給了三個設定值(500 棵、深度不限、每葉 1 筆)和四種處置,考的是你能不能看著設定就指出病灶:哪個旋鈕在放任單棵樹長到「把訓練資料背起來」,而哪些處置只是在旁邊瞎忙。本頁把四個選項全部實跑給你看。

閱讀模式

00題目

某 Tree Ensemble 出現 training accuracy=1.00validation accuracy=0.72,原始設定如下。若其他資料流程已確認無洩漏,下列調整何者最能直接降低單棵樹的複雜度並改善過擬合?

from sklearn.ensemble import RandomForestClassifier  # 拿出隨機森林分類器
model = RandomForestClassifier(                      # 開始組模型(括號先不關)
    n_estimators=500,                                # 樹的數量:500 棵
    max_depth=None,                                  # 樹深上限:不設限,想長多深就多深
    min_samples_leaf=1,                              # 每片葉子最少要有幾筆:1 筆也行
    random_state=42                                  # 固定亂數種子
)                                                    # 設定收尾——注意:題目連 .fit 都沒呼叫

先說「過擬合」是什麼

一個學生把三年份考古題的答案背得滾瓜爛熟:模擬考(訓練集)次次滿分。大考(驗證集)出了新題,只考 72 分——因為他背的是「答案」,不是「解法」。這就是過擬合(overfitting):模型把訓練資料的細節連同雜訊一起記下來,換一批沒看過的資料就原形畢露。

診斷的關鍵是兩個數字一起讀:train 高不是問題、val 低也不一定是過擬合——「train 很高、val 明顯低、中間裂縫很大」三件事同時成立,才是過擬合的招牌長相。本題 1.00 vs 0.72,裂縫 0.28,教科書級的病例。

題目那句「其他資料流程已確認無洩漏」是在幫你排除鑑別診斷。train 與 val 差很大,另一個常見嫌犯是資料洩漏(驗證資料的資訊漏進訓練)——但那通常反過來讓 val 虛高。出題者先把洩漏排除,就是要你把矛頭對準模型複雜度:500 棵「深度不設限、每葉 1 筆也能自成一格」的樹,每一棵都拿到了把訓練資料背起來的執照。

先點開看:過擬合是什麼?裂縫(gap)怎麼讀?單棵樹的複雜度是指什麼?

不熟 AI 專有名詞?你需要先認識下列名詞

點擊後出現漸進式說明:白話說明 → 說清楚一點 → 常見錯誤與考點。

這題的病症
過擬合 overfitting欠擬合 underfitting泛化 generalizationtrain/val 落差訓練/驗證/測試集
病灶:單棵樹的複雜度
單棵樹複雜度max_depthmin_samples_leafmin_samples_split剪枝 pruning
這座森林
隨機森林 RandomForestn_estimatorsBagging 裝袋平均偏差與變異本站的模擬資料
開藥的方法
用交叉驗證選參數GridSearchCV複雜度/驗證曲線OOB 分數正則化家族資料洩漏

不熟 Python?你需要先認識下列名詞

點擊後出現漸進式說明。這題的程式只有「設定」,一個動作都沒做——正因如此,每個設定值的意義就是全部。

把工具拿進來
importfrom模組 module
存東西、設數值
= 指派變數與命名關鍵字引數500、1、42 整數None
括號與排版
( ) 呼叫括號為什麼可以換行寫行尾的逗號. 點運算子model 這個名字

01逐行拆解:第 1 行到第 7 行

七行裡有五行是「設定值」。右上角的「看位置」可以把這一行放回完整程式裡看。

先看清楚:這段程式「什麼都還沒做」

model = RandomForestClassifier( ... )   ← 只是把一台機器組好、放在桌上
                                          沒有 .fit():一筆資料都還沒看
                                          題目的 1.00 / 0.72 是「之後訓練完」量到的

所以這題考的不是流程,是看設定值診斷病灶:
n_estimators=500、max_depth=None、min_samples_leaf=1 —— 哪個在縱容過擬合?

想深入的話點這裡:呼叫括號名字=值 的設定寫法為什麼可以換行

第 1 行拿出隨機森林分類器
from sklearn.ensemble import RandomForestClassifier   # 從「集成方法」抽屜拿出隨機森林

sklearn.ensemble集成方法的抽屜。題目說「Tree Ensemble(樹的集成)」,隨機森林就是最典型的一種:一大群決策樹各自判斷、投票表決

重點先講:集成(很多棵樹平均)能降低結果的波動,但每一棵樹自己有多會「背答案」,是另一件事——那由第 4、5 行的設定決定。這個分工是整題的鑰匙。

相關名詞:fromimport隨機森林Bagging

第 2 行開始組模型,取名 model
model = RandomForestClassifier(   # 呼叫開始,括號先不關

呼叫 RandomForestClassifier(...) 組一台森林,貼上 model 的名牌。括號沒關——第 2 到第 7 行其實是同一句話,只是把四個設定值排成一行一個,好讀。

這種「一行一個參數、行尾逗號」的排版是 sklearn 教學裡最常見的寫法。逗號的意思是「還有下一項」,最後一項後面可加可不加。

相關名詞:= 指派為什麼可以換行行尾的逗號

第 3 行n_estimators=500:樹的「數量」——它不是嫌犯
    n_estimators=500,   # 森林裡種 500 棵樹

500 棵不少,但先把話說死:樹的「數量」跟單棵樹的「複雜度」是兩個獨立的旋鈕。數量多=找更多評審來投票,平均起來更穩;複雜度高=每一位評審都在背答案。500 個都在背答案的評審,平均出來的還是背答案。

這正是選項 A 的死穴預告:本站實跑把 500 棵加到 2000 棵,train 一直是 1.000、val 只在 0.72~0.74 抖動——加樹是穩定器,不是剪枝刀。(第 05 節有完整實驗。)

相關名詞:n_estimatorsBagging偏差與變異

第 4 行max_depth=None:想長多深就長多深
    max_depth=None,   # 深度不設上限,長到分不動為止

None =「不設上限」:每棵樹可以一路分岔,直到每片葉子都純了(或碰到其他限制)為止。這是過擬合的第一個放任條款——樹越深,能刻出的規則越細,細到可以為單一筆訓練資料量身打造一條路徑。

本站實跑(重現題目的資料,210 筆訓練、60 個特徵):深度不設限時,500 棵樹實際長到 6~15 層、平均 9.3 層。而後面會看到:這份資料的甜蜜點在 5 層左右——放任的樹,深了快一倍。

None 是 Python 的正式值(「不設定」的明確寫法),不是空白也不是忘了填。它是預設值——你什麼都不寫,隨機森林本來就是深度不設限

相關名詞:max_depthNone單棵樹複雜度

第 5 行min_samples_leaf=1:一筆資料也能自成一片葉子
    min_samples_leaf=1,   # 每片葉子最少 1 筆就合法

min_samples_leaf 規定「分岔之後,每片葉子至少要包含幾筆訓練資料」。設成 1,代表樹可以為了一筆資料切出一片專屬葉子——這等於發給每棵樹一張「逐筆記憶執照」:連標錯的雜訊點,都能被切成自己的小房間。

本站實跑:leaf=1 時每棵樹平均 29 片葉子、每片平均只裝 7.2 筆;把 leaf 提高到 10,葉子剩 10.2 片、每片 20 筆左右——葉子必須「裝下一群人」,就沒辦法替單一筆雜訊開小房間。這就是「提高葉節點限制」四個字的物理意義。

它也是預設值(預設就是 1)。所以題目的設定其實是「全預設的放任狀態」——這在實務上非常常見:用預設值訓練,然後發現 train 1.00。

相關名詞:min_samples_leafmin_samples_split剪枝

第 6–7 行固定種子、收尾——然後呢?沒有然後
    random_state=42   # 固定所有抽籤,結果可重現
)                      # 括號關上,model 組裝完成

random_state=42 把森林裡所有抽籤(抽資料、抽特徵)固定住,讓 1.00/0.72 這組數字可以被重現。第 7 行關括號,這句六行長的「組裝指令」結束。

注意程式到這裡就停了——沒有 .fit()、沒有評分。題目給的 1.00 和 0.72 是「之後訓練並評估」的結果,這段程式只負責交代造成那兩個數字的設定。考題常這樣只給關鍵段落。

相關名詞:變數與命名關鍵字引數訓練/驗證集

02情境重現:這座森林到底長多複雜

為了把四個選項全部做出來對照,本站造了一份會誘發過擬合的資料:300 筆、60 個特徵,其中只有 6 個真的帶訊號(4 個有效+2 個冗餘),其餘 54 欄全是干擾;再摻 5% 的標籤雜訊。切 7:3 之後,用題目的原始設定訓練:

training accuracy
1.000
210 筆訓練資料全對
validation accuracy
0.722
90 筆驗證資料
裂縫 gap
0.278
跟題目的 1.00/0.72 對上了
解剖其中的單棵樹(本站實跑,500 棵的平均):深度 6~15 層、平均 9.3 層;每棵樹長出 29 片葉子,平均每片只裝 7.2 筆資料——而且 min_samples_leaf=1 允許很多葉子只裝 1 筆。這就是「單棵樹的複雜度」的具體長相:樹枝細到可以為個別樣本(含標錯的那 5%)刻專屬路徑。訓練資料當然全對——它們每一筆都有自己的房間。
接下來的實驗地圖:C 的「一路加深」(03 節)、D 的兩把剪枝刀 max_depth 與 min_samples_leaf(03、04 節)、A 的「只加樹」(05 節)、B 的「用 training accuracy 選參」(06 節)——四個選項,同一份資料,全部實跑。

相關名詞:這份模擬資料怎麼造的單棵樹複雜度gap 怎麼讀

03複雜度曲線:max_depth 這把刀,以及選項 C 的死路

把 max_depth 從 2 一路開到 None,train 和 val 各自怎麼走?這條「複雜度曲線」是過擬合考題的心臟:

互動實驗室:複雜度曲線點一列,看那個深度發生什麼事
紅條=train、綠條=val,右邊是裂縫大小。點任何一列看解讀。

三個讀點。第一,train 在深度 5 就衝到 1.000,之後永遠貼著天花板。第二,val 在深度 5~6 達到峰值 0.767,再深就往下掉、一路掉回 0.722——複雜度越過甜蜜點之後,多出來的容量全部拿去背雜訊第三,光看裂縫也會被騙——全場 gap 最小的其實是 depth 2(0.115),但那是「兩個都低」的欠擬合gap 一定要跟 val 一起讀,甜蜜點是「val 最高」的深度 5~6(gap 0.233),不是「gap 最小」的地方。

選項 C 的死路,現在可以講清楚了:「持續增加樹深,直到 validation accuracy 等於 training accuracy」——實跑顯示加深之後 train 卡在 1.000、val 反而下滑,兩條線只會越拉越開。想讓兩個數字相等,只剩兩條路:val 升到 1.0(不可能——資料摻了 5% 標籤雜訊,天花板遠低於 1.0)、或 train 掉下來(加深只會反方向)。把「讓指標相等」當目標本身就是搞錯方向:目標是 val 高,不是兩個數字好看。

相關名詞:複雜度/驗證曲線max_depth偏差與變異

04另一把剪枝刀:min_samples_leaf

max_depth 是「限制樓層數」,min_samples_leaf 則是「規定每個房間至少要住幾個人」——房間不能為一筆資料獨開,樹自然就刻不出那些為雜訊量身打造的細枝。把它從 1 調到 50(深度保持 None):

互動實驗室:葉節點限制點一列,順便看單棵樹被剪成什麼樣
點任何一列。注意右邊的樹統計——葉子數量和平均深度跟著限制一路縮小。

曲線同樣有甜蜜點:val 峰值在 leaf=5(0.756);再往上調,train 一路掉到 0.767、val 也回落——剪過頭就是欠擬合:leaf=50 時每棵樹平均只剩 2 片葉子、1 層深,變成 500 根「樹墩」,連真訊號都學不了。判讀口訣:train 高 val 低=過擬合;train val 一起低=欠擬合;兩個都不錯且接近=剛剛好。

為什麼題目說「min_samples_leaf 葉節點限制」?因為同一家族還有幾個親戚:min_samples_split(少於幾筆就不准再分岔)、max_leaf_nodes(葉子總數上限)、ccp_alpha(成本複雜度後剪枝)。它們都在做同一件事——讓樹的每個決定都必須有「一群樣本」背書,而不是為單筆資料服務。這類參數統稱樹的「預剪枝」,是樹家族的正則化。

相關名詞:min_samples_leafmin_samples_split剪枝欠擬合正則化家族

05選項 A:加樹是穩定器,不是剪枝刀

「維持 max_depth=None 與 min_samples_leaf=1,只增加 n_estimators」——直覺上「更多樹=更強」,實跑看看:

互動實驗室:只加樹,會發生什麼事50 棵到 2000 棵的實跑對照
點任何一列。留意 val 有沒有「向上的趨勢」。

結果一目了然:train 永遠 1.000;val 從 50 棵的 0.678 爬到 100 棵的 0.733 之後,就停在 0.72~0.74 的平台抖動——500、1000、2000 棵都突破不了,永遠到不了剪枝後的 0.767。

加樹在做的事:Bagging 的平均能降低「變異」——單棵樹的判斷很飄,500 棵平均起來就穩(所以樹太少確實會更糟:50 棵只有 0.678)。但每一棵樹「系統性背答案」的毛病,平均不掉——500 份背出來的答案平均起來,還是背答案。用偏差—變異的話說:加樹降 variance,不降因複雜度而背進來的雜訊記憶;要動後者,得動每棵樹本身的複雜度。所以 A 不是「錯的方向」,是「答非所問」——題目問的是降低單棵樹複雜度。

相關名詞:n_estimatorsBagging偏差與變異

06選項 B:把量尺丟掉的人

「移除驗證集,改以 training accuracy 選參數」——這是四個選項裡唯一連方向都沒有的。用同一個 8 × 5 的參數網格(max_depth × min_samples_leaf,共 40 組),兩種選法對照:

互動實驗室:兩種量尺選出來的參數按 train accuracy 排 vs 按交叉驗證排
兩個致命傷,實跑都看得到:
① 無鑑別度——40 組參數裡有 12 組的 training accuracy 並列 1.000,可是它們的 val 從 0.722 到 0.767 差了 4.5 個百分點。量尺上全部同分的東西,實力天差地遠——這把尺根本量不出你要的東西。
② 系統性偏向複雜——複雜度只會讓 train 更高,所以這把尺永遠不會懲罰過擬合;「放任到底」的原設定(None, 1)穩坐滿分席,而它正是並列 12 組裡 val 墊底的那個。
把驗證集移除,等於把病人的體溫計丟了,改看「病人自己說幾度」。

相關名詞:驗證集是幹嘛的為什麼用交叉驗證gap

07選項 D 完整實作:CV 選出剪枝設定

把 D 選項一字不漏做出來:「以交叉驗證限制 max_depth,並提高 min_samples_leaf 等葉節點限制」——正好接上上一頁的 GridSearchCV:8 個深度 × 5 個葉限制 = 40 組合,5 折交叉驗證(40 × 5 = 200 次 fit,上一頁的乘法)。

本站實跑結果:CV 挑出 {'max_depth': 5, 'min_samples_leaf': 1}(CV 分數 0.743;前三名 0.743/0.743/0.738 全是深度 4~6 的淺樹設定,原設定 (None, 1) 的 CV 只有 0.729、排第 22 名)。用最佳設定重訓:
trainvalgap單棵樹平均深平均葉數每葉筆數
原設定(None, 1)1.0000.7220.2789.3 層29.07.2
CV 最佳(depth 5)1.0000.7670.2335.0 層16.812.5
val 從 0.722 → 0.767、單棵樹從 9.3 層剪到 5.0 層、葉子從 29 片剪到 16.8 片——「直接降低單棵樹的複雜度」四個字,每一項都有數字對應。單獨調 min_samples_leaf 也有效(leaf=5 → val 0.756),這份資料上 CV 最後挑了深度那把刀。
一個誠實的細節:最佳設定的 train 還是 1.000。這不矛盾——目標從來不是把 train 壓低,是把 val 抬高。train 1.0 本身無罪(資料好分時剛剛好的模型也能全對);有罪的是「train 1.0 而且 val 被雜訊記憶拖低」。判準永遠放在 val(或 CV 分數)身上,gap 縮小是結果,不是手段——這也是 C 選項把手段當目標的對照。
為什麼是「交叉驗證」而不是「就用那 90 筆驗證集挑」?兩個理由:90 筆的分數本身雜訊很大(±0.02 常態);而且如果反覆拿同一批驗證集試 40 組參數,等於對驗證集調參——挑出來的參數會過擬合到這 90 筆身上。CV 用訓練集內部輪流當考官,5 個分數平均更穩,驗證集留到最後做最終確認。這正是題目 D 特別寫「以交叉驗證」的原因。

四個選項一句話收工

A維持放任設定,只增加 n_estimators答非所問

加樹降的是「變異」,不動單棵樹的複雜度——實跑 500→2000 棵,train 恆為 1.000、val 卡在 0.72~0.74 平台,永遠到不了剪枝後的 0.767。穩定器,不是剪枝刀。

B移除驗證集,用 training accuracy 選參數把量尺丟掉

training accuracy 永遠偏向複雜、也分不出好壞——實跑 40 組裡 12 組並列滿分(val 卻差 4.5 個百分點),原設定正是滿分席裡 val 墊底的。沒有驗證訊號,過擬合連被發現的機會都沒有。

C持續加深,直到 val 等於 train方向相反

實跑:深度越過 5~6 之後 train 卡 1.000、val 一路下滑——越加深兩條線越開。而 val 想升到 1.0 也不可能(資料有 5% 標籤雜訊)。把「兩個數字相等」當目標,是拿手段當目的。

D以交叉驗證限制 max_depth、提高 min_samples_leaf 等葉節點限制正確

兩把剪枝刀直接作用在「單棵樹複雜度」上(9.3 層→5.0 層、29 葉→16.8 葉),用 CV 這把可靠量尺挑設定——val 0.722 → 0.767、gap 0.278 → 0.233。對症(複雜度)、下對藥(葉節點與深度限制)、用對量尺(CV)。

回到題目:現在再作答一次

再看一次同一段設定。這次你知道每個旋鈕在管什麼了。

某 Tree Ensemble 出現 training accuracy=1.00validation accuracy=0.72若其他資料流程已確認無洩漏,下列調整何者最能直接降低單棵樹的複雜度並改善過擬合?

model = RandomForestClassifier(   # 組模型
    n_estimators=500,              # 數量:穩定器
    max_depth=None,                # 放任條款一:深度不限
    min_samples_leaf=1,            # 放任條款二:一筆也能自成一葉
    random_state=42                # 固定抽籤
)                                  # 組裝完成

08自我檢測

八題,全部都是本題的延伸。答錯會直接告訴你錯在哪。

09重點整理

  1. 第 2 到第 7 行是同一句話(括號沒關就能換行),而且整段程式只有設定、沒有 .fit()——題目的 1.00/0.72 是之後訓練評估的結果。
  2. None 是「不設上限」的正式寫法;max_depth=Nonemin_samples_leaf=1 都是預設值——題目的設定就是「全預設的放任狀態」。
  3. 診斷公式:train 很高+val 明顯低+裂縫大 = 過擬合(本題 1.00/0.72、gap 0.28);train、val 一起低=欠擬合。題目先聲明「無洩漏」,就是要你把矛頭對準模型複雜度。
  4. 單棵樹複雜度的具體長相(實跑):深度不限+每葉 1 筆 → 平均 9.3 層、29 片葉、每葉僅 7.2 筆——細到能為單筆雜訊刻專屬路徑。
  5. max_depth 限制樓層、min_samples_leaf 規定每個房間至少住幾人;同家族還有 min_samples_split、max_leaf_nodes、ccp_alpha——都是「預剪枝」,樹家族的正則化。
  6. 複雜度曲線(實跑):val 在深度 5~6 達峰值 0.767,再深一路掉回 0.722;train 從深度 5 起永遠 1.000。越過甜蜜點,多的容量全部拿去背雜訊。
  7. 葉限制同理:val 峰值在 leaf=5(0.756);剪過頭變欠擬合——leaf=50 時樹只剩 1 層深 2 片葉(樹墩),train 掉到 0.767。
  8. 加樹是穩定器不是剪枝刀(A 的死因):50→2000 棵,train 恆 1.000、val 卡在 0.72~0.74 平台。Bagging 平均降的是變異;500 份背出來的答案平均起來還是背答案。
  9. training accuracy 當量尺(B 的死因):永遠偏向複雜、且無鑑別度——實跑 40 組有 12 組並列 1.000,val 卻差 4.5 個百分點,原設定正是墊底者。
  10. 「加深直到 val=train」(C 的死因):加深後兩線越拉越開;val 也不可能到 1.0(5% 標籤雜訊天花板)。目標是 val 高,不是兩個數字相等。
  11. 為什麼用 CV 選參:單一驗證集分數雜訊大,反覆試 40 組會「對驗證集調參」;CV 在訓練集內輪流當考官更穩,驗證集留作最終確認。
  12. 正確答案 D:CV 網格挑出 depth=5 → val 0.722→0.767、gap 0.278→0.233、單棵樹 9.3 層→5.0 層。誠實註記:最佳設定 train 仍 1.000——判準在 val,train 1.0 本身無罪
完整程式碼