Skip to content

林軒田機器學習技法 T9–T11:決策樹、隨機森林與梯度提升樹

2026年9月30日1 分鐘
TL;DR技法第 9–11 講用「樹+aggregation」一條線串起三種模型。T9 把決策樹看成 conditional aggregation,講 C&RT 的二元分支、Gini 與迴歸誤差、剪枝、類別特徵與 surrogate branch。T10 把 bagging 套在完全長大的樹上,加上隨機子空間與隨機投影就是隨機森林,順帶得到免費的 OOB 驗證與 permutation 特徵重要度。T11 先把 AdaBoost 重新推導成對指數誤差做函數空間的最速下降,再把誤差換成平方誤差,得到「對殘差做迴歸」的 GBDT。練習用 Fall 2024 HW7 的 impurity、gradient boosting 證明題;沒有官方解答。

🌏 English version

版本說明:本文以 MOOC 版《機器學習技法》為核心教材:209_handout.pdf(Decision Tree)、210_handout.pdf(Random Forest)、211_handout.pdf(Gradient Boosted Decision Tree)與技法 YouTube 播放清單第 34–45 支。作業對照 Fall 2024 HW7。事實皆於 2026-09-30 打開核對。存取等級:MOOC 本身 A2,加上 Fall 2024 作業 PDF 是 A3(評分鏈除外)——沒有官方解答,Gradescope 與 NTU COOL 限修課生。

系列位置:上一篇 Blending、Bagging 與 AdaBoost|下一篇 神經網路與深度學習|系列總覽

上一篇結束時,aggregation 的地圖上還空著一格。T9 開頭把它畫成一張表:

uniformnon-uniformconditional
blending(先有 g_t 再組合)voting/averaginglinearstacking
learning(邊學 g_t 邊組合)BaggingAdaBoostDecision Tree

決策樹就是「邊學邊做 conditional aggregation」的那一格。本系列把三講合成一篇的理由也在這裡:T9 先講樹,T10 把樹放進 bagging,T11 把樹放進 boosting,三者共用同一條主線。

在課表上的位置

版本週次投影片延伸閱讀(課程頁原列)
MOOC技法 T9–T11209、210、211—
Fall 2024W12(11/18),和 T8 同一週209u、210u、211uLoh、Breiman et al.(CART 書)、Breiman(RF)、Friedman
Fall 2026W12(11/25)209u–211u 目前 404,尚未公開同上

課程頁沒有替這三講標 LFD 章節。

T9 Decision Tree

影片:Decision Tree Hypothesis、Decision Tree Algorithm、Decision Tree Heuristics in C&RT、Decision Tree in Action

決策樹是哪一種 aggregation

投影片的例子是「今天要不要看 MOOC」:先看下班時間,早於 18:30 再看有沒有約會,晚於 21:30 再看作業截止日還剩幾天。

寫成 aggregation 的形式,G(x) = Σ q_t(x)·g_t(x):g_t 是第 t 條路徑末端的葉子(這裡是常數),q_t(x) 是「x 是否走在第 t 條路徑上」。也可以用遞迴的觀點看:G(x) = Σ_c [b(x) = c]·G_c(x),b 是分支條件,G_c 是第 c 棵子樹。投影片的說法是「就像你的資料結構老師會講的」。

投影片也老實列了決策樹的兩面。好處:人看得懂、在商業與醫療資料分析裡很常用、簡單到大一生就能寫、訓練和預測都快。壞處:理論解釋很少、heuristics 多到讓初學者困惑、也沒有單一個代表性的演算法。

C&RT 的四個選擇

基本的決策樹演算法是遞迴:沒達到終止條件就學一個分支條件 b(x)、把資料切成 C 份、各自遞迴建子樹。要決定的有四件事:分支數、分支條件、終止條件、葉子的基礎假說。

課堂上的 C&RT(投影片聲明它只取 CART 的部分元件)這樣選:

  • C = 2,二元樹。
  • 葉子是 E_in 最佳的常數:分類取多數、迴歸取平均。
  • 分支用 decision stump,挑讓切出來的兩邊最純的:b(x) = argmin Σ_c |D_c|·impurity(D_c)。
  • impurity 就是用最佳常數時的 E_in。迴歸用平方誤差;分類有 Gini index(1 − Σ_k (N_k/N)²,所有類別一起考慮)與分類錯誤率(只看多數類別)。投影片說常見選擇是分類用 Gini、迴歸用迴歸誤差。
  • 終止:所有 y_n 一樣(impurity = 0),或所有 x_n 一樣(找不到 stump 可切),被迫停下。

所以 C&RT 預設會長成一棵完全長大、葉子是常數的樹。

剪枝、類別特徵、缺值

完全長大的樹在所有 x_n 都不同時 E_in = 0,但深處的節點只用很少的資料建出來,容易 overfitting。投影片的處理:

  • 剪枝:正則化項取葉子數,Ω(G) = NumberOfLeaves(G)。所有可能的樹列舉不完,所以只考慮一串:G^(0) 是完全長大的樹,G^(i) 是從 G^(i−1) 拿掉一片葉子後 E_in 最小的那棵。λ 用 validation 選。
  • 類別特徵:數值特徵用門檻切,類別特徵改用子集合,b(x) = [x_i ∈ S] + 1。
  • 缺值:訓練時同時記下幾個「替代分支」(surrogate branch),它們的切法接近最佳分支。例如最佳分支是體重 ≤ 50 kg,預測時若缺體重,就改用身高的門檻。

投影片把 C&RT 的特長整理成五點:人看得懂、容易做多類別、容易處理類別特徵、容易處理缺值、非線性而且訓練與測試都有效率。並提到另一個常見的決策樹演算法 C4.5,選了不同的 heuristics。在示範資料集上,C&RT 比上一講的 AdaBoost-Stump 還更有效率。

T10 Random Forest

影片:Random Forest Algorithm、Out-of-bag Estimate、Feature Selection、Random Forest in Action

bagging + 完全長大的樹

bagging 會降低 variance,完全長大的樹 variance 很大。把兩者放在一起,投影片叫它「aggregation of aggregation」:

隨機森林(RF)= bagging + 完全長大的 C&RT

好處有三:高度平行、繼承 C&RT 的優點、用投票抵銷完全長大的樹的缺點。

多樣性還能再加。bagging 抽的是樣本,RF 還可以抽特徵:隨機挑 d′ 個維度,Φ(x) = (x_{i1}, …, x_{id′}),也就是隨機子空間。原始 RF 在 C&RT 的每一次分支都重新抽一個子空間。

再進一步,投影矩陣 P 的每一列不一定要是單位向量,可以是隨機的低維組合 φ_i(x) = p_iᵀx(只有 d″ 個非零分量)。原始 RF 在每次分支時考慮 d′ 個這樣的隨機投影。這時每個分支 b(x) 其實就是一個 perceptron。投影片的標語是「randomness everywhere!」。

OOB:免費的驗證

bootstrap 抽 N′ 個時,每一份 D̃_t 都有一些樣本沒被抽到,它們是 g_t 的 out-of-bag(OOB)樣本。N′ = N 而且 N 很大時,某個樣本不在 D̃_t 裡的機率是 (1 − 1/N)^N ≈ 1/e,所以每棵樹大約有 N/e 個 OOB 樣本。

OOB 樣本對 g_t 就像 validation 資料。拿它驗證單棵樹很容易,但很少需要;真正有用的是驗證整個 G:

E_oob(G) = (1/N) Σ_n err(y_n, G_n⁻(x_n)),其中 G_n⁻ 只由「沒看過 x_n 的那些樹」組成。

投影片稱這是 bagging/RF 的 self-validation,可以直接拿來做模型選擇,例如選 d″ 這類 RF 參數,而且不需要重新訓練。投影片說 E_oob 在實務上通常很準。

用 permutation test 算特徵重要度

特徵選擇想去掉兩種特徵:重複的(像同時有「年齡」和「完整生日」)與無關的(像用保險類型預測癌症)。好處是效率、泛化、可解釋性;壞處是組合最佳化很貴、可能 overfit、也可能被誤讀。投影片說決策樹是少數內建特徵選擇的模型。

如果能算出每個特徵的重要度,就能挑前 d′ 名。線性模型可以直接看 |w_i|,非線性模型就難了。RF 的做法是 permutation test:如果特徵 i 重要,把它的值換成隨機值,表現應該變差。為了不改變 x_i 的分布,把 {x_{n,i}} 在樣本之間打亂順序,而不是換成均勻或高斯亂數。

importance(i) = performance(D) − performance(D^(p))

一般來說 D^(p) 要重新訓練再驗證,原始 RF 用 OOB 繞過:importance(i) = E_oob(G) − E_oob^(p)(G),其中 E_oob^(p) 是在算 OOB 誤差時,把 x_{n,i} 換成打亂後的 OOB 值。投影片的評語是「通常有效率,而且實務上有希望」。

要幾棵樹

示範資料上,樹越多,邊界越平滑,看起來也越像大 margin。投影片的經驗例子是 KDD Cup 2013 Track 1(台大再次奪冠,任務是預測作者與論文的關係):幾千棵樹的 E_val 隨亂數種子落在 0.015 到 0.019,前 20 名隊伍的 E_out 也落在 0.014 到 0.019,最後決定用 12000 棵、種子 1。RF 的缺點因此是:隨機過程不穩定時可能需要非常多棵樹,要回頭檢查 G 的穩定性。

T11 Gradient Boosted Decision Tree

影片:AdaBoost Decision Tree、Optimization of AdaBoost、Gradient Boosting、Summary of Aggregation

AdaBoost-DTree:樹要夠弱

把 RF 的 bagging 換成 AdaBoost,需要一棵吃樣本權重的樹。不想改 DTree 的程式時,可以依 u^(t) 的比例抽樣出 D̃_t,再拿一般的 DTree 去學。

另一個問題是 AdaBoost 需要弱的基礎演算法。完全長大的樹在所有 x_n 不同時 E_in^u = 0,於是 ε_t = 0、α_t = ∞,投影片叫這個「獨裁」。所以要剪枝(或直接限制高度),而且只在抽樣出來的部分資料上訓練。

極端情況是高度 ≤ 1 的樹:如果 impurity 用二元分類錯誤率,它就是 decision stump。所以 AdaBoost-Stump 是 AdaBoost-DTree 的特例。

AdaBoost 的最佳化觀點

這一節是 T11 的核心,把上一講看起來很「魔法」的 α_t 重新推一次。

先看權重:答錯乘 ♦_t、答對除 ♦_t,可以統一寫成 u_n^(t+1) = u_n^(t)·exp(−y_n α_t g_t(x_n))。一路乘下來,u_n^(T+1) 正比於 exp(−y_n·Σ_t α_t g_t(x_n))。

Σ_t α_t g_t(x_n) 是 G 的投票分數。回想 T7 的 linear blending 和硬邊界 SVM,y_n 乘上投票分數就是一個有正負號、沒正規化的 margin。我們希望它是正的而且越大越好,也就是 exp(−y_n·分數) 越小越好。

投影片的主張是:AdaBoost 會讓 Σ_n u_n^(t) 下降,等於在某種程度上最小化 Σ_n exp(−y_n s_n)。其中 err_ADA(s, y) = exp(−ys) 是 0/1 誤差的凸上界,叫指數誤差。

推導:g_t 是近似的函數梯度方向,α_t 是最速下降的步長

找方向。第 t 輪想找一個函數 h 與步長 η,讓 Ê_ADA 下降:

Ê_ADA = (1/N) Σ_n exp(−y_n(Σ_{τ<t} α_τ g_τ(x_n) + η h(x_n))) = Σ_n u_n^(t) exp(−y_n η h(x_n)) ≈ Σ_n u_n^(t)(1 − y_n η h(x_n))(在 η = 0 附近做 Taylor 展開) = Σ_n u_n^(t) − η Σ_n u_n^(t) y_n h(x_n)

所以好的 h 要最小化 Σ_n u_n^(t)(−y_n h(x_n))。二元分類時 y_n、h(x_n) ∈ {−1, +1},這個量等於 −Σ_n u_n^(t) + 2·E_in^u(h)·N。最小化它,就是最小化加權的 E_in^u(h),而這正是 AdaBoost 裡基礎演算法 A 在做的事。

找步長。找到 g_t 後,不用固定的小 η,而是直接找讓 Ê_ADA 最小的 η(最速下降):

Ê_ADA = (Σ_n u_n^(t))·((1 − ε_t) exp(−η) + ε_t exp(+η))

對 η 微分設為 0,得到 η_t = ln √((1 − ε_t)/ε_t) = α_t。

結論:AdaBoost 就是用近似的函數梯度做最速下降。上一講的 α_t 其實就是最佳步長。HW7 Q6 要你證明的 U_{t+1}/U_t = 2√(ε_t(1 − ε_t)),就是這個下降量的精確版本。

Gradient boosting:換掉誤差函數

既然 AdaBoost 是對指數誤差做最速下降,把誤差換成任意的 err、把 h 換成實數輸出的假說,就得到 GradientBoost。它可以用在迴歸、軟分類等其他問題。

迴歸用平方誤差時,推導出來的結論很乾淨:

推導:平方誤差下,g_t 是對殘差的迴歸,α_t 是一維線性迴歸

令 s_n = Σ_{τ<t} α_τ g_τ(x_n),err(s, y) = (s − y)²。在 s_n 附近 Taylor 展開:

min_h (1/N) Σ_n err(s_n + η h(x_n), y_n) ≈ 常數 + (η/N) Σ_n h(x_n)·2(s_n − y_n)

如果 h 沒有限制,最佳解是 h(x_n) = −∞·(s_n − y_n),沒有意義。h 的大小不重要(η 之後會再最佳化),所以加上懲罰項 (h(x_n))²:

常數 + (η/N) Σ_n (2h(x_n)(s_n − y_n) + (h(x_n))²) = 常數 + (η/N) Σ_n (常數 + (h(x_n) − (y_n − s_n))²)

也就是在 {(x_n, y_n − s_n)} 上做平方誤差迴歸,y_n − s_n 就是殘差。

找到 g_t 後,α_t 是讓 Σ_n((y_n − s_n) − η g_t(x_n))² 最小的 η,也就是以 g_t(x_n) 為輸入、殘差為輸出的一維線性迴歸。

組起來就是 GBDT:

  1. s_1 = … = s_N = 0。
  2. 每一輪用(平方誤差的)迴歸演算法在 {(x_n, y_n − s_n)} 上學 g_t,投影片建議用抽樣加剪枝的 C&RT。
  3. α_t = OneVarLinearRegression({(g_t(x_n), y_n − s_n)})。
  4. 更新 s_n ← s_n + α_t g_t(x_n)。
  5. 回傳 G(x) = Σ_t α_t g_t(x)。

投影片稱 GBDT 是 AdaBoost-DTree 的「迴歸手足」,實務上很受歡迎。

Aggregation 模型總整理

T11 最後把整個第二段收成三張圖:

  • Blending(先有 g_t):uniform 是投票/平均,non-uniform 是在 g_t 轉換後的輸入上學線性模型,conditional 是學非線性模型。uniform 為了穩定;non-uniform 與 conditional 要小心複雜度。
  • Aggregation learning(邊學邊組):Bagging 靠 bootstrap 造多樣性、uniform 投票;AdaBoost 靠重新加權、以最速搜尋決定線性權重;決策樹靠切資料、以分支做 conditional 投票;GradientBoost 靠擬合殘差、以最速搜尋決定線性權重。投影片說 boosting 類的最受歡迎。
  • Aggregation of aggregation:RF = 隨機化的 bagging + 「強」的樹;AdaBoost-DTree = AdaBoost + 「弱」的樹;GBDT = GradientBoost + 「弱」的樹。三者實務上都很常用。

最後一張回到 T7 開頭的兩個直覺:aggregation 可以讓 G 變強,像特徵轉換,治 underfitting;也可以讓 G 變穩,像正則化,治 overfitting。適當的 aggregation(又稱 ensemble)帶來更好的表現。

用 Fall 2024 作業練習

HW7(2024-12-02 發布、12-16 截止)裡跟這三講相關的題目:

題類型練什麼
Q2自動批改把幾種 impurity 函數(分類錯誤率、平方誤差、entropy、closeness)除以最大值正規化後,哪一個和 Gini index 等價
Q6人工批改證明 U_{t+1}/U_t = 2√(ε_t(1 − ε_t));題目明寫對應 Lecture 208 與 211 的 AdaBoost
Q7人工批改gradient boosting 的基礎模型換成不帶正則化的線性迴歸時,證明或反駁最佳的 α_1 = 1
Q8人工批改GBDT 用最速的 η 當 α_t 更新完 s_n 後,證明 Σ_n (y_n − s_n) g_t(x_n) = 0,並思考殘差向量與 g_t 輸出向量的關係

這三講沒有程式題。想動手的話,可以把上一篇的 AdaBoost-Stump(HW7 Q10–12)改成 AdaBoost-DTree,或在同一份 madelon 資料上跑 scikit-learn 的 RandomForestClassifier,比較 oob_score_ 與測試集誤差,親手驗證「E_oob 通常很準」這句話。沒有官方解答,證明題只能靠自己或同學互相檢查。完整的作業導讀見技法作業與期末專題。

自學怎麼用這三講

  1. T9、T10 可以當作「讀懂 scikit-learn 參數」的課:max_depth、max_features、oob_score、feature_importances_ 背後分別是投影片的哪一段,看完應該都對得上。
  2. T11 的 Optimization of AdaBoost 最值得反覆看。把兩個折疊推導各自推一次,之後讀 gradient boosting 的任何變體都會輕鬆很多。
  3. 今晚可以做的一件事:用 numpy 寫 30 行的 GBDT(基礎模型用深度 2 的 DecisionTreeRegressor),在一維 sin 曲線加雜訊的資料上畫出第 1、5、20 輪的 G。你會看到每一輪都在補上一輪留下的殘差。

延伸閱讀

課程頁列的延伸閱讀:

站內其他課程對同一主題的講法(本篇內容不因此省略):

參考資料