① 依序閱讀:每節先讀說明;遇到互動元件時,先預測結果,再操作驗證。 ② 對照來源:章節旁標示課本章節與講義主題,正文保留公式、條件與算例;計算細節、完整實作與證明預設收合,可按需要展開。來源標記可查原教材。 ③ 檢查理解:答錯時先看回饋,再回到相關說明;標為延伸的內容可留待第二輪。 ④ 最後翻關鍵詞彙卡自測術語,並用 重點速查與來源查閱。
教科書:An Introduction to Statistical Learning with Applications in Python(ISLP);
進階參考:The Elements of Statistical Learning(ESL)。章節旁的來源標記可點到本頁書目。
你已經會擬合模型了。現在的問題換成:這個模型在沒見過的資料上會有多準? 最直覺的做法是拿訓練資料算誤差,但那個數字幾乎一定太樂觀,因為模型是照著那批資料調出來的。 極端一點想:一棵長到每個葉子只剩一個樣本的樹,訓練誤差是 0,可是它什麼都沒學到。
如果手上有一大筆獨立的測試資料,事情很簡單。但真實情況通常是資料就這麼多, 再切出去一塊當測試集就不夠訓練了。重抽樣(resampling)的想法是: 反覆從同一批資料裡切出訓練/驗證組合,用它們的平均表現估計測試誤差。
本章介紹兩種重抽樣方法。交叉驗證(cross-validation)估計測試誤差,並用它挑選適當的模型彈性,也就是選超參數(hyperparameter)。講義的定義是:超參數是用來控制學習過程的參數,無法在把模型擬合到訓練集時順便推得。它分成兩類:
bootstrap 則用來估計參數估計值的標準差,也用在集成學習(第 8 章的 bagging)。
參數(parameter)是擬合時由訓練資料直接學出來的量,例如線性迴歸的 $\beta_0,\beta_1,\ldots,\beta_p$,或神經網路的權重;最佳化程序會把它們算出來。超參數則是用來控制學習過程的設定值:在擬合模型之前就要先指定,訓練程序本身不會順便把它估出來,通常要靠驗證集或交叉驗證來選。例如 ridge regression:
$$\hat\beta=\arg\min_\beta\Bigl[\sum_{i=1}^n(y_i-x_i^\mathsf{T}\beta)^2+\lambda\|\beta\|^2\Bigr].$$這裡 $\beta$ 是參數,$\lambda$ 是超參數:給定 $\lambda$,最佳化會解出 $\hat\beta$;但若把 $\lambda$ 也拿來最小化訓練誤差,永遠會選 $\lambda=0$,所以要另外用 CV 評估。兩類超參數的對照:
| 模型超參數(model hyperparameter) | 演算法超參數(algorithm hyperparameter) | |
|---|---|---|
| 控制什麼 | 學什麼模型:模型的形式、複雜度或假設空間 | 怎麼學:最佳化程序如何把模型訓練出來 |
| 例子 | KNN 的 $k$、多項式的次數、決策樹的最大深度、ridge 的 $\lambda$、神經網路的層數與每層神經元數 | 學習率、batch size、epoch 數、最佳化器的選擇、momentum |
| 改變它會 | 改變可能的擬合結果與偏差–變異取捨 | 改變收斂速度、穩定性,或最後停在哪個解 |
例如梯度下降 $\theta^{(t+1)}=\theta^{(t)}-\eta\nabla L(\theta^{(t)})$ 的學習率 $\eta$:太大可能跳過最佳點、甚至不收斂;太小則學得很慢。它不改變模型的形式,只控制最佳化怎麼走,所以算演算法超參數。這兩類的界線並不嚴格;dropout 比例既改變有效的模型,也影響訓練過程,常被視為訓練/模型兩用的超參數。實務上大家通常統稱為超參數,重點是:它們都不由擬合程序直接估出,要靠獨立於訓練的評估來選,本章介紹的正是這類評估工具。
講義先複習兩個定義。測試誤差是用學好的方法去預測一筆沒參與訓練的新觀測時的平均誤差;訓練誤差則把方法套回訓練用的那些觀測就能算出來,通常會低估測試誤差。
以最小平方線性迴歸為例:$y=X\beta+\varepsilon$,$X$ 為 $n\times p$ 滿欄秩(含截距),誤差獨立、平均 0、變異數 $\sigma^2$。
訓練 MSE。殘差 $e=(I-H)y=(I-H)\varepsilon$,$H=X(X^\mathsf{T}X)^{-1}X^\mathsf{T}$。$I-H$ 對稱且冪等,跡為 $n-p$,所以
$$E\Bigl[\frac1n\|e\|^2\Bigr]=\frac1n E\bigl[\varepsilon^\mathsf{T}(I-H)\varepsilon\bigr]=\frac{\sigma^2}{n}\operatorname{tr}(I-H)=\sigma^2\Bigl(1-\frac pn\Bigr).$$在同樣的 $X$ 上重新觀測的測試 MSE。新反應 $y^{new}=X\beta+\varepsilon^{new}$,$\varepsilon^{new}$ 與訓練誤差獨立。預測誤差 $y^{new}-X\hat\beta=\varepsilon^{new}-H\varepsilon$,兩項獨立,
$$E\Bigl[\frac1n\|y^{new}-X\hat\beta\|^2\Bigr]=\sigma^2+\frac{\sigma^2}{n}\operatorname{tr}(H)=\sigma^2\Bigl(1+\frac pn\Bigr).$$兩者相差 $2p\sigma^2/n$:參數愈多、樣本愈少,訓練誤差就愈樂觀。這正是第 6 章 $C_p$ 在訓練誤差上加 $2p\hat\sigma^2/n$ 的由來。更一般的結論(模型類事先固定、取訓練誤差最小者時,期望訓練誤差不大於期望測試誤差)見第 2 章的證明。
講義補充連結:證明訓練資料上的期望 MSE 小於測試資料。
最好的解法是一個夠大的獨立測試集,但通常拿不到。講義列出兩條替代路線:
講義補充連結:scikit-learn:交叉驗證總覽。
| 切幾次 | 每次訓練用多少 | 有隨機性嗎 | 主要用途 | |
|---|---|---|---|---|
| 驗證集法 | 1 | 約 $n/2$ | 有,換 seed 就變 | 快速粗估 |
| LOOCV | $n$ | $n-1$ | 沒有(分割唯一) | 小資料、要穩定 |
| $k$-fold CV | $k$(通常 5 或 10) | $n(k-1)/k$ | 有,但比驗證集小很多 | 選模型的標準做法 |
| Bootstrap | $B$(通常 1000) | $n$(有放回) | 有,$B$ 大就穩 | 估標準誤與信賴區間 |
為什麼「訓練誤差」不能拿來當測試誤差的估計?
最直接的做法:把資料隨機切成兩半,一半訓練、一半當驗證集(validation set, 也叫 hold-out set)。模型完全沒看過驗證集,所以驗證集上的 MSE 就是一個誠實的測試誤差估計:
$$\mathrm{MSE}_{\text{valid}} = \frac{1}{|V|} \sum_{i \in V} \left(y_i - \hat f(x_i)\right)^2$$講義用 Auto 資料($n=392$)示範:把 196 筆拿去訓練、196 筆當驗證集,
用 horsepower 預測 mpg,比較線性、二次與更高次多項式 $\texttt{mpg}=\beta_0+\sum_{j=1}^d\beta_j\,\texttt{horsepower}^j$。單一次切分得到的驗證 MSE 曲線顯示二次明顯比線性好、三次以上沒有再改善。看起來很乾淨——問題是換一個切法,答案就變了。
講義補充連結:ISLP 的 Auto 資料說明。
test_size=196)算出的驗證 MSE,$x$ 軸是 horsepower 多項式的次數。粗線是十次的平均。十條線的高低差距,就是驗證集法的變異。
np.float64(25.57387818968441)
這個 25.57 就是課本 §5.1.1 引用的數字。注意 random_state=rng——換掉它,下面的數字就會不一樣。
Ch05-resample-lab-zh.ipynb
array([20.75540796, 16.94510676, 16.97437833])
degree 1/2/3 的驗證 MSE 從 [25.57, 22.22, 22.67] 變成 [20.76, 16.95, 16.97]。同一份資料、同一個模型,只是切法不同,數字差了快 5。但兩次都指向同一個結論:二次比一次好,三次沒有再更好。
Ch05-resample-lab-zh.ipynb
因為它只用了一半的資料訓練。統計模型通常有愈多訓練資料,表現愈好,所以用 $n/2$ 筆訓練出來的模型,本來就比用全部 $n$ 筆訓練出來的差。你量到的是「一個比較弱的模型」的誤差,因此系統性偏高。
交叉驗證同時改善了講義列的兩個缺點:每一輪都用 $n(k-1)/k$ 筆訓練(比 $n/2$ 多),而且做 $k$ 輪再平均(變異變小)。
random_state 到底該不該固定?固定 seed 讓你和讀程式的人能重跑出同樣的數字,使結果可重現。
危險的做法是「試幾個 seed,挑數字最漂亮的那個報出來」。那等於用驗證集調參,報出的誤差會受到這次選擇影響。可以用 $k$-fold CV 降低單次分割對結果的影響。
驗證集法有兩個公認的缺點。下面哪一組說對了?
驗證集法浪費了一半的資料,而且答案會跳。把它推到極端: 每次只留一個樣本當驗證集,其餘 $n-1$ 筆全部拿去訓練,做 $n$ 次再平均。 這就是留一交叉驗證(leave-one-out cross-validation, LOOCV):
$$\mathrm{CV}_{(n)} = \frac{1}{n} \sum_{i=1}^{n} \mathrm{MSE}_i, \qquad \mathrm{MSE}_i = \left(y_i - \hat f^{(-i)}(x_i)\right)^2$$其中 $\hat f^{(-i)}$ 是「拿掉第 $i$ 筆」擬合出來的模型。這樣做有兩個好處: 每一輪都用了幾乎全部的資料(偏差很小),而且分割方式唯一——沒有隨機性, 跑一百次都是同一個數字。
| 輪次 | 訓練資料 | 驗證資料 | 得到的量 |
|---|---|---|---|
| $i=1,\ldots,n$ | 除了第 $i$ 筆以外的 $n-1$ 筆 | 第 $i$ 筆 | $(y_i-\hat f^{(-i)}(x_i))^2$ |
| 最後 | — | — | 把 $n$ 個平方誤差平均成 $\mathrm{CV}_{(n)}$ |
cross_validate 跑 LOOCVnp.float64(24.23151351792922)
24.2315 就是 degree 1 的 LOOCV 估計。跟上面驗證集法的 25.57/20.76 比一比:LOOCV 只有一個答案,不會因為切法而跳。
來源:Ch05-resample-lab-zh.ipynb
它像普通的訓練 MSE,只是每個殘差除以 $1-h_i$:槓桿值愈大的點,愈能把擬合結果拉向自己,訓練殘差就愈樂觀,所以要放大得愈多。這個公式只適用於最小平方這類模型;scikit-learn 的通用 cross_validate() 不會用它,仍然真的擬合 $n$ 次。
最小平方的擬合值是 $\hat y=Hy$,$H=X(X^\mathsf{T}X)^{-1}X^\mathsf{T}$ 是帽子矩陣,$h_i=H_{ii}$ 是第 3 章學過的槓桿值。把第 $i$ 個擬合值拆開:
$$\hat y_i=\underbrace{h_iy_i}_{\text{自己對自己的影響}}+\underbrace{\sum_{j\ne i}H_{ij}y_j}_{\text{其他資料的影響}}.$$$h_i$ 愈大,這筆資料愈能把擬合結果拉向自己,訓練殘差 $e_i$ 就愈過度樂觀。LOOCV 不允許 $y_i$ 參與預測自己,所以要把這部分影響拿掉;刪掉一筆後係數也會重新調整,最後精確的修正剛好是除以 $1-h_i$;完整推導見本節最後的「計算細節:LOOCV 捷徑與槓桿值」。
講義補充連結:LOOCV 捷徑公式的證明。
講義列出三點:
假設 $n=100$。LOOCV 每次都是 99 筆訓練、1 筆驗證。例如 $D_{-1}=\{2,3,\ldots,100\}$ 與 $D_{-2}=\{1,3,\ldots,100\}$ 有 98 筆完全相同,訓練出來的兩個模型通常也非常像。講義列出三個後果:
1. 對資料的擾動不夠大。每次只移除一筆,$n\to n-1$,不同輪的訓練資料幾乎一樣;相比之下,10-fold CV 每次拿掉約 10%($100\to90$),模型受到比較明顯的擾動。LOOCV 因此沒有充分觀察到「訓練樣本改變時,模型表現會怎麼變」。
2. 仍然很花時間。上面的捷徑只適用於最小平方這類線性平滑器。一般的機器學習方法沒有這種捷徑:$n=10000$ 時 LOOCV 要真的擬合 10000 次模型,10-fold CV 只要 10 次。對隨機森林、支持向量機、神經網路等方法,LOOCV 通常成本很高。
3. 各折的估計高度相關,平均之後的變異可能仍然很大。令第 $i$ 折的誤差為 $E_i$,$\mathrm{CV}=\frac1n\sum_iE_i$。若各 $E_i$ 獨立,平均的變異是 $\sigma^2/n$;但它們的訓練集幾乎相同,$\operatorname{Cov}(E_i,E_j)>0$,正相關會抵銷平均的效果(公式見下一節的「平均相關誤差的變異數」)。極端情況 $E_1=E_2=\cdots=E_n$,平均 100 次的資訊和只有 1 次差不多。所以這句話的意思不是「取平均會增加變異」,而是因為各折太相關,取平均無法像獨立樣本那樣降低變異。
三點合起來看:LOOCV 偏差較低,但各折高度相關,變異可能較高,而且計算昂貴;5-fold 或 10-fold 通常提供較好的偏差、變異與計算量取捨。
嚴格說,它估的是「用 $n-1$ 筆資料訓練出來的模型」的期望測試誤差,但因為 $n-1$ 跟 $n$ 幾乎一樣,實務上直接把它當成「用全部 $n$ 筆訓練出來的那個模型」的測試誤差。
這也是為什麼 CV 的最後一步通常是:用 CV 選出超參數(例如次數 = 2),然後用全部資料重新擬合一次,交出那個模型。CV 負責比較設定,選好後再擬合最終模型。
cross_validate() 為什麼跑 LOOCV 還是很慢?因為它是通用函式,不知道你的模型是不是最小平方,所以不使用式 5.2 的捷徑,仍然真的擬合 $n$ 次。lab 也提到:原則上最小平方的 LOOCV 可以比 $k$-fold 還快,但通用函式沒有利用這個公式。
同一份資料上,把 LOOCV 跑兩次,會得到一樣的答案嗎?
固定的最小平方設計矩陣 $X$ 滿欄秩,而且每次刪一筆後仍滿欄秩,才能用 $e_i^{(-i)}=e_i/(1-h_{ii})$。其中 $H=X(X^TX)^{-1}X^T$、$h_{ii}=x_i^T(X^TX)^{-1}x_i$。
$h_{ii}=1$ 時分母為零,刪除後也失去滿秩,不能把 $0/0$ 設成零。若每折重新選變數、選多項式次數或調整超參數,也不能只拿選好模型的一組 $H$ 取代整個流程。固定基底的普通最小平方適用;非線性估計器沒有此一般捷徑。
令 $A=X^TX$、$b=X^Ty$。刪除第 $i$ 筆的 normal equations 為 $(A-x_ix_i^T)\hat\beta_{(-i)}=b-x_iy_i$。完整資料則有 $A\hat\beta=b$。兩式相減並整理:
$$A(\hat\beta_{(-i)}-\hat\beta)=-x_i(y_i-x_i^T\hat\beta_{(-i)})=-x_i e_i^{(-i)}.$$左乘 $x_i^TA^{-1}$,得 $x_i^T(\hat\beta_{(-i)}-\hat\beta)=-h_{ii}e_i^{(-i)}$。而 $e_i^{(-i)}=e_i-x_i^T(\hat\beta_{(-i)}-\hat\beta)$,所以 $(1-h_{ii})e_i^{(-i)}=e_i$。平方後逐筆平均就是 LOOCV 公式。矩陣行列式引理給 $\det(A-x_ix_i^T)=\det(A)(1-h_{ii})$,也說明分母為零對應刪除後秩不足。
LOOCV 要擬合 $n$ 次模型,$n$ 大就吃不消。折衷方案:把資料隨機平分成 $k$ 份, 每次拿一份當驗證集、其餘 $k-1$ 份訓練,做 $k$ 輪再平均。這就是 $k$-fold 交叉驗證:
講義的寫法:令 $C_1,\ldots,C_k$ 為各折觀測的索引集合,第 $j$ 折有 $n_j$ 筆($n$ 能被 $k$ 整除時 $n_j=n/k$)。第 $j$ 折當驗證時,
$$\mathrm{MSE}_j=\frac1{n_j}\sum_{i\in C_j}\bigl(y_i-\hat y_i^{(-j)}\bigr)^2,\qquad \mathrm{CV}_{(k)}=\sum_{j=1}^k\frac{n_j}{n}\,\mathrm{MSE}_j,$$其中 $\hat y_i^{(-j)}$ 是拿掉第 $j$ 折擬合的模型對 $x_i$ 的預測。各折一樣大時,權重都是 $1/k$,就是常見的 $\frac1k\sum_j\mathrm{MSE}_j$;scikit-learn 的 cross_validate() 回傳各折分數,lab 直接取平均,相當於等權重,$n$ 不能被 $k$ 整除時與加權式會有些微差異。
LOOCV 其實就是 $k=n$ 的特例。實務上 $k$ 取 5 或 10——原因下一節講。
講義接著用三組模擬資料比較真正的測試 MSE、LOOCV 與 10-fold CV(ISLP 圖 5.6)。三張圖中,CV 曲線的高度有時低估、有時高估真正的測試 MSE,但最小值出現的位置大致正確。選擇模型彈性時,我們在乎的正是最小值的位置,所以 CV 即使數值不準,仍然有用。
| 方法 | 每輪訓練 | 每輪驗證 | 輪數 | 分割是否唯一 |
|---|---|---|---|---|
| 5-fold | 4/5 的資料 | 1/5 的資料 | 5 | 否;需固定分割以公平比較模型 |
| 10-fold | 9/10 的資料 | 1/10 的資料 | 10 | 否 |
| LOOCV | $n-1$ 筆 | 1 筆 | $n$ | 是;等同 $k=n$ |
KFold 跑 10-foldshuffle=True 很重要:如果原始資料有排序(例如 Auto 按年份),不打亂就會讓每一折的分佈完全不同。random_state=0 是為了讓不同 degree 用同一組分割。這樣比較才公平。這格 lab 沒存下輸出,下一節的圖用同樣設定重算了一次。
Ch05-resample-lab-zh.ipynb
比較不同模型(例如 degree 1 到 10)的 CV 誤差時,為什麼要讓每個模型用同一組折分割?
$k$ 該取多少?講義從偏差與變異兩個方向說明:
講義以 Auto 比較不同次數的模型:
horsepower 多項式的次數,$y$ 軸是 CV 估的測試 MSE。兩條線分別是 LOOCV 與 10-fold CV。兩條幾乎重疊。這在實務上很常見,也是大家願意用計算量較少的 10-fold 取代 LOOCV 的理由。
| $k$ | 每輪訓練用 | 偏差(高估測試誤差的程度) | 各折相關 | 擬合模型次數 | 評語 |
|---|---|---|---|---|---|
| 2 | $n/2$ | 較大 | 低 | 2 | 太粗,很少用 |
| 5 | $0.8n$ | 小 | 中 | 5 | 實務常用 |
| 10 | $0.9n$ | 較小 | 中 | 10 | 實務最常用 |
| $n$(LOOCV) | $n-1$ | 最小 | 很高,估計變異可能較大 | $n$ | 小資料、或有式 5.2 捷徑時 |
平均更多項會更穩,前提是那些項彼此獨立。這裡不是。
算式上看:$\mathrm{Var}(\bar X) = \frac{\sigma^2}{k} + \frac{k-1}{k}\rho\sigma^2$。第一項隨 $k$ 變大而變小,但第二項隨 $\rho$(各折之間的相關)變大而變大。講義的論點是 LOOCV 各折訓練出的模型幾乎相同,各折估計因而正相關;$\rho>0$ 時第二項會抵銷一部分第一項隨 $k$ 減小的效果。實際的相關程度依方法與資料而定,不一定接近 1。
直覺版:LOOCV 的 $n$ 個模型幾乎是同一個模型,所以你其實只有「一個」意見被重複算了 $n$ 次。
這條式子假設每折變異 $\sigma^2$ 與兩兩相關 $\rho$ 都相同;$k$ 改變時 $\sigma^2$ 與 $\rho$ 也會一起變,詳見本節的收合補充。
為什麼實務上常選 $k=5$ 或 $10$,而不直接用 LOOCV?
講義與 ISLP 的說法是 LOOCV 的估計「傾向」有較高的變異。這是常見的經驗,但不是對每個問題都成立的定理。
Auto 的兩條曲線就是例子;對不穩定的方法,差異才較明顯。講義補充連結:相關與不相關資料的平均,其變異數如何不同、LOOCV 與 $k$-fold CV 的偏差與變異。
對 $K$ 個有有限變異數的折誤差 $E_1,\ldots,E_K$,由平方展開與期望線性性:
$$\operatorname{Var}\left(\frac1K\sum_k E_k\right)=\frac1{K^2}\left[\sum_k\operatorname{Var}(E_k)+2\sum_{k\lt l}\operatorname{Cov}(E_k,E_l)\right].$$若每折變異數為 $v$、兩兩相關均為 $\rho$,則結果為 $v/K+(K-1)\rho v/K$。$\rho=0$ 才有熟悉的 $v/K$;正相關會限制平均所能降低的變異。不過不同 $K$ 的 $v$ 與相關結構也會改變,因此這個公式解釋取捨,沒有證明每個問題的 LOOCV 都比 10-fold 變異大。
整套邏輯搬到分類問題只要換一件事:把 MSE 換成錯誤率。
$$\mathrm{CV}_{(k)} = \sum_{j=1}^{k} \frac{n_j}{n}\,\mathrm{Err}_j, \qquad \mathrm{Err}_j = \frac{1}{n_j} \sum_{i \in C_j} I(y_i \neq \hat y_i)$$$I(\cdot)$ 是指示函數:預測錯就是 1、對就是 0。其餘完全一樣:切 $k$ 折、輪流當驗證集、平均。 ISLP 圖 5.7–5.8 用邏輯斯迴歸加上不同次數的多項式項示範:訓練錯誤率隨彈性增加持續下降, 真正的測試錯誤率先降後升,而 10-fold CV 錯誤率雖然略為低估測試錯誤率, 最小值的位置卻和測試錯誤率接近,所以能用來挑多項式的次數;KNN 的 $1/K$ 也呈現同樣的趨勢。
承接講義的「分類問題的交叉驗證」與選讀的切分方式:Lab 匯入了 StratifiedKFold,但主要實作仍是 Auto 迴歸的 KFold。下面說明分層與群組切分;病人的例子是為了看清切分界線而設計的,不是 Auto 的欄位。
StratifiedKFold(分層)依照 y 的類別安排觀測,讓各折的類別比例盡量接近整體。例如 100 筆獨立觀測有 20 筆正例,分成 5 折時,每折 20 筆約有 4 筆正例。一般分類也可以用分層,不必等到嚴重不平衡才使用;它沒有增加少數類資料,也不會解決所有抽樣不確定性。
若正例只有 3 筆卻切成 5 折,就不可能每折都有正例。折數與評估指標要配合各類的筆數;ROC AUC 等指標在只有單一類別的驗證折上無法計算。分層可避免部分不良切分,但不能保證折分數的變異完整反映母體的不確定性。
GroupKFold(分組)依照 groups 的群組編號安排整組觀測。同一病人的 5 次就診,應一起放在訓練或驗證的一側;每一折的兩側沒有共用病人,各群組在一輪 CV 中恰好當一次驗證資料。若逐筆隨機分折,模型可能在驗證時認出訓練過的病人;這樣的分數回答的是「熟悉病人的新紀錄」,不適合用來宣稱「新病人的表現」。至少要有 n_splits 個不同群組;群組大小不同時,驗證筆數也可能不一樣。
分層與分組保護的是不同界線。分層不保證病人隔離;分組不保證類別比例相同。若兩者都需要,用 StratifiedGroupKFold:先確保群組不跨兩側,再嘗試維持類別比例。若正例都集中在少數大群組,比例可能無法平衡,仍應列出各折的群組數與各類筆數。
| 資料情境 | 切分器 | 切分時保留什麼 |
|---|---|---|
| 獨立的迴歸觀測 | KFold(shuffle=True) | 讓觀測分散到各折 |
| 獨立的分類觀測 | StratifiedKFold | 各折類別比例盡量接近整體 |
| 同一病人/使用者有多筆紀錄 | GroupKFold | 同群組不跨訓練與驗證 |
| 分類且同一實體有多筆紀錄 | StratifiedGroupKFold | 群組隔離,並盡量維持類別比例 |
| 預測未來的時間序列 | TimeSeriesSplit | 用較早資料預測較晚資料;必要時留間隔 |
講義補充連結:scikit-learn:交叉驗證與資料相依性、StratifiedKFold:分層切分、GroupKFold:群組隔離、StratifiedGroupKFold:同時考慮類別與群組。
因為隨機切折會讓「未來」的資料進到訓練集、「過去」的資料留在驗證集。模型於是可以用 2026 年的資訊去預測 2025 年。這在部署時根本不可能發生,所以 CV 誤差會嚴重低估真實表現。
正解是只往前切(TimeSeriesSplit):用前 100 筆訓練、預測第 101–120 筆;再用前 120 筆訓練、預測第 121–140 筆…訓練集永遠在驗證集之前。
一份資料裡正例只佔 2%。用普通的 KFold(n_splits=10) 會有什麼風險?
先篩選特徵再做 CV,可能讓驗證資料的資訊提前進入訓練流程;程式仍會正常執行。
講義的情境:兩類資料,5000 個預測變數、50 筆樣本。步驟一:找出和類別標籤相關最大的 100 個預測變數; 步驟二:只用這 100 個變數擬合分類器,例如 logistic regression。要估計這個分類器的測試表現, 能不能只對步驟二做交叉驗證、忘掉步驟一?不能,這個數字受到資料洩漏(data leakage)影響。
問題在於「挑特徵」這一步看過了全部的 $y$,包含後來被當成驗證資料的那些。 篩選本身就是模型訓練的一部分,它必須在每一折的訓練部分內重新執行。
下面把兩種流程放在預測變數和類別完全無關的資料上比較,真正的錯誤率是 0.5:
下面的程式產生上圖的 100 次模擬:每次的種子是 7000 到 7099,兩種流程用同一組切分,差別只在「挑變數」放在 CV 迴圈外或迴圈內。用 numpy 1.24.4、scikit-learn 1.6.1 執行,兩個平均是 0.001 與 0.501;其他版本的數字可能有小差異,但錯誤流程接近 0、正確流程接近 0.5 的結論不變。100 次重複在一般筆電上約需數秒到數十秒。
想看單次結果可以只呼叫 cv_misuse_once(7000)。把 k_sel 調小,或把 p_all 減少,錯誤流程的錯誤率會上升:可以挑的雜訊變數少了,「剛好」和標籤相關的變數也比較少。
錯誤流程回報的 CV 錯誤率接近 0,彷彿找到了完美的分類器;正確流程才接近真實的 0.5。在 5000 個純雜訊變數中,總會有一些剛好和這 50 個標籤高度相關,先看全部資料挑出它們,等於讓驗證折的答案參與了選擇。
講義補充連結:scikit-learn:常見陷阱中的資料洩漏。
scikit-learn 裡,把它們串成 Pipeline 再交給
cross_validate,這件事就自動對了。
要,因為部署時無法先用未來資料估前處理參數。
不看 $y$ 的前處理不會直接把標籤洩漏進來,但偏差方向與大小仍取決於模型與資料,有時預測可以完全不變。但它仍然用到了驗證資料的分佈資訊(PCA 的方向、特徵的變異數),而在部署時你不可能先看過未來資料的分佈。既然包進 Pipeline 幾乎沒有額外成本,就一律包進去,不必去分辨哪種洩漏比較嚴重。
不太行,它會偏低。你已經拿 CV 誤差當目標挑過超參數了——被挑中的那組本來就是「在這組折上運氣最好」的那組,這叫做選擇偏差。
要把調參與評估分開,可以用巢狀交叉驗證(nested CV):外層折只負責評估、完全不參與調參;內層折在外層的訓練部分裡調參。或者更簡單:一開始就切出一份從頭到尾沒碰過的測試集。
在 5-fold CV 之前先用全部資料把特徵標準化(減平均、除標準差)。這樣有問題嗎?
一般的 $k$-fold CV 希望每一折都像是「從整體資料抽出的一小部分」。若原始資料有排序,不洗牌就切,各折的分布會不一樣,CV 估計就會偏掉。
KFold 加了 shuffle=True。洗牌的目的是讓每一折更接近整體資料的分布,各折之間比較公平,CV 估計也比較穩定。scikit-learn 的 KFold 預設不洗牌;KFold(shuffle=True, random_state=0) 是在分折前先洗一次,固定 random_state 可以讓不同模型用同一組分折比較。分類問題通常再用 StratifiedKFold 分層:整體是 90% 負類、10% 正類時,每一折也盡量維持接近 90/10。
但不是所有 CV 都該洗牌。資料有自然結構時,亂洗反而可能造成資訊洩漏:
TimeSeriesSplit。GroupKFold。簡單記:i.i.d. 資料通常先洗牌;有時間、群組或空間結構時不能隨便洗牌。
講義的選讀頁另外介紹可以精確控制驗證集大小的 ShuffleSplit。兩者的差別在於:KFold 把資料切成互斥的 $k$ 份,每一筆資料恰好當一次驗證;ShuffleSplit 每次都重新隨機抽一組訓練/驗證,不同次的驗證集可以重疊。假設 100 筆資料:
KFold(n_splits=5):先分成 $F_1,\ldots,F_5$,第 $j$ 次拿 $F_j$ 當驗證;各驗證折互不重疊,每筆剛好被驗證一次。ShuffleSplit(n_splits=5, test_size=0.2):做 5 次彼此獨立的隨機 80/20 切分。某筆資料可能多次進入驗證集,也可能一次都沒被抽到。它比較接近重複隨機切分,有時也稱為蒙地卡羅交叉驗證(Monte Carlo cross-validation)。KFold | ShuffleSplit | |
|---|---|---|
| 每次是否重新隨機抽 | 否,先分成 $k$ 折(可先洗牌一次) | 是 |
| 驗證集是否重疊 | 不重疊 | 可以重疊 |
| 每筆是否一定當驗證 | 恰好一次 | 不一定 |
| 驗證集大小 | 約 $n/k$ | 自己指定 test_size |
| 切分次數 | $k$ | 自己指定 n_splits |
| 分類、類別不平衡時 | StratifiedKFold | StratifiedShuffleSplit |
即使兩者都是「5 次、驗證 20%」,概念也不同:KFold 是分割(partition),ShuffleSplit 是重複隨機抽樣。ShuffleSplit(n_splits=1) 就是驗證集法;lab 用 10 次切分得到平均 23.80、標準差 1.42(這個標準差的解讀見 lab 區塊)。下面的元件把幾種切分畫在一起,資料依類別排序,方便看出洗牌與分層的效果。
講義補充連結:scikit-learn:不同交叉驗證切分的視覺化、scikit-learn:關於洗牌的說明、時間序列的交叉驗證討論。
ShuffleSplit 做驗證集法與重複切分array([23.61661707])
驗證 MSE 23.62。它和驗證集法一節圖中 random_state=0 那次切分的一次式數字相同,因為兩者用了同一種隨機切法。
Ch05-resample-lab-zh.ipynb
(np.float64(23.802232661034168), np.float64(1.4218450941091842))
10 次切分的平均 23.80、標準差 1.42。各次的訓練樣本重疊、彼此相關,所以這個標準差只反映換不同隨機切分的蒙地卡羅變異,不能當作平均測試分數的抽樣標準誤。
來源:Ch05-resample-lab-zh.ipynb
承接講義「Cross-validation: right and wrong」的原則:資料驅動的選擇必須放在適當的訓練折內。Lab 用 Auto 的 horsepower 預測 mpg,比較 1 到 5 次多項式的 CV 誤差;以下沿用同一資料與候選模型,延伸到自動選次數與獨立的外層評估。Nested CV 是這裡的延伸實作,並非原 Lab 已執行的步驟。
一般 CV 有兩種用途。超參數事先固定時,它可評估這個訓練程序;搭配 GridSearchCV 等搜尋時,它可比較設定並選超參數。若同一份 CV 分數既用來選冠軍,又用來報告冠軍的表現,就可能偏樂觀:例如很多候選設定的真實表現接近,但估計有起伏,挑最高分等於偏向挑中在這次切分中運氣好的設定。
Nested CV 評估包含選擇步驟的完整程序。它問的是:「收到一批新的訓練資料後,依照這套調參規則選模型,對未見資料的預測會多準?」因此每個外層折都要重新執行內層搜尋,不是先用全部資料選好設定,再做一次外層 CV。
做法是兩層迴圈:外層每一折先留下一份資料只供評估,在其餘資料上用內層 CV 選超參數(例如 Lab 的多項式次數),選好後擬合並對留下的那份評分;換下一個外層折時,從搜尋開始重做。各外層折選到不同次數是正常的。評估完成後,再用全部資料重新搜尋、擬合交付的模型。sklearn 的寫法是把 GridSearchCV 搜尋器直接交給 cross_validate,見下方官方範例。
Nested CV 仍要選對切分方式。群組資料兩層都要隔離群組,時間資料兩層都要遵守時間順序;巢狀結構本身不會修復病人重疊或時間洩漏。
講義補充連結:scikit-learn:一般 CV 與 Pipeline、Nested versus non-nested cross-validation:官方範例、GridSearchCV:best_params_、best_score_ 與 refit。
換一個問題。前面都在問「模型的預測有多準」;現在問「我算出來的這個數字有多不確定」。
抽樣分佈與自助法還不熟時,可先複習 S4 的 Bootstrap 入門。
ISLP §5.2 的例子:把錢分成比例 $\alpha$ 投資 $X$、$1-\alpha$ 投資 $Y$,要讓報酬的變異最小,最佳比例是
$$\alpha = \frac{\sigma_Y^2 - \sigma_{XY}}{\sigma_X^2 + \sigma_Y^2 - 2\sigma_{XY}}$$組合 $\alpha X+(1-\alpha)Y$ 的變異數為
$$V(\alpha)=\alpha^2\sigma_X^2+(1-\alpha)^2\sigma_Y^2+2\alpha(1-\alpha)\sigma_{XY}.$$對 $\alpha$ 微分並令為零:
$$V'(\alpha)=2\alpha\sigma_X^2-2(1-\alpha)\sigma_Y^2+2(1-2\alpha)\sigma_{XY}=2\alpha(\sigma_X^2+\sigma_Y^2-2\sigma_{XY})-2(\sigma_Y^2-\sigma_{XY})=0,$$ $$\Longrightarrow\quad \alpha=\frac{\sigma_Y^2-\sigma_{XY}}{\sigma_X^2+\sigma_Y^2-2\sigma_{XY}}.$$二階導數 $V''(\alpha)=2(\sigma_X^2+\sigma_Y^2-2\sigma_{XY})=2\operatorname{Var}(X-Y)$。分母大於 0 時 $V$ 是開口向上的拋物線,這個臨界點就是唯一的最小值;分母等於 0 時 $X-Y$ 幾乎處處是常數,變異數不隨 $\alpha$ 改變,公式沒有定義。
公式允許任意實數權重($\alpha<0$ 或 $\alpha>1$ 代表放空)。若另外規定 $0\le\alpha\le1$,把上面的解截到 $[0,1]$ 即可;這是額外加上的限制,不是 bootstrap 的一部分。
把樣本變異數代進去就得到 $\hat\alpha$。但 $\hat\alpha$ 有多可靠? 它的標準誤沒有簡單的公式可查。理想上我們會重新蒐集 1000 份新資料、算 1000 個 $\hat\alpha$、 看它們的標準差,但我們只有一份資料。
這個名字來自英文俗語「拉著自己的靴帶把自己提起來」:只靠手上這一份資料,就估出估計量的不確定性。
這句俗語常和吹牛男爵 Munchausen 的故事連在一起:他聲稱抓著自己的頭髮(後來的版本變成靴帶)把自己從沼澤裡拉出來。這件看似不可能的事,後來被用來形容「不靠外力、只用自己手上的東西完成」。統計上的 bootstrap 也是這樣:沒有新的資料,只從原本那一份資料重抽,就估出估計量的抽樣變異。
講義補充連結:bootstrap 這個名字的由來。
講義先用模擬說明 bootstrap 想近似的東西。假設知道母體參數 $\sigma_X^2=1$、$\sigma_Y^2=1.25$、$\sigma_{XY}=0.5$,代入公式得真正的 $\alpha=0.6$。每次從母體抽 100 對 $(X,Y)$、算一次 $\hat\alpha$,重複 1000 次。講義(ISLP 圖 5.9、5.10)的四個例子 $\hat\alpha$ 為 0.576、0.532、0.657、0.651;1000 次的平均是
$$\bar\alpha=\frac1{1000}\sum_{r=1}^{1000}\hat\alpha_r=0.5996,$$很接近 $\alpha=0.6$;標準差
$$\sqrt{\frac1{1000-1}\sum_{r=1}^{1000}(\hat\alpha_r-\bar\alpha)^2}=0.083,$$問題是真實世界只有一份資料,無法從母體反覆抽樣。bootstrap 改從手上的資料有放回地重抽,模仿這個過程。下圖左邊是從母體重抽的 $\hat\alpha$,右邊是只從一份資料做 bootstrap 的 $\hat\alpha^*$。書上圖 5.10 的 bootstrap 直方圖來自一份從同一母體模擬的資料,這裡改用課程 lab 的 Portfolio;兩者的中心不同(一個在真值 0.6 附近,一個在這份資料的 $\hat\alpha$ 附近),但散布寬度相近,而 bootstrap 要估的正是這個寬度。
上面的程序在真實資料上做不到,因為無法從原本的母體產生新樣本。bootstrap 讓電腦模仿「取得新資料」的過程:它不從母體重複抽獨立的資料集,改成從原始資料有放回地重複抽樣。每份 bootstrap 資料集和原資料一樣大,所以有些觀測會出現不只一次,有些一次也沒出現。
Bootstrap 的做法:把手上這份資料當成母體,從裡面有放回地抽 $n$ 筆, 當成一份「新」資料集,重算 $\hat\alpha^*$。重複 $B$ 次,那 $B$ 個 $\hat\alpha^*$ 的標準差 就是 $\mathrm{SE}(\hat\alpha)$ 的估計。不必指定常態分布,但重抽單位須符合資料的獨立性與研究設計。
講義用兩個平行的世界整理這個想法:
| 真實世界 | bootstrap 世界 | |
|---|---|---|
| 母體 | 未知的分布 $P$ | 手上的資料 $Z$(每筆機率 $1/n$ 的經驗分布) |
| 抽一份資料 | 從 $P$ 抽 $n$ 筆 | 從 $Z$ 有放回抽 $n$ 筆,得到 $Z^{*r}$ |
| 算估計量 | $\hat\alpha$ | $\hat\alpha^{*r}$ |
| 重複 | 理論上重複很多次(做不到) | $r=1,\ldots,B$,電腦可以做 |
為什麼一定要「有放回」?有放回時,每次抽籤都面對同一個經驗分布,$n$ 筆彼此獨立,才能模仿「從母體再抽一份資料」;不放回只會得到原資料的重新排列,看不到變異。直覺與前提見下方「為什麼要有放回重抽?」收合區。
只有 3 筆資料的例子最容易看清楚:原資料是觀測 1、2、3;一份 bootstrap 樣本可能是 3、1、3,第 3 筆出現兩次、第 2 筆沒出現。重複 $B$ 次得到 $\hat\alpha^{*1},\ldots,\hat\alpha^{*B}$。
ISLP 用 $B=1000$ 得到 $\mathrm{SE}_B(\hat\alpha)=0.087$,和上面理想模擬的 0.083 很接近;課程 lab 用自己的種子得到 0.0912。
我們想知道的是:如果能從母體 $P$ 一再抽出大小 $n$ 的新資料,估計量 $\hat\theta$ 會怎麼波動。$P$ 未知,bootstrap 就用手上資料的經驗分布 $\hat P$(每筆機率 $1/n$)代替它,這叫 plug-in 原則。接下來在 bootstrap 世界裡照做一次「抽樣 → 估計」:
$$\text{真實世界:}\ P\ \xrightarrow{\text{抽 }n\text{ 筆}}\ Z\ \to\ \hat\theta,\qquad \text{bootstrap 世界:}\ \hat P\ \xrightarrow{\text{有放回抽 }n\text{ 筆}}\ Z^{*}\ \to\ \hat\theta^{*}.$$直覺是:$\hat\theta^{*}$ 在 $\hat\theta$ 周圍的散布,模仿 $\hat\theta$ 在真值 $\theta$ 周圍的散布。所以 $\hat\theta^{*}$ 的標準差可以拿來估 $\mathrm{SE}(\hat\theta)$。
這些條件說的是「bootstrap 世界和真實世界夠像」。在這些條件,加上適當的矩條件(例如平均數需要有限變異數;$\hat\alpha$ 還要求分母不退化)成立時,bootstrap 不必假設常態,也不必推導 $\mathrm{SE}$ 的公式;條件不成立時,程式照樣算得出數字,但它不再描述估計量真正的波動。
百分位區間。把 $B$ 個 $\hat\alpha^{*r}$ 排序,取第 5 與第 95 百分位數,就得到近似 90% 的信賴區間。講義的例子是 $(0.43,\,0.72)$。這叫 bootstrap 百分位信賴區間(percentile interval),是最簡單的一種;估計量偏差大、樣本太少或統計量不規則時,涵蓋率可能不足。
迴歸曲線的信賴區間。講義用局部迴歸(lowess)曲線示範,步驟是:
這是逐點區間:每個 $x$ 各自有 95% 的近似涵蓋,不代表整條曲線同時落在帶內的機率是 95%。它描述平均曲線的不確定性,不包含新觀測本身的雜訊,所以不是預測區間。
講義補充連結:statsmodels 的 lowess 範例(含 bootstrap 信賴區間帶)。
講義先將觀測 $(x_i,y_i)$ 配對重抽、每次重新擬合,再在同一組 $x$-grid 評估曲線。每個 grid 點的重抽分位數描述平均曲線的估計不確定性,屬於逐點區間。它不涵蓋新觀測本身的誤差,也不是整條曲線同時涵蓋的區間。
用車子資料想:我們問「100 horsepower 的車平均 mpg 大約多少」,與「下一台 100 horsepower 的車會有多少 mpg」,後者還有個別車輛的變動。即使平均曲線估得很準,新車的 mpg 仍會分散。如果只重抽係數或擬合線,再取曲線的分位數,就會漏掉新觀測的誤差。
要得到新觀測的預測區間,必須在係數的重抽變異之外,再加入新觀測本身的誤差。講義附錄只列出連結,建構方法(殘差 bootstrap、保形預測等)可從下方連結延伸閱讀。
延伸來源:statsmodels:重抽 LOWESS 曲線的逐點區間/講義的 bootstrap 預測區間討論/MAPIE 官方文件:預測區間與保形方法
bootstrap 每次抽一筆觀測,隱含假設觀測彼此獨立。時間序列的相鄰觀測相關,講義的做法是改成有放回地抽連續的區塊,以保留區塊內的相關結構。
假設每天的溫度有正向自我相關,今天偏高,明天也往往偏高。逐筆重抽會把連續的高溫段打散,重抽序列便不再有同樣的相依性。對平均數,差別可以直接從變異數展開看見:
$$\operatorname{Var}(\bar X)=\frac1{n^2}\left[\sum_i\operatorname{Var}(X_i)+2\sum_{i\lt j}\operatorname{Cov}(X_i,X_j)\right].$$正共變異數增加平均數的變異;逐筆 bootstrap 打散相依結構後,可能漏掉這部分變異。方向仍取決於相依型態與統計量,不能斷言所有相依資料的標準誤都必定偏小。
移動區塊 bootstrap先取長度 $l$ 的所有連續區塊,起點可為 1 到 $n-l+1$;再有放回抽區塊、按抽到的順序串接,直到至少 $n$ 筆,最後裁成 $n$ 筆。區塊內原本的先後與相關被保留,區塊接縫則不保留原序列的全部相依性。非重疊區塊、循環區塊與隨機區塊長度是不同版本,使用時要交代採用哪一種。
例如序列 1 到 8、區塊長度 3,移動區塊有 $(1,2,3),(2,3,4),\ldots,(6,7,8)$。抽到起點 4、1、5,串成 $(4,5,6,1,2,3,5,6,7)$,裁前 8 筆後才重算估計量。重複的是整個步驟,不是只拿一次亂序結果當作所有樣本。
區塊太短可能保留不了主要相依;太長又讓可重新組合的單位太少,估計不穩。平穩性、長期趨勢與季節性也會影響做法:若資料生成方式隨時間改變,單純抽區塊並不能自動處理。先判斷資料有哪些相依關係,再選區塊版本與長度,並檢查改變長度時結果是否穩定。
群組資料同樣要先決定重抽的單位。例如病人內重複觀測相關、病人之間可視為獨立,就可考慮抽整位病人而非逐次就診;是否還要在病人內重抽,取決於研究的抽樣設計。bootstrap 的重抽單位與前面 GroupKFold 的群組界線都來自資料結構,但兩者的目的不同:一個估不確定性,一個評估未見群組的預測。
Portfolio 的一列是同一期的兩個報酬 $(X_i,Y_i)$。同一期兩個資產的共同漲跌決定共變異數,因此不能把 $X$ 與 $Y$ 分別洗牌或分別重抽;那會破壞原本的配對,回答另一個問題。每次抽的是列索引,兩欄一起跟著走。Lab 的 alpha_func(data, idx) 正是先取同一組 idx,再算兩欄的樣本共變異數。
權重公式的推導與分母為正的條件,見本節開頭 $\alpha$ 公式下方的證明。
三筆觀測的重抽例子也要區分「位置」與「不同資料」:索引 $(3,1,3)$ 仍有三筆,但第三列出現兩次,第二列完全沒出現。對樣本平均數可列出全部 $3^3=27$ 個等機率索引組合;對 Portfolio 權重,若重抽後全是同一列,樣本共變異數可能退化,估計量便未必有定義。抽出索引後,還要確認重抽資料能不能算出要研究的統計量;資料退化時,bootstrap 估計也可能失去定義。
boot_SE()np.float64(0.57583207459283)
這就是 ISLP 書上的 $\hat\alpha=0.5758$。
來源:Ch05-resample-lab-zh.ipynb
np.float64(0.6074452469619004)
replace=True 是關鍵:有放回,所以同一筆可能被抽到好幾次,也會有一些完全沒被抽到。這一次抽出來的 $\hat\alpha^*=0.6074$,跟 0.5758 差了不少。這個「差」正是我們要量化的東西。
Ch05-resample-lab-zh.ipynb
在 Portfolio 資料上,$\mathrm{SE}(\hat\alpha)$ 的 bootstrap 估計是 0.0912。注意這支函式用 $E[\theta^2] - (E[\theta])^2$ 累加,不必存下 1000 個值;它抽的是列的位置,不是 index 標籤。Auto 的 index 是車名且有重複,依標籤抽樣會把同名的車一次全部取出,標準誤會被低估。
來源:Ch05-resample-lab-zh.ipynb
array([[39.88064456, -0.1567849 ],
[38.73298691, -0.14699495],
[38.31734657, -0.14442683],
[39.91446826, -0.15782234],
[39.43349349, -0.15072702],
[40.36629857, -0.15912217],
[39.62334517, -0.15449117],
[39.0580588 , -0.14952908],
[38.66688437, -0.14521037],
[39.64280792, -0.15555698]])partial() 凍結模型與反應變數兩個參數,得到 boot_SE() 需要的 (D, idx) 函式。上面是前 10 份 bootstrap 樣本的截距與斜率。
Ch05-resample-lab-zh.ipynb
intercept 0.717 horsepower 0.006 Name: std err, dtype: float64
1000 次 bootstrap 給 $\mathrm{SE}(\hat\beta_0)\approx0.85$、$\mathrm{SE}(\hat\beta_1)\approx0.0074$,公式給 0.717 與 0.006。差異來自公式的假設:它用殘差估 $\sigma^2$,而直線模型漏掉了非線性,殘差被誇大;公式也假設 $x$ 固定。bootstrap 不依賴這些假設,但仍假設各列彼此獨立,也不保證一定比較準。
來源:Ch05-resample-lab-zh.ipynb
intercept 1.800 poly(horsepower, degree=2, raw=True)[0] 0.031 poly(horsepower, degree=2, raw=True)[1] 0.000 Name: std err, dtype: float64
二次模型對資料的擬合好得多,bootstrap 與公式的標準誤因此對應得更好。
來源:Ch05-resample-lab-zh.ipynb
有放回地抽 $n$ 次,每筆至少出現一次的機率如下;它也是不同原始觀測所占比例的期望,不代表每份樣本的固定比例。
$$P(\text{第 } i \text{ 筆有進 bootstrap 樣本}) = 1 - \left(1-\frac{1}{n}\right)^n \;\xrightarrow[n \to \infty]{}\; 1 - e^{-1} \approx 0.632$$剩下那 36.8% 沒被抽到的樣本叫做 out-of-bag(OOB)。 它們對這一輪的模型來說是天然的驗證集。樹狀方法的 bagging 與 random forest 就靠這招 不另切驗證集就能估計測試誤差。
| $n$ | 5 | 20 | 100 | $n\to\infty$ |
|---|---|---|---|---|
| $1-(1-1/n)^n$ | 0.6723 | 0.6415 | 0.6340 | $1-e^{-1}=0.6321$ |
這也回答了講義的問題「bootstrap 能估預測誤差嗎?」交叉驗證的 $k$ 個驗證折和訓練用的其他 $k-1$ 折沒有重疊,交叉驗證行得通靠的就是這一點。若拿每份 bootstrap 樣本訓練、用原始資料驗證,每份訓練樣本約含三分之二的原始觀測,驗證資料大量出現在訓練資料裡,會嚴重低估真正的預測誤差。只用沒抽到的觀測來驗證可以部分修正,但方法會變複雜;最後還是交叉驗證比較簡單。
第一步:某筆在一次抽籤中沒被抽到。從 $n$ 筆中有放回抽一次,抽到第 $j$ 筆的機率是 $1/n$,沒抽到的機率是 $1-1/n$。
第二步:$n$ 次都沒被抽到。各次抽籤獨立,所以第 $j$ 筆完全不在 bootstrap 樣本裡的機率是 $(1-1/n)^n$。
第三步:取極限。由 $\lim_{n\to\infty}(1-1/n)^n=e^{-1}\approx0.368$,第 $j$ 筆至少出現一次的機率趨近 $1-e^{-1}\approx0.632$。
第四步:期望的不同觀測數。令 $I_j$ 表示第 $j$ 筆是否至少出現一次,則一份 bootstrap 樣本中不同觀測的個數是 $\sum_jI_j$,期望為 $n\{1-(1-1/n)^n\}\approx0.632n$,大約三分之二。各 $I_j$ 不獨立也不影響這個期望;每一份樣本的實際比例會在 0.632 附近起伏。
講義補充連結:為什麼每份 bootstrap 樣本平均約含三分之二的觀測。
上方的推導已說明:每份重抽資料平均只含約三分之二的不同觀測,所以「重抽資料訓練、全部原始資料驗證」有大量重疊。補救的方向是只對這次沒抽到的 OOB 觀測預測,避開直接的觀測重疊。
例如原始索引 1 到 5,抽到 $(1,1,3,4,4)$,這次的 OOB 是 2、5。下一次抽到 $(2,3,3,5,5)$,OOB 是 1、4。各次可評估的資料與數目都不同;同一觀測會在多個重抽模型的 OOB 出現,模型也不是彼此獨立的。
OOB 解決的是訓練/評估重疊,並沒有讓 bootstrap 訓練集等同於 $n$ 筆獨立的新觀測。不同訓練規模、重複列、調參使用 OOB 以及如何平均分數,都會影響估計的解讀。講義因此以 CV 作為本章預測誤差評估的主線;第八章 bagging/random forest 再使用 OOB 對集成程序做內部評估。
估標準誤時 $B=1000$ 通常就很夠;要估信賴區間的尾端分位數(例如 2.5% 與 97.5%),$B$ 建議拉到 2000 以上,因為尾端需要更多樣本才穩。
注意 $B$ 大只會讓「bootstrap 對真實 SE 的估計」更穩定,不會讓原始資料變多。$n$ 小的時候 bootstrap 本身就不可靠,拉高 $B$ 也救不了。它只是把同一份資料提供的資訊算得更精確而已。
常見的三種情況:估計量依賴極值(bootstrap 樣本的最大值永遠不超過原資料的最大值)、資料不獨立(要改用區塊 bootstrap)、$n$ 很小。背後的原因見上方「為什麼要有放回重抽?直覺與前提」。
bootstrap 的主線是:以觀測為單位有放回重抽、每次重算同一估計量,再由這些估計值的散布估標準誤。平均曲線的信賴區間和新觀測的預測區間不同,後者還要包含新觀測雜訊。下面的延伸說明預測區間與講義附錄的其他重抽樣方法。
$n=100$ 時,一筆特定的觀測值完全沒有出現在某個 bootstrap 樣本裡的機率約為多少?
講義最後的附錄列出 jackknife 與置換檢定,作為 bootstrap 以外的重抽樣工具;兩者都是選讀,可展開閱讀。
Jackknife 不用隨機重抽,而是第 $i$ 次刪掉第 $i$ 筆資料,得到 $\hat\theta_{(-i)}$,總共 $n$ 次。令刪一估計的平均為 $\bar\theta_{(-)}$,其標準誤估計為
$$\widehat{SE}_{jack}=\sqrt{\frac{n-1}{n}\sum_{i=1}^n(\hat\theta_{(-i)}-\bar\theta_{(-)})^2}.$$公式前面的 $(n-1)/n$ 用來校正刪一估計值的變動量。各次只刪一筆,刪一估計值的變動通常比 $n$ 筆樣本重新抽出的變動小,不能直接把 $n$ 個刪一估計的普通標準差當標準誤。
樣本平均數能精確驗算:$\bar x_{(-i)}=(n\bar x-x_i)/(n-1)$,刪一估計的平均仍是 $\bar x$。代入上式得到 $\widehat{SE}_{jack}=s/\sqrt n$,與獨立觀測的樣本平均數標準誤一致。例如資料 $(2,4,9)$,平均 5,$s^2=13$,標準誤是 $\sqrt{13/3}\approx2.082$。
Jackknife 常適用於對單筆資料影響平滑的統計量;中位數、樣本最大值等非平滑或端點問題不能一概套用。與 bootstrap 相比,它只有 $n$ 個決定性的刪一樣本,常較省計算,但不會給出同樣豐富的重抽分布。
| 方法 | 每次怎麼產生樣本 | 主要用途與限制 |
|---|---|---|
| Bootstrap | 從 $n$ 筆有放回抽 $n$ 筆,重複 $B$ 次 | 近似估計量抽樣分布;必須選對重抽單位 |
| Jackknife | 逐次刪一筆,得到 $n$ 份大小 $n-1$ 的樣本 | 估標準誤;對非平滑統計量有限制 |
| Permutation | 依虛無假設允許的交換方式重排標籤或觀測 | 近似虛無分布與 p-value;交換性與設計必須合理 |
Bootstrap 通常從經驗分布重抽,問估計量在重複抽樣時如何波動;置換檢定則依虛無假設,把允許交換的部分重排,問「如果沒有這個關係,會得到多極端的統計量」。兩者都會重複計算;讀結果之前,先確認近似的是抽樣分布還是虛無分布。
例如兩組的平均數差,先固定每組筆數並計算觀測差 $T_{obs}$。若虛無假設使觀測在兩組間可交換,就把組別標籤重排、重新計算差 $T$。隨機做 $B$ 次雙尾置換,可用
$$\hat p=\frac{1+\sum_{b=1}^B I(|T_b|\ge |T_{obs}|)}{B+1}.$$雙尾時兩邊都要取絕對值;只寫 $T_b\ge |T_{obs}|$ 會漏掉負方向的極端結果。加一是隨機置換常用的 Monte Carlo 校正,使原始排列也被計入比較;完整枚舉所有允許排列時,則直接以其精確比例計算。$B=199$ 的隨機置換最小 p-value 是 1/200,不可能宣稱得到了 0。
置換要求的是虛無假設下的交換性。同一病人的重複紀錄、配對實驗、時間序列不能任意逐筆洗牌;應尊重配對、區塊或隨機分派設計。兩組平均相同也不必表示整個分布相同,因此簡單重排標籤檢定的條件,比「只要平均相同」更強。
講義的分類例子保留 $X$、重排 $y$。原始資料先得到交叉驗證分數;每次置換標籤後,重新擬合每一折的模型、重新得到 CV 分數,形成模型在虛無假設下的分數分布。不能只洗牌已算好的預測值,或固定原始資料訓練好的分類器,因為那沒有重做學習程序。
sklearn 的 score 一律愈大愈好,所以 permutation_test_score 比較置換分數是否大於或等於原始分數。若使用負 MSE,也依這個方向比較,不另把 MSE 的「小才好」直接貼到 score 上。前處理包進 Pipeline;若原始程序含調參或特徵選擇,置換時也要重新執行同樣的選擇程序。
這個例子沿用官方分類器示範的 Iris,用分層 CV 和線性 SVM;是講義附錄的延伸,而不是 Portfolio 重抽 Lab 的結果。低 p-value 表示觀測分數相對於這套置換程序很不尋常,支持特徵與標籤之間存在模型能利用的關係;不表示分數一定足夠高、模型一定適合部署,也不是虛無假設為真的機率。高 p-value 也可能是模型沒利用到關係或檢定力不足,不能證明完全沒有關係。
延伸來源:講義:Permutation test/scikit-learn:分類分數的置換檢定示範/permutation_test_score:分數、群組與 p-value
下面幾題取自 ISLP §5.4 的課後習題,題號都對得回課本。先自己想過再點選項; 每個選項都有解說;需要完整解答時,可查閱下面3個站。
從 $n$ 筆資料中有放回地抽第一筆時,抽到的不是第 $j$ 筆觀測值的機率是多少?第二筆呢?
相對於驗證集法,$k$-fold CV 的優點是什麼?
課本第 8 題在模擬資料上跑 degree 1 到 4 的 LOOCV,真實模型是二次的。預期會看到什麼?
課本第 9 題要對 Boston 的 medv 平均值做 bootstrap,並跟公式解 $\mathrm{{SE}}(\bar\mu) = s/\sqrt{{n}}$ 比較。預期結果是?
考前把這一頁掃過去就好。
| 方法 | 在估什麼 | 偏差 | 變異 | 計算成本 | 隨機性 | 典型用途 |
|---|---|---|---|---|---|---|
| 驗證集法 | 測試誤差 | 大(高估) | 大 | $1\times$ | 有,很大 | 快速看一眼 |
| LOOCV | 測試誤差 | 最小 | 大 | $n\times$ | 無 | 小資料、線性有捷徑 |
| $k$-fold CV | 測試誤差 | 小 | 小 | $k\times$ | 有,較小 | 選模型的標準做法 |
| Bootstrap | 估計量的 SE | — | — | $B\times$ | 有,$B$ 大就穩 | 估不確定性 |
| 名稱 | 式子 | 備註 |
|---|---|---|
| LOOCV | $\mathrm{CV}_{(n)} = \frac1n\sum_i \mathrm{MSE}_i$ | 式 5.1 |
| LOOCV 捷徑(最小平方) | $\frac1n\sum_i\left(\frac{y_i-\hat y_i}{1-h_i}\right)^2$ | 式 5.2,只擬合一次模型 |
| $k$-fold | $\mathrm{CV}_{(k)} = \frac1k\sum_j \mathrm{MSE}_j$ | 式 5.3 |
| 分類版 | $\mathrm{Err}_j = \frac{1}{|C_j|}\sum_{i\in C_j} I(y_i \ne \hat y_i)$ | 式 5.4 |
| 最小變異配置 | $\alpha = \frac{\sigma_Y^2-\sigma_{XY}}{\sigma_X^2+\sigma_Y^2-2\sigma_{XY}}$ | 式 5.7 |
| 在 bootstrap 樣本裡的機率 | $1-(1-1/n)^n \to 1-e^{-1} \approx 0.632$ | OOB 的來源 |
詞彙卡整理本章講義與 ISLP 第 5 章中常用的統計或機器學習專有名詞,正面附英文名稱。 先看正面的術語,試著說出定義,再翻面核對。可以洗牌複習,也可以搭配本章例子練習解釋。