變數該,還是該

ISLP 第 6 章 — 對應講義 06
最佳子集|逐步選擇|Cp|AIC|BIC|調整後 R²|Ridge L2|Lasso L1|PCR|PLS
向下捲動開始互動
📌 本頁使用方式(ISLP Ch.6|講義 06)

照節次讀:每節先讀說明,動手玩互動元件——先預測結果,再按按鈕驗證。 ② 對照講義:每個 §徽章都標了 ISLP 節號與講義頁碼,細節與完整推導請回講義與課本。 ③ 每節做 quiz:答錯就回到該節重讀,不要往下跳;錯的選項也寫了「錯在哪」。 ④ 最後翻關鍵詞彙卡自測術語,並用 REF 總覽當速查表。

CONTENTS · 內容目錄
PROLOGUE · 開場

最小平方法什麼時候會不夠用 ISLP §6 開頭講義 06 · p.2–5

第 3 章的最小平方法很好用:沒有調整參數、有封閉解、係數可以直接解讀。 這一章不是要換掉它,而是要問一句話:當變數很多的時候,「把全部變數丟進去做最小平方」 還是最好的做法嗎?答案通常是不。

問題出在兩個地方。第一是預測準確度:當 p 逼近 n,最小平方的估計會非常不穩定 (變異很大);當 p > n,它連唯一解都沒有——你可以找到無限多組係數把訓練誤差壓到 0, 而它們在新資料上都爛得一樣。第二是可解讀性:一堆跟 y 沒關係的變數留在模型裡, 最小平方幾乎不可能把它們的係數估成剛好 0,於是你得到一個沒人看得懂的模型。

這一章的三大類方法 1. 子集選擇(subset selection):挑出一部分變數, 只用它們做最小平方。最佳子集、前向逐步、後向逐步。
2. 收縮(shrinkage)/正則化:全部 p 個變數都留著,但把係數往 0 壓。 Ridge 用 L2 懲罰、Lasso 用 L1 懲罰(順便做變數選擇)。
3. 降維(dimension reduction):把 p 個變數投影成 M < p 個線性組合, 再對這 M 個新變數做最小平方。PCR 與 PLS。

三類方法都在做同一件事:用一點偏差換一大塊變異。最小平方是無偏的, 但在 p 大的時候變異大到讓它毫無用處;只要願意接受一點偏差,測試誤差往往降得很明顯。 整章的節奏都是這個交換。

$$\text{RSS} = \sum_{i=1}^{n}\left(y_i - \beta_0 - \sum_{j=1}^{p}\beta_j x_{ij}\right)^2$$

下面這張表先放在這裡,讀完整章再回來看一次會比較有感覺。

留幾個變數係數會剛好是 0 嗎有調整參數嗎座標系主要弱點
最小平方全部 p 個幾乎不會沒有原始變數p 大時變異爆炸
子集選擇k 個(自己選)沒被選的就是 0k原始變數搜尋空間太大、不穩定
Ridge(L2)全部 p 個不會λ原始變數不做變數選擇
Lasso(L1)由 λ 決定λ原始變數相關變數之間的選擇很不穩
PCR / PLS全部 p 個都參與不會M換過的座標新座標不好解讀
QUIZ · 為什麼要動手術

為什麼 p 逼近 n 的時候,「把全部變數丟進去做最小平方」是個壞主意?

(A) 因為係數估計的變異會變得非常大,訓練資料稍微變動一點,配出來的模型就差很多
(B) 因為最小平方法假設誤差是常態分佈,變數多了這個假設就不成立
(C) 因為變數多了以後 RSS 會變大,配適品質下降
PART 01 · 子集選擇

2^p 個模型跑不完:最佳子集與逐步選擇 ISLP §6.1講義 06 · p.6–14

最直白的想法:每一種變數組合都試一次,挑最好的。這就是最佳子集選擇 (best subset selection)。p 個變數有 2p 種組合(含空模型), 演算法分兩階段——先在每個大小 k 裡挑出訓練 RSS 最小的 Mk, 再從 M0, …, Mp 裡挑一個。

$$\text{總共要配} \; \sum_{k=0}^{p} \binom{p}{k} = 2^{p} \; \text{個模型}$$
為什麼一定要分兩階段 第一階段用訓練 RSS 挑同大小的贏家沒問題(同樣的 k, 比 RSS 是公平的)。第二階段絕對不能再用訓練 RSS——因為 RSS 隨 k 單調下降、 R² 隨 k 單調上升,你一定會選到全部變數。第二階段要用 Cp、AIC、BIC、調整後 R²,或直接用交叉驗證。

2p 長得太快,p 超過 40 就算不完了。前向逐步選擇 (forward stepwise selection)改成貪婪地走:從空模型開始,每一步加一個「讓 RSS 降最多」的變數。 後向逐步選擇(backward stepwise selection)反過來,從全模型開始每次砍一個。 兩者都只要配

$$1 + \sum_{k=0}^{p-1} (p-k) = 1 + \frac{p(p+1)}{2} \; \text{個模型}$$

p = 20 時這是 211 個,而最佳子集是 1,048,576 個。 代價是:貪婪走法不保證找到最佳子集。下面第二張圖用真實的 Credit 資料把這件事畫出來。

上面的滑桿看 2ᵖ 有多可怕;下面按「開始」看 forward 在真實資料上怎麼走。
p =10
要配幾個模型
p(變數個數)10
最佳子集 2ᵖ
forward 1+p(p+1)/2
差幾倍
前向逐步選擇的虛擬碼 CODE
M0 = 空模型 for k in range(p): 試 p−k 個「再加一個變數」 留 RSS 最小的 → M(k+1) 用 CV/Cp/BIC 從 M0…Mp 挑一個
Credit 的 4 變數格圖
這一步在試
選到的
同大小的最佳子集
RSS 差(百萬)
下圖怎麼看 圖 6.1
每一個點是一個子集(Balance ~ Limit + Rating + Cards + Student 的 16 種組合),x 是變數個數、y 是訓練 RSS。紅線是每個大小的最佳子集(ISLP 圖 6.1 的紅色前緣),綠線是 forward 走出來的路。
這張格圖的重點Credit 上,forward 第一步選 Rating、 第二步加 Student——到這裡都跟最佳子集一樣。但三變數的最佳子集是 Limit + Cards + Student(RSS 15.23 百萬),forward 卻只能給 Rating + Cards + Student(15.51 百萬)。原因是 forward 一旦選了 Rating不能再把它丟掉,而 LimitRating 幾乎共線,最佳子集會拿 Limit 換掉 Rating。 ISLP 表 6.1 在完整的 11 個變數上是同一個現象(第四個模型開始分歧)。

講義完整實作:Hitters、前向與後向逐步選擇

講義 06 · 載入 Hitters 並丟掉缺失值
Hitters = load_data('Hitters') Hitters.head() np.isnan(Hitters['Salary']).sum() Hitters = Hitters.dropna() Hitters.shape
預期輸出
(263, 20)

59 名球員的 Salary 是缺失的,dropna() 之後剩 263 列、20 欄(19 個預測變數+Salary)。整章的 Hitters 結果都建立在這 263 筆上。

來源:Ch06-varselect-lab-zh.ipynb · 儲存格 12、13、15
講義 06 · 自訂迴圈的前向逐步選擇
def forward(X, Y, predictors): # Pull out predictors we still need to process remaining_predictors = [p for p in X.columns if p not in predictors] results = [] for p in remaining_predictors: results.append(processSubset(X, Y, predictors+[p])) # Wrap everything up in a nice dataframe models = pd.DataFrame(results) # Choose the model with the lowest RSS best_model = models.loc[models['RSS'].idxmin()] return best_model def backward(X, Y, predictors): results = [] for combo in itertools.combinations(predictors, len(predictors)-1): results.append(processSubset(X, Y, list(combo))) # Wrap everything up in a nice dataframe models = pd.DataFrame(results) # Choose the model with the lowest RSS best_model = models.loc[models['RSS'].idxmin()] return best_model models1 = pd.DataFrame(columns=['RSS', 'model']) predictors = [] design = MS(Hitters.columns.drop('Salary')).fit(Hitters) Y = np.array(Hitters['Salary']) X = design.transform(Hitters) X = X.drop('intercept', axis=1) for i in range(1,len(X.columns)+1): models1.loc[i] = forward(X, Y, predictors) exog = models1.loc[i]['model'].model.exog_names.copy() exog.remove('const') predictors = exog print(i, predictors)
預期輸出
1 ['CRBI']
2 ['CRBI', 'Hits']
3 ['CRBI', 'Hits', 'PutOuts']
4 ['CRBI', 'Hits', 'PutOuts', 'Division[W]']
5 ['CRBI', 'Hits', 'PutOuts', 'Division[W]', 'AtBat']
6 ['CRBI', 'Hits', 'PutOuts', 'Division[W]', 'AtBat', 'Walks']
7 ['CRBI', 'Hits', 'PutOuts', 'Division[W]', 'AtBat', 'Walks', 'CWalks']
8 ['CRBI', 'Hits', 'PutOuts', 'Division[W]', 'AtBat', 'Walks', 'CWalks', 'CRuns']
9 ['CRBI', 'Hits', 'PutOuts', 'Division[W]', 'AtBat', 'Walks', 'CWalks', 'CRuns', 'CAtBat']
10 ['CRBI', 'Hits', 'PutOuts', 'Division[W]', 'AtBat', 'Walks', 'CWalks', 'CRuns', 'CAtBat', 'Assists']
11 ['CRBI', 'Hits', 'PutOuts', 'Division[W]', 'AtBat', 'Walks', 'CWalks', 'CRuns', 'CAtBat', 'Assists', 'League[N]']
12 ['CRBI', 'Hits', 'PutOuts', 'Division[W]', 'AtBat', 'Walks', 'CWalks', 'CRuns', 'CAtBat', 'Assists', 'League[N]', 'Runs']
13 ['CRBI', 'Hits', 'PutOuts', 'Division[W]', 'AtBat', 'Walks', 'CWalks', 'CRuns', 'CAtBat', 'Assists', 'League[N]', 'Runs', 'Errors']
14 ['CRBI', 'Hits', 'PutOuts', 'Division[W]', 'AtBat', 'Walks', 'CWalks', 'CRuns', 'CAtBat', 'Assists', 'League[N]', 'Runs', 'Errors', 'HmRun']
15 ['CRBI', 'Hits', 'PutOuts', 'Division[W]', 'AtBat', 'Walks', 'CWalks', 'CRuns', 'CAtBat', 'Assists', 'League[N]', 'Runs', 'Errors', 'HmRun', 'CHits']
16 ['CRBI', 'Hits', 'PutOuts', 'Division[W]', 'AtBat', 'Walks', 'CWalks', 'CRuns', 'CAtBat', 'Assists', 'League[N]', 'Runs', 'Errors', 'HmRun', 'CHits', 'RBI']
17 ['CRBI', 'Hits', 'PutOuts', 'Division[W]', 'AtBat', 'Walks', 'CWalks', 'CRuns', 'CAtBat', 'Assists', 'League[N]', 'Runs', 'Errors', 'HmRun', 'CHits', 'RBI', 'NewLeague[N]']
18 ['CRBI', 'Hits', 'PutOuts', 'Division[W]', 'AtBat', 'Walks', 'CWalks', 'CRuns', 'CAtBat', 'Assists', 'League[N]', 'Runs', 'Errors', 'HmRun', 'CHits', 'RBI', 'NewLeague[N]', 'Years']
19 ['CRBI', 'Hits', 'PutOuts', 'Division[W]', 'AtBat', 'Walks', 'CWalks', 'CRuns', 'CAtBat', 'Assists', 'League[N]', 'Runs', 'Errors', 'HmRun', 'CHits', 'RBI', 'NewLeague[N]', 'Years', 'CHmRun']

讀這段輸出的正確方式是看每一行是不是前一行的超集合CRBI → 加 Hits → 加 PutOuts…一路只加不減。這正是前向逐步的定義,也正是它可能錯過最佳子集的原因。

來源:Ch06-varselect-lab-zh.ipynb · 儲存格 33、34
講義 06 · 後向逐步選擇(BIC 挑出來的大小不一樣)
models2 = pd.DataFrame(columns=['RSS', 'model'], index = range(1, len(X.columns))) predictors = X.columns # we start with full model Mp models2.loc[len(predictors)] = processSubset(X, Y, predictors) while(len(predictors) > 1): models2.loc[len(predictors)-1] = backward(X, Y, predictors) exog = models2.loc[len(predictors)-1]['model'].model.exog_names.copy() exog.remove('const') predictors = exog print(len(predictors), predictors) bic_b = [] for m in models2.model: bic_b.append(m.bic) np.array(bic_b).argmin()
預期輸出
np.int64(7)

bic_b 是照 models2 的索引順序(1、2、…、19)收集的,0-based 的 argmin() = 7 指的是第 8 個元素,也就是 8 變數模型;而前向那邊(下一節)是 6 變數。同一份資料、同一個準則,兩個搜尋方向給出不同大小的模型——講義第 42 頁講的就是這件事。

來源:Ch06-varselect-lab-zh.ipynb · 儲存格 40、41
搜尋法要配幾個模型p = 20 時n < p 能用嗎保證找到最佳子集嗎
最佳子集2p1,048,576不能(最多到 n−1 個變數)
前向逐步1 + p(p+1)/2211可以不保證
後向逐步1 + p(p+1)/2211不能(要先配全模型)不保證
混合逐步略多於逐步約 211+看實作不保證(但比較接近)
QUIZ · 子集選擇

同一份資料上做最佳子集、前向逐步、後向逐步。大小同樣是 k 的三個模型裡,哪一個的訓練 RSS 最小?

(A) 最佳子集的一定最小(或並列最小),因為它窮舉了所有 k 變數子集
(B) 三個一定相同,因為它們都是在同一份資料上做最小平方
(C) 後向逐步的最小,因為它從全模型開始,資訊最完整
PART 02 · 選模型的準則

Cp、AIC、BIC、調整後 R²:懲罰項在做什麼 ISLP §6.1.3講義 06 · p.15–24

第二階段的問題是:怎麼比較「大小不同」的模型?訓練 RSS 與 R² 不能用, 因為它們單調偏好大模型。兩條路——間接(把訓練誤差加一個懲罰項,修掉它的樂觀偏差) 與直接(用驗證集或交叉驗證真的去估測試誤差,下一節講)。

間接法的四個常客。設模型有 d 個預測變數、σ̂² 是用全模型估出來的誤差變異數:

$$C_p = \frac{1}{n}\left(\mathrm{RSS} + 2 d \hat\sigma^2\right), \qquad \mathrm{BIC} = \frac{1}{n}\left(\mathrm{RSS} + \log(n)\, d \hat\sigma^2\right)$$ $$\text{Adjusted } R^2 = 1 - \frac{\mathrm{RSS}/(n-d-1)}{\mathrm{TSS}/(n-1)}$$

兩個公式長得幾乎一樣,只差在每多一個變數要罰多少:Cp 罰 2σ̂², BIC 罰 log(n)·σ̂²。因為 n > 7 就有 log n > 2,BIC 罰得比 Cp 重,所以偏好更小的模型。 n 愈大這個差距愈誇張——Credit 的 n = 400,log 400 ≈ 5.99,BIC 的懲罰是 Cp 的三倍。

AIC 與 Cp 的關係 對高斯誤差的最小平方模型,課本的 AIC 就是 RSS + 2dσ̂²,跟 Cp 成正比(所以 ISLP 圖 6.2 只畫 Cp)。 但實作(statsmodels.aic)用的是 log-likelihood 版 −2·log L + 2k,它跟 Cp 不是單調對應——所以下圖把它畫成獨立一條線。 兩個版本都叫 AIC,看到數字差很多不要慌,先問是哪一個公式。
圖表需要連網載入 Chart.js。此圖的重點:Credit 上 Cp 選 6 個變數、BIC 選 4 個、調整後 R² 選 7 個——同一份資料,四個準則挑出三種答案,而 BIC 因為懲罰項是 log n 而不是 2,明顯偏好小模型。
Credit 全部 2¹¹ 個子集窮舉後,五個準則畫在同一張圖上。
各準則挑出的大小 Credit n=400
Cp
AIC(log-likelihood 版)
BIC
調整後 R²
10-fold CV 誤差
怎麼看這張圖 圖 6.2/6.3
每一條線是一個準則在「最佳 d 變數模型」上的值,大圓點是它自己的最佳位置。預設把五條線各自正規化到 0–1(0 = 該準則最好),這樣單位完全不同的五個量才能放在一起比。按「切換原始單位」可以看 Cp、BIC、CV 誤差的真實數值(都是 MSE 單位)。
最重要的一件事
四條曲線從 d = 4 之後幾乎是平的。不要為了「哪個數字最小」去爭論——Cp 在 d=6 是 9846.8、在 d=4 是 9982.8,差 1.4%,遠在雜訊範圍內。看的是曲線在哪裡拉平。
準則式子(最小平方)每多一個變數罰多少n=400 時的懲罰Credit 選出
Cp(RSS + 2dσ̂²)/n2σ̂²2σ̂²6 個
AIC(課本)RSS + 2dσ̂²2σ̂²與 Cp 成正比同 Cp
BIC(RSS + log(n)·dσ̂²)/nlog(n)·σ̂²5.99σ̂²4 個
調整後 R²1 − [RSS/(n−d−1)] / [TSS/(n−1)]分母的 n−d−1 變小很輕7 個
交叉驗證直接估測試誤差不需要 σ̂²6 個
觀念釐清
Q:Cp、AIC、BIC 到底差在哪?為什麼 BIC 偏好小模型?

三個都是「訓練 RSS + 一個隨模型變大而變大的懲罰」。差別只在懲罰的係數:Cp 與課本版 AIC 都是 $2d\hat\sigma^2$,BIC 是 $\log(n)\, d\hat\sigma^2$。$\log n > 2$ 對任何 $n > 7$ 都成立($e^2 \approx 7.39$),所以 BIC 一律罰得比較重,選出來的模型一律比較小或一樣大。n = 400 時 $\log n \approx 5.99$,懲罰差三倍。

背後的動機不同。Cp 是估測試 MSE:可以證明只要 $\hat\sigma^2$ 是 $\sigma^2$ 的無偏估計,Cp 就是測試 MSE 的無偏估計。BIC 是從貝氏觀點來的,它在近似「這個模型是真模型的後驗機率」。所以兩者的目標本來就不一樣:Cp/AIC 想預測得準,BIC 想找出正確的模型。如果真模型確實在候選清單裡,n 夠大時 BIC 會挑中它(一致性);AIC 不保證,它會傾向多留幾個變數。

實務上的建議:目的是預測就用 CV(或 AIC/Cp),目的是「哪些變數真的有關」就參考 BIC。而且兩者都要求你估得出 $\hat\sigma^2$——這在 p > n 的時候直接破功(最後一節會講)。

Q:調整後 R² 為什麼「理論基礎比較弱」?

Cp、AIC、BIC 都有明確的推導:Cp 是測試 MSE 的無偏估計,AIC 來自 Kullback–Leibler 距離的漸近論證,BIC 來自後驗機率的 Laplace 近似。調整後 R² 沒有這種東西——它就是「把 RSS 除以 $n-d-1$ 而不是 n」這個直覺上合理的修正。

它的直覺是對的:真正有用的變數都進來以後,再加雜訊變數只會讓 RSS 降一點點,但 $d$ 變大會讓分母 $n-d-1$ 變小,兩者相抵之下 $\mathrm{RSS}/(n-d-1)$ 會變大、調整後 R² 會下降。問題是「一點點」有多點沒有理論刻度,所以它的懲罰強度是任意的——在 Credit 上它比 Cp 還鬆(選 7 個 vs 6 個)。

順便記一件事:調整後 R² 在 p > n 時可以輕易做到 1,所以高維度下它完全不能用。

講義完整實作:用 BIC 與調整後 R² 挑大小

講義 06 · 前向路徑上的 BIC
bic_f = [] for m in models1.model: bic_f.append(m.bic) np.array(bic_f).argmin() bic_f[5]
預期輸出
np.float64(3812.2130777982)

argmin() 回傳 5,而 bic_f 是 0-based 的 list,所以指的是清單的第 6 個元素——6 變數模型,BIC = 3812.21。注意下一格的 models1.model[5] 用的是 pandas 的標籤索引,取到的是 5 變數模型(輸出列出 5 個特徵)。同一個 5,兩種索引意義完全不同,讀別人的程式碼時要分清楚。

來源:Ch06-varselect-lab-zh.ipynb · 儲存格 36、37
講義 06 · 最佳子集 + 調整後 R²
def adjust_r2(r2, num_examples, num_features): coef = (num_examples - 1) / (num_examples - num_features - 1) return 1 - (1 - r2) * coef adj_r2 = [] for i, r2 in enumerate(r11): adj_r2.append(adjust_r2(r2=r2, num_examples=X.shape[0], num_features=i+1)) results2['sub'][11]
預期輸出
('AtBat',
 'Hits',
 'Walks',
 'CAtBat',
 'CRuns',
 'CRBI',
 'CWalks',
 'League[N]',
 'Division[W]',
 'PutOuts',
 'Assists')

這是 adjust_r2() 的定義(就是式 6.4)加上在最佳子集前緣上取最大值。Hitters 上調整後 R² 選出 11 個變數;BIC 選 6 個。兩個準則差了 5 個變數——這不是誰算錯,是兩個準則的懲罰強度本來就不同。

來源:Ch06-varselect-lab-zh.ipynb · 儲存格 97、98、101
QUIZ · 選模型的準則

同一份資料上,BIC 選出的模型大小,跟 Cp 選出的比起來?

(A) 一定小於或等於(n > 7 時),因為 BIC 每多一個變數要罰 log(n)·σ̂² 而 Cp 只罰 2σ̂²
(B) 不一定,取決於資料裡有多少真的有用的變數
(C) 一定一樣,因為兩者都是測試 MSE 的無偏估計
PART 03 · 用 CV 選模型

驗證與交叉驗證,以及 one-standard-error 規則 ISLP §6.1.3講義 06 · p.22–24

Cp、AIC、BIC 都需要估 $\hat\sigma^2$,而在 p 接近 n 的時候那個估計本身就不可靠。 交叉驗證不需要 $\hat\sigma^2$、不需要知道自由度、也不需要假設模型是對的—— 它直接估測試誤差。所以只要算得動,CV 是首選。

做法就是第 5 章那一套,只是把「模型」換成「模型大小」:對每個大小 k, 在每一折的訓練部分做子集選擇、在驗證折上算誤差。 注意選變數這件事必須關在折裡面——這正是第 5 章 P06 講的那個錯誤。

one-standard-error 規則 CV 誤差本身有抽樣變異。Credit 上的 CV 曲線在大小 4 到 8 之間幾乎是平的, 差異遠小於誤差棒。這時候硬選最低點沒有道理,因為那個「最低」很可能只是運氣。

規則:先找到 CV 誤差最小的模型,算出它的標準誤;然後在「CV 誤差落在 最小值 + 一個標準誤」以內的所有模型裡,選最簡單的那個。

Credit 資料上 CV 選 6 個變數,one-SE 規則選 4 個—— 少兩個變數,預測能力在統計上分不出差別。上一節那張圖的橘色線就是 10-fold CV 誤差, 大圓點是它的最低點。
講義 06 · 用 GridSearchCV 選調整參數
grid = skm.GridSearchCV(pipe, param_grid, cv=kfold, scoring='neg_mean_squared_error') grid.fit(X, Y) grid.best_params_['ridge__alpha'] grid.best_estimator_
預期輸出
Pipeline(steps=[('scaler', StandardScaler()),
                ('ridge', Ridge(alpha=np.float64(2.494832928915928)))])

Pipeline 是關鍵:把標準化包進去,GridSearchCV 就會在每一折的訓練部分重新 fit scaler,而不是用全部資料的平均與標準差。這一步做錯,CV 誤差會偏低而且不會報錯。

來源:Ch06-varselect-lab-zh.ipynb · 儲存格 134
觀念釐清
Q:既然 CV 最好,為什麼還要教 Cp、AIC、BIC?

三個理由。第一,算力:最佳子集有 $2^p$ 個模型,每個都跑 k-fold 是 $k \cdot 2^p$ 次配適;而 Cp 只要一次配適加一個修正項。第二,這三個準則會出現在別人的論文與報表裡,你得看得懂。第三,它們解釋了「懲罰複雜度」這個想法的來源——AIC 從 KL 散度來、BIC 從後驗機率來,各有各的目標。

但如果你只是要挑一個模型來預測,而且資料量算得動:用 CV。

Q:one-SE 規則會不會選出「太簡單」的模型?

會,而且那是刻意的。它的立場是:在預測能力分不出差別時,偏好簡單

這個偏好有實際理由——變數少的模型更好解釋、需要蒐集的資料更少、上線後更不容易因為某個變數的定義改變而壞掉。如果你的目標純粹是最小化預測誤差而完全不在意這些,那就選最低點;但要記得那個「最低」在下一份資料上很可能換人。

QUIZ · one-SE 規則

CV 誤差在模型大小 4、5、6、7 上分別是 54100、53900、53800、53850,而最小值的標準誤是 6000。one-SE 規則會選哪一個?

(A) 4 個變數,因為 54100 落在 53800 + 6000 = 59800 以內,而它是這些之中最簡單的
(B) 6 個變數,因為 53800 是最小的
(C) 5 個變數,因為它在 4 和 6 之間取折衷
PART 04 · Ridge 迴歸

把係數往零壓:L2 懲罰與係數路徑 ISLP §6.2.1講義 06 · p.25–32

子集選擇是離散的:一個變數要嘛在、要嘛不在。這讓它變異很大—— 資料動一點,選出來的變數就換一批。另一條路是留下全部變數,但把係數往零壓

Ridge 在原本的 RSS 上加一個 L2 懲罰:

$$\sum_{i=1}^{n}\left(y_i - \beta_0 - \sum_{j=1}^{p}\beta_j x_{ij}\right)^2 + \lambda \sum_{j=1}^{p} \beta_j^2 \;=\; \mathrm{RSS} + \lambda \|\beta\|_2^2$$

$\lambda = 0$ 就是最小平方;$\lambda \to \infty$ 所有係數趨近 0。 注意截距 $\beta_0$ 不罰——罰它等於在乎你把 y 的原點放在哪裡。

圖表需要連網載入 Chart.js。此圖的重點:λ 變大時所有係數一起往零收縮,但沒有任何一個變成剛好 0。
圖表需要連網載入 Chart.js。此圖的重點:λ 增加時變異快速下降、偏差緩慢上升,測試 MSE 因此先降後升。
拖動滑桿看係數怎麼收縮。
怎麼看上圖 圖 6.4
x 軸可以切換 log λ 與 ‖β̂ᴿ‖₂ ⁄ ‖β̂‖₂(相對收縮量)。每條線是一個變數的係數。注意它們一起往中線靠,但到最右邊仍然沒有任何一條落在 0 上。
目前的 λ
λ
‖β̂ᴿ‖₂ ⁄ ‖β̂‖₂
非零係數
下圖:偏差–變異 圖 6.5
模擬資料上把測試 MSE 拆成偏差²、變異、不可縮減誤差。變異從 59.1 掉到 0.2,偏差² 從 0.4 升到 17.6——中間有一段 λ 讓總和比最小平方(λ→0)更低,這就是 Ridge 划算的地方。
講義 06 · Ridge 與係數的 L2 範數
#ridge = skl.ElasticNet(alpha=lambdas[59], l1_ratio=0) ridge = skl.Ridge(alpha=lambdas[59]* n_samples) scaler = StandardScaler(with_mean=True, with_std=True) pipe = Pipeline(steps=[('scaler', scaler), ('ridge', ridge)]) pipe.fit(X, Y) np.linalg.norm(ridge.coef_)
預期輸出
np.float64(160.42371017725918)

ElasticNetl1_ratio=0 就是純 Ridge。係數的 L2 範數會隨 λ 單調下降——這個數字就是上圖 x 軸的分子。

來源:Ch06-varselect-lab-zh.ipynb · 儲存格 122、124
講義 06 · 用 RidgeCV 選 λ
ridgeCV = skl.RidgeCV(alphas=lambdas, cv=kfold) pipeCV = Pipeline(steps=[('scaler', scaler), ('ridge', ridgeCV)]) pipeCV.fit(X, Y)
預期輸出
Pipeline(steps=[('scaler', StandardScaler()),
                ('ridge',
                 RidgeCV(alphas=array([2.22093791e+05, 1.76005531e+05, 1.39481373e+05, 1.10536603e+05,
       8.75983676e+04, 6.94202082e+04, 5.50143278e+04, 4.35979140e+04,
       3.45506012e+04, 2.73807606e+04, 2.16987845e+04, 1.71959156e+04,
       1.36274691e+04, 1.07995362e+04, 8.55844774e+03, 6.78242347e+03,
       5.37495461e+03, 4.25955961e+03, 3.375...
       1.84386167e-03, 1.46122884e-03, 1.15799887e-03, 9.17694298e-04,
       7.27257037e-04, 5.76338765e-04, 4.56738615e-04, 3.61957541e-04,
       2.86845161e-04, 2.27319885e-04, 1.80147121e-04, 1.42763513e-04,
       1.13137642e-04, 8.96596467e-05, 7.10537367e-05, 5.63088712e-05,
       4.46238174e-05, 3.53636122e-05, 2.80250579e-05, 2.22093791e-05]),
                         cv=KFold(n_splits=5, random_state=0, shuffle=True)))])

RidgeCV 把「掃 λ + 交叉驗證」包成一步。注意 alphas 要給一整排值,而且照慣例是由大到小掃,因為暖啟動(warm start)從收縮較重的解開始比較快收斂。

來源:Ch06-varselect-lab-zh.ipynb · 儲存格 144、145
Ridge 之前一定要標準化 懲罰項 $\sum \beta_j^2$ 對單位敏感。 同一個變數用「元」還是「千元」為單位,最小平方的預測完全一樣(係數等比例調整), 但 Ridge 不是——係數變大 1000 倍,懲罰項就變大 10⁶ 倍,這個變數會被壓得特別兇。

所以標準做法是先把每個 $x_j$ 標準化成標準差 1 再配適。scikit-learn 的解法是 Pipeline([('scaler', StandardScaler()), ('ridge', Ridge())]), 順便解決了 CV 的洩漏問題。
QUIZ · Ridge

把某個預測變數的單位從「元」改成「千元」(數值除以 1000)。Ridge 的預測會變嗎?

(A) 會變,因為 L2 懲罰對單位敏感——這正是為什麼要先標準化
(B) 不會,因為線性模型對預測變數的線性變換不變
(C) 不會,因為 scikit-learn 會自動標準化
PART 05 · Lasso 與稀疏性

L1 為什麼會把係數壓成剛好 0 ISLP §6.2.2講義 06 · p.33–41

Ridge 的缺點是:它留下全部 p 個變數。p = 500 的時候你得到 500 個很小但不為零的係數, 模型一點也不好解釋。Lasso 把 L2 換成 L1

$$\mathrm{RSS} + \lambda \sum_{j=1}^{p} |\beta_j| \;=\; \mathrm{RSS} + \lambda \|\beta\|_1$$

只差一個平方,行為完全不同:λ 夠大時 Lasso 會把一部分係數壓成剛好 0, 於是它同時做了收縮與變數選擇。這種解叫做稀疏(sparse)。

為什麼 L1 會歸零、L2 不會

把兩者寫成等價的約束型式($s$ 是預算,跟 $\lambda$ 一對一對應):

$$\min_{\beta} \mathrm{RSS} \quad \text{s.t.} \quad \|\beta\|_1 \le s \;\;(\text{Lasso,菱形}) \qquad\text{或}\qquad \|\beta\|_2^2 \le s \;\;(\text{Ridge,圓})$$

RSS 的等高線是以 $\hat\beta^{\mathrm{OLS}}$ 為中心的同心橢圓。解就是 橢圓第一次碰到約束區域的那一點。菱形有尖角而且尖角剛好落在座標軸上, 所以碰撞很容易發生在尖角——那裡有一個座標是 0。圓沒有尖角,碰到座標軸是機率 0 的事。

紅色橢圓是 RSS 等高線,藍色區域是約束。解在兩者相切處。
動手玩 圖 6.7
拖動滑桿縮小預算 s,看解怎麼被推出去。切換 L1/L2 比較兩者的接觸點:L1 的解常常「卡」在尖角上(某個係數變成剛好 0),L2 的解只是變小、方向幾乎不變。
這個 s 之下的解
預算 s
β₁
β₂
有幾個剛好是 0
RSS
看不到尖角效應?
把 s 調到 1.5 以下,並注意橢圓的傾斜方向。β̂ 的兩個座標差得愈多,尖角效應愈明顯——這也解釋了為什麼真實係數本來就稀疏時 Lasso 特別佔優勢。
圖表需要連網載入 Chart.js。此圖的重點:λ 變大時係數一個一個變成剛好 0,最後只剩幾個變數存活。
拖動滑桿看變數一個一個被淘汰。
怎麼看 圖 6.6
跟 Ridge 那張圖同樣的畫法,但這裡的線會真的碰到 0 並停在 0。右側清單是在目前這個 λ 之下還沒被歸零的變數。
目前的 λ
λ
非零係數
CV 選出的 λ364.76
存活的變數
講義 06 · Lasso 與被歸零的係數
lassoCV = skl.ElasticNetCV(n_alphas=100, l1_ratio=1, cv=kfold) pipeCV = Pipeline(steps=[('scaler', scaler), ('lasso', lassoCV)]) pipeCV.fit(X, Y) tuned_lasso = pipeCV.named_steps['lasso'] tuned_lasso.alpha_ tuned_lasso.coef_
預期輸出
array([-210.01008773,  243.4550306 ,    0.        ,    0.        ,
          0.        ,   97.69397357,  -41.52283116,   -0.        ,
          0.        ,   39.62298193,  205.75273856,  124.55456561,
       -126.29986768,   15.70262427,  -59.50157967,   75.24590036,
         21.62698014,  -12.04423675,   -0.        ])

注意輸出裡有剛好等於 0 的係數——那不是「很小」,是真的 0。這是 Lasso 跟 Ridge 最實際的差別:你可以直接說「這些變數被模型丟掉了」。

來源:Ch06-varselect-lab-zh.ipynb · 儲存格 162、172
觀念釐清
Q:Lasso 一定比 Ridge 好嗎?

不一定,取決於真實的係數結構

如果真的只有少數幾個變數有用(真實係數稀疏),Lasso 佔優勢——它能把沒用的丟掉,省下估計它們所花的變異。如果很多變數都有小小的貢獻(係數密集),Ridge 通常較好——Lasso 會硬把一些真的有用的變數歸零,付出偏差的代價。

而你事前並不知道是哪一種。實務作法是兩個都跑、用 CV 比較,或直接用 elastic net(同時放 L1 與 L2 懲罰)讓資料自己決定混合比例。

Q:Lasso 選出來的變數,可以說它們「顯著」嗎?

不能。Lasso 的變數選擇沒有附帶 p 值,而且「先用資料選變數、再對選出來的變數做 t 檢定」會嚴重高估顯著性——那是同一份資料用了兩次,跟第 5 章的 CV 誤用是同一個病。

要做選後推論(post-selection inference)需要專門的方法(selective inference、debiased lasso 等),已經超出本課範圍。實務上的誠實說法是:「在這個 λ 之下,Lasso 保留了這些變數」,而不是「這些變數顯著」。

Q:兩個高度相關的變數,Lasso 會怎麼處理?

傾向隨機留一個、丟另一個——因為留一個就夠解釋,留兩個要多付一份 L1 懲罰。

問題是「留哪一個」很不穩定,資料動一點就換人。這在解釋上很危險:你可能報告「基因 A 重要、基因 B 不重要」,而重跑一次結論就反過來。

Ridge 相反,它會讓相關的變數平分係數。想要「同進同出」的行為,elastic net 或 group lasso 是更合適的工具。

QUIZ · Lasso 的幾何

為什麼 L1 約束區域(菱形)會讓解落在座標軸上,而 L2(圓)不會?

(A) 菱形的尖角剛好在座標軸上,橢圓等高線很容易先碰到尖角;圓處處平滑,碰到軸是機率 0 的事
(B) 因為 L1 懲罰比 L2 懲罰強,把係數壓得更兇
(C) 因為 Lasso 用的是絕對值,絕對值函數在 0 沒有定義
PART 06 · 怎麼選 λ

調整參數也要用 CV 選 ISLP §6.2.3講義 06 · p.42–45

λ 是調整參數(tuning parameter),不是從資料估出來的參數。 選它的方法跟第 5 章選多項式次數完全一樣:掃一排候選值,用交叉驗證比較。

  1. 選一排 λ(通常是對數等距,例如從 10⁻² 到 10⁵ 取 100 個點)。
  2. 對每個 λ 做 k-fold CV,得到 CV 誤差。
  3. 選 CV 誤差最小的 λ,或用 one-SE 規則選一個更大(更收縮)的 λ。
  4. 用全部資料在那個 λ 上重配一次,交出這個模型。

Credit 資料上 Lasso 的 CV 選出 λ = 364.76, 在那個 λ 之下 11 個變數全部還活著——這份資料的係數並不稀疏, 所以 Lasso 沒有真的丟掉東西。這是個誠實的結果,不是失敗: Lasso 沒有義務一定要歸零。

為什麼用對數等距而不是等距 因為 λ 的作用是乘性的。從 1 到 2 的改變跟從 1000 到 1001 的改變完全不同量級——前者讓懲罰加倍,後者幾乎沒差。等距取樣會把幾乎全部的點浪費在 「懲罰太重、係數全被壓平」的那一端。

np.logspace(-2, 5, 100)10**np.linspace(a, b, 100) 才是對的做法。
講義 06 · 用 ElasticNetCV 選 λ 並取最小 CV 誤差
np.min(tuned_lasso.mse_path_.mean(1))
預期輸出
np.float64(114690.73118253677)

mse_path_ 的形狀是(λ 個數 × 折數),.mean(1) 先對折取平均、再取最小值,就是 CV 曲線的最低點。

來源:Ch06-varselect-lab-zh.ipynb · 儲存格 162、168
QUIZ · 選 λ

用 CV 選好 λ 之後,最終交出的模型應該是?

(A) 用全部資料、在選出的那個 λ 上重配一次的模型
(B) k 折各自配出來的模型的平均
(C) CV 誤差最小的那一折所配出來的模型
PART 07 · 主成分迴歸 PCR

先降維再迴歸:方向由 X 自己決定 ISLP §6.3.1講義 06 · p.46–55

第三條路:不動變數,改換座標。先把 p 個相關的預測變數壓成 M 個互不相關的方向(M ≪ p),再對這 M 個方向做最小平方。

主成分迴歸(principal components regression, PCR)用的方向就是第 12 章的主成分: 第一主成分是 X 變異最大的方向,第二個是在跟第一個正交的條件下變異最大的方向,依此類推。

$$Z_m = \sum_{j=1}^{p} \phi_{jm} X_j, \qquad y_i = \theta_0 + \sum_{m=1}^{M} \theta_m z_{im} + \varepsilon_i$$

M 是調整參數,同樣用 CV 選。M = p 時 PCR 就退回最小平方(只是換了個座標); M 小的時候,被丟掉的那些低變異方向就是被收縮掉的部分。

灰點是資料,兩條線分別是 PC1 與 PLS1 的方向。
PCA 方向 vs PLS 方向 圖 6.14–6.15
拖動滑桿改變 y 對兩個 x 的依賴方向。藍線 PC1 只看 X 的散佈,所以完全不動紅線 PLS1 也看 y,所以會跟著轉。
目前的方向
y 的真實方向
PC1 方向
PLS1 方向
PC1 與真實方向的夾角
這說明了什麼
PCR 的方向完全是非監督式的——它假設「X 變異大的方向也是跟 y 有關的方向」。這個假設常常成立,但沒有保證。PLS 讓 y 參與挑方向,所以在這個假設不成立時表現較好。
講義 06 · 用 CV 選主成分個數 M
param_grid = {'pca__n_components': range(1, 20)} grid = skm.GridSearchCV(pipe, param_grid, cv=kfold, scoring='neg_mean_squared_error') grid.fit(X, Y)
預期輸出
GridSearchCV(cv=KFold(n_splits=5, random_state=0, shuffle=True),
             estimator=Pipeline(steps=[('scaler', StandardScaler()),
                                       ('pca', PCA(n_components=2)),
                                       ('linreg', LinearRegression())]),
             param_grid={'pca__n_components': range(1, 20)},
             scoring='neg_mean_squared_error')

pca__n_components 這種雙底線寫法是 Pipeline 的參數命名慣例:步驟名 + __ + 該步驟的參數名。標準化同樣包在 pipeline 裡,PCA 必須在標準化之後做——不然變異數大的變數會主宰第一主成分。

來源:Ch06-varselect-lab-zh.ipynb · 儲存格 180、182
講義 06 · 各主成分解釋了多少變異
pipe.named_steps['pca'].explained_variance_ratio_
預期輸出
array([0.3831424 , 0.21841076])

explained_variance_ratio_ 就是第 12 章的 PVE。累加起來可以回答「留幾個主成分才夠」。

來源:Ch06-varselect-lab-zh.ipynb · 儲存格 188
觀念釐清
Q:PCR 算不算變數選擇?

不算。每一個主成分都是全部 p 個原始變數的線性組合,所以就算你只留 M = 2 個主成分,最終模型仍然用到了每一個原始變數。

這是 PCR 跟 Lasso 最重要的差別:Lasso 給你「這 5 個變數有用、其餘丟掉」;PCR 給你「這 2 個方向有用」,而每個方向都攪拌了所有變數。後者在解釋上通常更難——你得去看 loadings 才知道那個方向大致代表什麼。

Q:PCR 之前為什麼一定要標準化?

因為主成分是「變異最大的方向」,而變異數的大小完全取決於單位。

Credit 資料裡 Limit 的數值是幾千、Cards 是個位數。不標準化的話,第一主成分幾乎就等於 Limit 本身——不是因為它最重要,而是因為它的單位最大。第 12 章的 USArrests biplot 有更戲劇性的例子。

QUIZ · PCR

PCR 用 M = 2 個主成分。最終模型用到了幾個原始預測變數?

(A) 全部 p 個,因為每個主成分都是所有原始變數的線性組合
(B) 2 個,就是 loadings 最大的那兩個
(C) 不確定,要看 CV 選出多少
PART 08 · 偏最小平方 PLS

讓 y 也參與挑方向 ISLP §6.3.2講義 06 · p.56–58

PCR 挑方向時完全沒看 y。這有點浪費——我們明明知道 y 是什麼。

偏最小平方(partial least squares, PLS)修掉這一點:第一個方向的權重直接取 $\phi_{j1} \propto$ 每個 $X_j$ 與 $y$ 的簡單線性迴歸係數, 也就是跟 y 相關性愈強的變數,權重愈大。 取完第一個方向後,把各變數對它迴歸取殘差,再在殘差上重複同樣的步驟得到第二個方向。

上一節那個元件就是在演這件事:拖滑桿改變 y 的方向,PLS1 跟著轉、PC1 不動。

方向怎麼挑有沒有用到 y做變數選擇嗎何時較好
PCRX 變異最大的方向沒有沒有X 的主要變異方向剛好跟 y 有關時
PLS跟 y 相關性最強的方向沒有X 的大變異方向跟 y 無關時
Ridge不換座標,全部收縮有(配適時)沒有很多變數都有小貢獻
Lasso不換座標,部分歸零有(配適時)真實係數稀疏

實務上 PLS 的表現常常跟 PCR 差不多,有時還略差。原因是: 它雖然降低了偏差(方向跟 y 有關),但也增加了變異(方向是估出來的,而且用到了 y)。 ISLP §6.3.2 的結論就是這樣:PLS 沒有一致地贏過 PCR 或 Ridge。

講義 06 · 用 CV 選 PLS 的成分個數
param_grid = {'n_components':range(1, 20)} grid = skm.GridSearchCV(pls, param_grid, cv=kfold, scoring='neg_mean_squared_error') grid.fit(X, Y)
預期輸出
GridSearchCV(cv=KFold(n_splits=5, random_state=0, shuffle=True),
             estimator=PLSRegression(),
             param_grid={'n_components': range(1, 20)},
             scoring='neg_mean_squared_error')

PLSRegressionn_components 跟 PCR 的 n_components 是同一個角色的調整參數,一樣用 CV 選。注意它預設 scale=True,已經幫你標準化了。

來源:Ch06-varselect-lab-zh.ipynb · 儲存格 192、194
QUIZ · PLS

PLS 相對於 PCR 的差別是什麼?

(A) 挑方向時用到了 y,所以方向會跟著 y 轉;但降維與不做變數選擇這兩點跟 PCR 一樣
(B) PLS 會把不重要的變數歸零,所以比 PCR 好解釋
(C) PLS 不需要標準化,PCR 需要
PART 09 · 高維度的陷阱

p 逼近 n 時 R² 會騙你騙得很徹底 ISLP §6.4講義 06 · p.59–66

基因資料、文字資料、感測器資料常常是 p 遠大於 n: 幾萬個變數、幾百個樣本。這時候最小平方不只是「表現不好」,而是徹底失效

當 p ≥ n 時,最小平方能找到一組係數完美通過每一個訓練點—— 殘差全部是 0、R² 剛好等於 1。這不是模型好,而是自由度用完了: n 個方程式、p ≥ n 個未知數,解不唯一而且必然過度配適。

圖表需要連網載入 Chart.js。此圖的重點:p 從 1 增到 n = 20 時訓練 R² 一路衝到 1,而測試 MSE 從 1.07 爆到 46.3。
圖表需要連網載入 Chart.js。此圖的重點:加入完全無關的噪音變數只會讓測試誤差變差,從 1.34 升到 7.54。
純噪音變數愈多,訓練誤差愈好看、測試誤差愈糟。
上圖在做什麼 圖 6.22–6.23
n = 20 的模擬資料,只有第一個變數真的跟 y 有關,其餘都是純噪音。x 軸是放進模型的變數個數。訓練 R² 從 0.051 升到 1.000,測試 MSE 從 1.07 升到 46.3
關鍵數字
p = 1:訓練 R² / 測試 MSE0.051 / 1.07
p = 18:訓練 R² / 測試 MSE1.000 / 46.3
下圖:維度的詛咒 圖 6.24
Lasso 在 p = 20、50、2000 個候選變數下的測試 MSE:1.34 → 1.60 → 7.54。真正有用的變數一直是那 20 個,多加進來的全是噪音——但噪音也要花代價去排除。
在高維度千萬不要相信這三個數字 1. 訓練資料上的 R²。 p 接近 n 時它必然接近 1,跟模型好壞完全無關。
2. 訓練資料上的 RSS 或 MSE。同理,必然接近 0。
3. 用同一份資料選完變數之後算出來的 p 值。 從幾萬個變數裡挑「最顯著」的,一定挑得到看起來很顯著的,那是多重比較,不是發現。

唯一能信的是在完全沒參與過任何選擇的資料上算出來的誤差—— 獨立的測試集,或誠實做的交叉驗證(第 5 章 P06)。
觀念釐清
Q:p > n 的時候「維度的詛咒」到底詛咒了什麼?

詛咒的是額外的變數不是免費的

直覺上多一個變數只會提供更多資訊,最壞也就是沒用。但實際上每個變數都要花自由度去估它的係數,而估計本身帶進變異。一個跟 y 完全無關的變數,它的係數估計值不會剛好是 0,而是一個隨機的小數字——那個隨機性直接進到預測裡。

下面那張圖就是這件事:真正有用的變數固定是 20 個,把候選池從 20 擴到 2000 之後測試 MSE 從 1.34 升到 7.54。雜訊不會互相抵消,它會累加。

Q:那高維度該用什麼?

這一章的三類工具全部都是為此設計的:子集/逐步選擇(明確減少變數)、收縮(Ridge 與 Lasso,Lasso 還順便選變數)、降維(PCR 與 PLS)。它們的共同點是降低變異,代價是接受一點偏差

在 p ≫ n 的場景,Lasso 與 elastic net 特別受歡迎,因為稀疏假設常常合理(幾萬個基因裡真的有關的通常只有少數幾個),而且結果可以直接列出「這幾個變數」。

QUIZ · 高維度

n = 50、p = 500 的資料,用最小平方配適。訓練 R² 大約會是多少?

(A) 1.0,因為 p > n 時一定存在完美通過所有訓練點的解
(B) 接近 0,因為 500 個變數大部分是噪音
(C) 無法計算,因為 XᵀX 不可逆
EXERCISES · 練習

動手驗證:ISLP 第 6 章精選題 ISLP §6.6 習題

下面幾題取自 ISLP §6.6 的課後習題,題號都對得回課本。先自己想過再點選項; 每個選項——包含錯的——都寫了為什麼。想看完整解答再對照下面3個站。

EXERCISE 1 · ISLP 6.6 第 1 題(b)

最佳子集、forward stepwise、backward stepwise 各自選出的「k 個變數的最佳模型」中,測試誤差最低的會是哪一個?

(A) 不確定——三者都有可能,因為測試誤差要看運氣,而三者選出的模型未必相同
(B) 最佳子集,因為它搜遍所有可能的模型
(C) forward stepwise,因為它的搜尋空間小所以變異低
EXERCISE 2 · ISLP 6.6 第 2 題(a)

相對於最小平方,Lasso 的特性是?

(A) 彈性較低,因此當「變異的下降」大於「偏差的上升」時,預測準度會更好
(B) 彈性較高,因此當「偏差的下降」大於「變異的上升」時會更好
(C) 彈性一樣,只是係數的解不同
EXERCISE 3 · ISLP 6.6 第 4 題

Ridge 的懲罰參數 λ 從 0 開始往上增加。訓練 RSS 會怎麼變化?

(A) 單調上升
(B) 先下降再上升,呈 U 型
(C) 單調下降
EXERCISE 4 · ISLP 6.6 第 9 題

課本第 9 題在 College 資料上比較最小平方、Ridge、Lasso、PCR、PLS 的測試誤差。預期會看到什麼?

(A) 五者的測試誤差常常很接近,Ridge 與 Lasso 略勝最小平方;沒有哪一個一致最好
(B) PCR 與 PLS 明顯勝出,因為它們降了維
(C) Lasso 一定最好,因為它同時做收縮與變數選擇
REFERENCE · 總覽

線性模型選擇與正則化速查表 ISLP Ch.6

考前把這一頁掃過去就好。

三類工具對照

做什麼調整參數會歸零嗎算力何時最適合
最佳子集搜遍 2^p 個模型模型大小 k會(沒選就是 0)2^p,p > 40 不可行p 很小
Forward/backward貪婪地一次加/減一個模型大小 k1 + p(p+1)/2p 中等
Ridge(L2)全部係數一起收縮λ不會很快,有封閉解很多變數都有小貢獻
Lasso(L1)收縮 + 部分歸零λ很快(座標下降)真實係數稀疏
PCR換成 M 個非監督式方向M不會(用到全部變數)很快X 的大變異方向跟 y 有關
PLS換成 M 個監督式方向M不會很快X 的大變異方向跟 y 無關

Credit 資料上六個準則選出的模型大小

準則選出的大小懲罰項備註
Cp6$+2d\hat\sigma^2$測試 MSE 的無偏估計
AIC6常態誤差下與 Cp 等價從 KL 散度來
BIC4$+\log(n)\,d\hat\sigma^2$n > 7 時罰得比 Cp 重,偏好小模型
調整後 R²7分母帶 $n-d-1$罰得最輕,選最大的模型
10-fold CV6無(直接估測試誤差)不需要 $\hat\sigma^2$
CV + one-SE4同上,再取門檻內最簡單的跟 BIC 一致

n = 400、p = 11、$\hat\sigma^2$ = 9760。 Cp 選 6 個、BIC 選 4 個、調整後 R² 選 7 個,與 ISLP 圖 6.2 的數字相符。 最佳子集與 forward stepwise 在大小 3 之後就開始選出不同的變數組合。

公式速查

名稱式子備註
Cp$\frac{1}{n}(\mathrm{RSS} + 2d\hat\sigma^2)$式 6.2
AIC$\frac{1}{n\hat\sigma^2}(\mathrm{RSS} + 2d\hat\sigma^2)$式 6.3,常態誤差下與 Cp 等價
BIC$\frac{1}{n}(\mathrm{RSS} + \log(n)\,d\hat\sigma^2)$式 6.3,$\log n > 2$ 時罰得比 Cp 重
調整後 R²$1 - \frac{\mathrm{RSS}/(n-d-1)}{\mathrm{TSS}/(n-1)}$式 6.4
Ridge$\mathrm{RSS} + \lambda\sum_j \beta_j^2$式 6.5,等價於 $\|\beta\|_2^2 \le s$
Lasso$\mathrm{RSS} + \lambda\sum_j |\beta_j|$式 6.7,等價於 $\|\beta\|_1 \le s$
主成分方向$Z_m = \sum_j \phi_{jm} X_j$式 6.16,$\phi$ 由 X 的變異決定
四個一定要記住的觀念 1. 三條路:選變數、收縮係數、換座標。 共同點都是降低變異,代價是接受一點偏差。
2. L1 會歸零、L2 不會,差別在形狀不在強弱。 菱形有尖角而尖角落在座標軸上;圓沒有。
3. Ridge、Lasso、PCR、PLS 之前都必須標準化。 它們的目標函數對單位敏感,最小平方不是。
4. 高維度時訓練 R² 必然接近 1,看它等於沒看。 只信沒參與過任何選擇的資料上算出來的誤差。

本頁「預期輸出」逐字取自課程 lab notebook(老師在課程環境實跑);圖表用的烘焙資料由 tools/frames/ 在固定種子下產生,環境為 numpy 1.24.4 · pandas 2.3.2 · scikit-learn 1.6.1 · scipy 1.13.1 · statsmodels 0.14.2 · ISLP 0.4.0 · pygam 0.10.1。每張卡下方的「來源」標了 lab 的儲存格編號,可以直接回去對。

CARDS · 關鍵詞彙卡

關鍵詞彙卡:點卡片翻面 課程題庫 · 27 張

詞彙卡取自本章講義與 ISLP 第 6 章,正面是中文術語(附英文原名)。 先看正面、心裡默想定義,再翻面對答案;洗牌後再過一輪,直到每張都能不看答案講出來。