沒有 y 的時候,還能學到什麼?

ISLP 第 12 章 — 對應講義 12
PCA|負荷量與得分|PVE|Scree plot|Biplot|矩陣補全|K-means|階層式分群|Dendrogram
向下捲動開始互動
📌 本頁使用方式(ISLP Ch.12|講義 12)

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

CONTENTS · 內容目錄
PROLOGUE · 開場

非監督式學習的挑戰:沒有 y 就沒有對錯 ISLP §12.1講義 12 · p.2–6

前面十幾週,每一章都有一個 y。有了 y,一切都好辦: 切出測試集、算 MSE 或錯誤率、用交叉驗證挑超參數——「哪個模型比較好」有客觀答案

這一章把 y 拿掉。手上只剩 X₁, X₂, …, Xp,問題變成: 這批資料本身有什麼結構?能不能用兩個座標軸就把 6830 個基因的樣本畫在紙上? 這 64 個細胞株是不是可以分成幾個自然的群?

麻煩的地方是:沒有 y,就沒有對錯。你沒辦法交叉驗證一個分群結果, 因為沒有「正確的群」可以比。所以非監督式學習比監督式主觀得多, 它的定位通常是探索式資料分析(exploratory data analysis)—— 產出的是值得進一步檢驗的假設,不是結論。

本章的三條主線 1. 主成分分析(PCA):找幾個「變異最大」的方向, 把 p 維壓成 2 維畫出來。它同時也是「最佳低維近似」。
2. 矩陣補全(matrix completion):把 PCA 的想法套到有缺失值的矩陣上, 順手就變成推薦系統。
3. 分群(clustering):K-means 與階層式分群,兩種找子群的方式。

PCA 與分群都在「化簡資料」,但化簡的方式不同,這個分工先記住:

產出什麼問的問題要先決定什麼本頁的節
PCA連續的低維座標(每筆資料一組新座標)哪幾個方向的變異最大?留幾個主成分 MP01–P06
分群離散的群標籤(每筆資料一個編號)哪些觀測值彼此相似?K,或樹要切在哪P07–P09
沒有 y 不代表可以隨便說 非監督式學習最大的風險不是算錯,而是過度解讀。 任何時候把資料丟去分群,它一定會給你群——問題是那些群是真的子群, 還是只是把雜訊切開而已。ISLP §12.4.3 的建議是:換不同設定多跑幾次, 看哪些結構每次都出現;報告時說清楚這是探索結果,不是定論。
QUIZ · 為什麼非監督式比較難

為什麼非監督式學習「無法用交叉驗證來驗證結果」?

(A) 交叉驗證需要在留出的資料上比對預測與真實答案,而非監督式問題根本沒有真實答案可比
(B) 因為非監督式方法沒有參數可以調,所以不需要交叉驗證
(C) 因為非監督式方法的計算量太大,跑 k 折會太慢
PART 01 · 主成分是什麼

第一主成分:變異最大的那個方向 ISLP §12.2.1講義 12 · p.7–12

先想一個很現實的問題:p = 10 個變數,兩兩畫散佈圖有 45 張,你看不完; 而且每一張都只含一小部分資訊。有沒有辦法用兩張圖就把大部分結構看完

PCA 的答案是:不要看原始的座標軸,去找資料變異最大的那個方向。 第一主成分是所有標準化線性組合裡樣本變異數最大的那一個:

$$Z_1 = \phi_{11} X_1 + \phi_{21} X_2 + \cdots + \phi_{p1} X_p, \qquad \text{s.t.} \sum_{j=1}^{p} \phi_{j1}^2 = 1$$

那些係數 $\phi_{j1}$ 叫做負荷量(loading),合起來是負荷向量 $\phi_1$。 為什麼要限制平方和等於 1?因為不限制的話,把係數全部乘 100 變異數就變 10000 倍, 「最大」就沒有意義了。把資料先置中(每欄減掉平均)之後,要解的是

$$\max_{\phi_{11},\dots,\phi_{p1}} \left\{ \frac{1}{n}\sum_{i=1}^{n} \Big(\sum_{j=1}^{p} \phi_{j1} x_{ij}\Big)^2 \right\} \quad \text{s.t.} \quad \sum_{j=1}^{p} \phi_{j1}^2 = 1$$

括號裡的東西就是第 i 筆資料投影到 $\phi_1$ 上的值,叫做得分(score) $z_{i1}$。因為資料置中過,得分的平均是 0,所以上式就是得分的樣本變異數。 負荷向量是新座標軸的方向,得分是每筆資料在新座標軸上的位置——這兩個詞不要混。

下面這個元件就是把上面那個最佳化問題「用手轉一遍」:拖動角度,看投影後的變異數怎麼變。

拖動橘色把手轉動投影方向,看投影後的變異數怎麼變。
目前這個方向
角度
投影後的變異數
佔總變異的比例
最大變異(第一主成分)
PC1 的方向
怎麼玩
拖那顆橘色的把手(或用滑桿)轉動灰色的投影軸。每個點會沿虛線垂直落到軸上,變成一個一維的數字。那些落點的變異數就是右上角那個數。轉到變異數最大的地方,元件會自動吸附並告訴你——那就是第一主成分。
為什麼不是「距離最近」? P03
其實兩者是同一件事。把點投影到軸上,「投影後散得最開」與「原始點到軸的垂直距離平方和最小」加起來是定值(畢氏定理),所以最大化前者等於最小化後者。這就是 P03 那一節要講的另一種解釋。

找完第一主成分之後,第二主成分是所有跟 $Z_1$ 不相關的線性組合裡變異最大的那一個。 「與 $Z_1$ 不相關」這個條件等價於「方向 $\phi_2$ 與 $\phi_1$ 垂直」, 所以主成分就是一組互相垂直的新座標軸,總共最多有 $\min(n-1,\,p)$ 個。

講義完整實作:標準化 → PCA() → 取出負荷量

講義 12 · USArrests 的 PCA
scaler = StandardScaler(with_std=True, with_mean=True) USArrests_scaled = scaler.fit_transform(USArrests) pcaUS = PCA() scores = pcaUS.transform(USArrests_scaled) pcaUS.components_
預期輸出(儲存格 29)
array([[ 0.53589947,  0.58318363,  0.27819087,  0.54343209],
       [-0.41818087, -0.1879856 ,  0.87280619,  0.16731864],
       [-0.34123273, -0.26814843, -0.37801579,  0.81777791],
       [-0.6492278 ,  0.74340748, -0.13387773, -0.08902432]])

components_每一列是一個負荷向量。第一列 [0.536, 0.583, 0.278, 0.543] 在 Murder/Assault/Rape 上幾乎一樣重、UrbanPop 明顯較輕——所以 PC1 大致就是「整體暴力犯罪率」。第二列幾乎全押在 UrbanPop(0.873),那是「都市化程度」。注意 PCA() 預設只置中、不縮放,所以標準化要自己先做(第 19 格)。

來源:Ch12-unsup-lab-zh.ipynb · 儲存格 19、21、27、29
QUIZ · 負荷量與得分

USArrests 的 pcaUS.components_ 是 4×4、scores 是 50×4。哪個描述正確?

(A) components_ 的每一列是一個負荷向量(長度 p = 4),scores 的每一行是一個州的四個得分
(B) components_ 的每一列是一個州在四個主成分上的座標
(C) 兩者都是 50×4,因為 PCA 對每一筆資料各算一組負荷量
PART 02 · Biplot 怎麼讀

USArrests:一張圖同時放州與變數 ISLP §12.2.2講義 12 · p.13–16

算完 PCA 之後,最常畫的圖是 biplot(雙標圖): 同一張圖上同時放得分(點)與負荷量(箭頭)。 ISLP 圖 12.1 就是 USArrests 的 biplot——50 個州當點,4 個變數當箭頭。

讀法有三條,記住就夠用:

下面這個 biplot 用的是課本的資料。真正要玩的是那個 toggle: 按下「未標準化」,整張圖會變形。

這是標準化後的 biplot,對應 ISLP 圖 12.1 與圖 12.4 左。
負荷量(箭頭的座標)
Murder
Assault
UrbanPop
Rape
PC1 的 PVE
四個變數的變異數 儲存格 17
Murder18.97
Assault6945.17
UrbanPop209.52
Rape87.73

Assault 是「每十萬人的件數」,數字本來就大得多。不標準化的話 PC1 幾乎等於 Assault 自己。

為什麼有些州沒有標字 圖 12.1
50 個州全部標字會擠成一團。這裡只標課本正文點名的八個:CA/NV/FL(犯罪率高)、ND/MS(低)、HI(都市化高但犯罪低)、IN(兩者都接近平均)、AK。滑到點上看不到名字是刻意的——biplot 要看的是整體結構,不是逐一查表。

講義完整實作:手工畫 biplot

講義 12 · biplot(scatter + arrow + text)
scale_arrow = s_ = 2 scores[:,1] *= -1 pcaUS.components_[1] *= -1 # flip the y-axis fig, ax = plt.subplots(1, 1, figsize=(8, 8)) ax.scatter(scores[:,0], scores[:,1]) ax.set_xlabel('PC%d' % (i+1)) ax.set_ylabel('PC%d' % (j+1)) for k in range(pcaUS.components_.shape[1]): ax.arrow(0, 0, s_*pcaUS.components_[i,k], s_*pcaUS.components_[j,k]) ax.text(s_*pcaUS.components_[i,k], s_*pcaUS.components_[j,k], USArrests.columns[k])

scikit-learn 沒有內建 biplot,所以 lab 用 ax.scatter 畫得分、ax.arrow 畫負荷量,再用 s_ = 2 把箭頭放長一點(否則負荷量都在 ±1 以內,跟得分的尺度差太多,會縮成一小坨)。箭頭長度只是為了看得清楚,可以自己乘上任何常數。
第 2 行與第 3 行把第二個主成分的得分與負荷量同時乘上 −1。同時翻兩邊,圖只是上下鏡射,任何結論都不變——這正是 P05 要講的符號不唯一。本頁的 biplot 直接用儲存格 29 那組負荷量,跟課本表 12.1 的數字逐位相同。

來源:Ch12-unsup-lab-zh.ipynb · 儲存格 31、33
QUIZ · 讀 biplot

在 USArrests 的 biplot 上,Murder 與 UrbanPop 兩支箭頭夾角接近 90°。這代表什麼?

(A) 這兩個變數在前兩個主成分所描述的範圍內幾乎不相關
(B) 這兩個變數的變異數差不多大
(C) 這兩個變數合起來就能解釋所有變異,其他變數是多餘的
PART 03 · 另一種解釋

主成分也是「最佳低維近似」 ISLP §12.2.2講義 12 · p.17–19

到目前為止主成分的定義是「變異最大的方向」。現在換一個完全不同的角度看它, 結論會一模一樣——這件事很值得多花五分鐘。

第一主成分的負荷向量所定義的那條直線,是 p 維空間中離所有資料點平均平方距離最近 的那條線。前兩個主成分張出的平面,是離所有資料點最近的那個平面(ISLP 圖 12.2 左)。 前 M 個主成分張出的是最近的 M 維超平面。

把「最近」寫成最佳化問題就清楚了。置中後的資料矩陣 $\mathbf{X}$, 在所有 $x_{ij} \approx \sum_{m=1}^{M} a_{im} b_{jm}$ 這種形式的近似裡, 找殘差平方和最小的那一組:

$$\min_{A \in \mathbb{R}^{n\times M},\, B \in \mathbb{R}^{p\times M}} \left\{ \sum_{j=1}^{p} \sum_{i=1}^{n} \Big( x_{ij} - \sum_{m=1}^{M} a_{im} b_{jm} \Big)^2 \right\}$$

解出來的 $\hat a_{im}$ 就是得分 $z_{im}$、$\hat b_{jm}$ 就是負荷量 $\phi_{jm}$。 也就是說:「變異最大」與「近似誤差最小」是同一個問題的兩種寫法。 ISLP 式 12.11 把這件事寫得很漂亮:

$$\underbrace{\sum_{j=1}^{p} \frac{1}{n} \sum_{i=1}^{n} x_{ij}^2}_{\text{資料的總變異}} = \underbrace{\sum_{m=1}^{M} \frac{1}{n} \sum_{i=1}^{n} z_{im}^2}_{\text{前 } M \text{ 個主成分的變異}} + \underbrace{\frac{1}{n} \sum_{j=1}^{p} \sum_{i=1}^{n} \Big( x_{ij} - \sum_{m=1}^{M} z_{im}\phi_{jm} \Big)^2}_{M \text{ 維近似的 MSE}}$$

左邊是固定的,所以中間變大就等於右邊變小。這也是為什麼下一節的 PVE 可以直接讀成「近似的 $R^2$」。

實務上怎麼算:SVD 求主成分不必真的做特徵分解。把置中後的資料矩陣做 奇異值分解(singular value decomposition, SVD) $\mathbf{X} = \mathbf{U}\mathbf{D}\mathbf{V}^{\mathsf T}$, $\mathbf{V}$ 的每一列就是負荷向量、$\mathbf{U}\mathbf{D}$ 就是得分矩陣。 numpy.linalg.svd 比自己算 $\mathbf{X}^{\mathsf T}\mathbf{X}$ 的特徵向量穩定得多, 而且下一節的矩陣補全就是靠它一步步逼近的。

講義完整實作:SVD 與 components_ 的關係

講義 12 · np.linalg.svd 取出負荷矩陣
X = USArrests_scaled U, D, V = np.linalg.svd(X, full_matrices=False) U.shape, D.shape, V.shape V
預期輸出(儲存格 50)
array([[-0.53589947, -0.58318363, -0.27819087, -0.54343209],
       [-0.41818087, -0.1879856 ,  0.87280619,  0.16731864],
       [ 0.34123273,  0.26814843,  0.37801579, -0.81777791],
       [ 0.6492278 , -0.74340748,  0.13387773,  0.08902432]])

V 的每一列就是負荷向量,只差符號。跟上一節儲存格 29 的 components_ 比:第 1、3、4 列整列變號,第 2 列一模一樣。
lab 儲存格 51 又印了一次 components_,但那時第 33 格已經把 PC2 翻號了,所以第 2 列跟儲存格 29 不同——不是印錯,是同一個物件被就地改過。儲存格 53 與 54 也是同一件事:U * Dscores 差整組符號。

來源:Ch12-unsup-lab-zh.ipynb · 儲存格 48、50、51
觀念釐清
Q:既然「變異最大」與「近似最好」是同一件事,為什麼課本要講兩次?

因為它們通往不同的用途。

「變異最大」的說法讓你解讀主成分:負荷量告訴你這個方向由哪些變數組成,PC1 是「整體犯罪率」、PC2 是「都市化」這種話就是從這裡讀出來的。

「近似最好」的說法讓你把 PCA 當工具用。既然前 M 個主成分是最佳的秩 M 近似,那它就可以拿來壓縮(存 M 個得分而不是 p 個原值)、去雜訊(NCI60 那種資料常先取前幾個主成分再分群)、以及最直接的——填補缺失值。下一節 P06 的矩陣補全整個建立在這個解釋上,從「變異最大」那邊完全看不出來要怎麼做。

QUIZ · 最佳低維近似

式 12.11 說「總變異 = 前 M 個主成分的變異 + M 維近似的 MSE」。由此可以推出什麼?

(A) 把前 M 個主成分的變異最大化,等於把 M 維近似的誤差最小化
(B) M 愈大,前 M 個主成分的變異愈大,所以近似誤差也愈大
(C) 只有在資料標準化過的情況下這個等式才成立
PART 04 · PVE 與 scree plot

要留幾個主成分?先看解釋了多少變異 ISLP §12.2.3講義 12 · p.20–22

壓到 2 維畫出來很方便,但丟掉了多少東西?這個問題的答案叫做 解釋變異比例(proportion of variance explained, PVE)。

置中後資料的總變異是 $\sum_{j=1}^{p} \frac{1}{n}\sum_{i=1}^{n} x_{ij}^2$, 第 m 個主成分的變異是 $\frac{1}{n}\sum_{i=1}^{n} z_{im}^2$,所以

$$\mathrm{PVE}_m = \frac{\sum_{i=1}^{n} z_{im}^2}{\sum_{j=1}^{p}\sum_{i=1}^{n} x_{ij}^2} = 1 - \frac{\mathrm{RSS}_M}{\mathrm{TSS}}\Big|_{M=m} - \text{(前 } m-1 \text{ 個的部分)}$$

所有 $\min(n-1,p)$ 個 PVE 加起來剛好是 1。累積 PVE 就是「前 M 個主成分留住了幾成」, 由上一節的式 12.11,它同時也是「用前 M 個主成分近似資料矩陣」的 $R^2$。

圖表需要連網載入 Chart.js。此圖的重點:USArrests 的四個 PVE 是 62.0% / 24.7% / 8.9% / 4.3%,第二個之後就掉下來了,所以留兩個主成分(累積 86.8%)是合理的選擇。
拖滑桿改變 M,看留住多少變異、丟掉多少。
2
滑桿選的 M
M2
累積 PVE(留住的變異)
丟掉的變異
M 維近似的 RSS / TSS
要存幾個數字
怎麼看這張圖 圖 12.3
實線是每個主成分自己的 PVE(這就是 scree plot),虛線是累積 PVE。虛線碰到 1.0 表示所有主成分都用上了、近似變成完全相等。
肘點在哪裡?
從 62% 掉到 24.7% 是一個大落差,從 24.7% 掉到 8.9% 又是一個。課本的說法是「第二個主成分之後有一個肘點(elbow)」——第三個只解釋不到 10%、第四個不到一半的一半。
但要老實說:這是目測,沒有客觀標準。NCI60 那種資料前七個主成分合起來也只有 40%,照樣只能目測。

講義完整實作:explained_variance_ratio_

講義 12 · 得分的標準差、變異數與 PVE
scores.std(0, ddof=1) pcaUS.explained_variance_ pcaUS.explained_variance_ratio_
預期輸出(儲存格 39)
array([0.62006039, 0.24744129, 0.0891408 , 0.04335752])

三格印的是同一件事的三種寫法:scores.std(0, ddof=1) 是得分的標準差、explained_variance_ 是它的平方、explained_variance_ratio_ 是再除以總和。第一個 0.62006 就是課本說的「第一主成分解釋了 62.0% 的變異」。lab 儲存格 41/43 用 cumsum() 畫出累積版,就是課本圖 12.3 右。

來源:Ch12-unsup-lab-zh.ipynb · 儲存格 35、37、39
QUIZ · PVE 與 scree plot

USArrests 的四個 PVE 是 0.620、0.247、0.089、0.043。如果我只留前兩個主成分,那 50×4 的資料矩陣被近似得多好?

(A) 近似的 R² 是 0.868,也就是殘差平方和只剩總平方和的 13.2%
(B) 無法判斷,PVE 只說變異被解釋多少,跟近似的好壞沒有關係
(C) 近似誤差是 0.089 + 0.043 = 0.132 個單位的 MSE
PART 05 · 尺度化與符號

沒標準化就等於在比單位;符號翻掉不影響結論 ISLP §12.2.3講義 12 · p.23–28

這一節只有兩件事,但兩件都會在實務上咬人:做 PCA 之前要不要標準化, 以及算出來的符號可以信到什麼程度

一、尺度:不標準化就等於在比單位

PCA 找的是「變異最大」的方向。問題是變異數跟單位有關: USArrests 的 Assault 是「每十萬人的件數」,變異數 6945;Murder 也是每十萬人,但只有 18.97。 不標準化的話,第一主成分幾乎整支押在 Assault 上(負荷量 0.995), 其他三個變數等於沒參與。回到 P02 那個 biplot 元件把 toggle 切到「未標準化」就看得到。

更糟的是這個結果是任意的。如果 Assault 改成「每一百人的件數」, 數值全部除以 1000,變異數變成原來的百萬分之一,它就從主宰者變成陪襯。 沒有人希望分析結論取決於別人當年怎麼選單位,所以慣例是先標準化。

什麼時候不該標準化 變數本來就同單位、而且尺度差異本身有意義的時候。 最典型的是基因表現量:p 個基因都用同一種方法測、同一個單位, 某些基因的變異大就是生物上的事實,把它縮成 1 反而是把訊息丟掉。 lab 對 NCI60 還是做了 StandardScaler(),但也在旁邊註明 「這裡其實可以合理主張不要縮放」——這是判斷題,不是規則題。
情況要不要標準化為什麼
變數單位不同(USArrests、房價資料)否則 PC1 只是「數字最大的那個變數」
同單位但量級差很多(收入 vs 年齡)同上,量級差就是單位差的變形
同單位、尺度差異有意義(基因表現、像素)看情況縮放會把真實的變異差異抹掉
已經是比例或分數(0–1 之間)通常不用尺度已經可比
變數是 0/1 指示變數小心標準化會放大罕見類別,考慮別的方法

二、符號:翻掉不影響任何結論

負荷向量描述的是一個方向。把 $\phi_1$ 整支乘上 $-1$, 它指的還是同一條直線,只是箭頭朝反邊;投影後的變異數 $\mathrm{Var}(-Z) = \mathrm{Var}(Z)$ 也沒變。所以最佳化問題有兩個一樣好的解,套件挑哪一個是實作細節。

關鍵在於要一起翻:近似式用的是乘積 $z_{im}\phi_{jm}$, 兩個都乘 $-1$ 乘積不變,重建出來的資料一模一樣。lab 儲存格 33 就是這樣做的 (scores[:,1] *= -1components_[1] *= -1 成對出現)。

講義完整實作:先看變異數,再決定要不要標準化

講義 12 · USArrests 的平均與變異數
USArrests = get_rdataset('USArrests').data USArrests USArrests.mean() USArrests.var()
預期輸出(儲存格 17)
Murder        18.970465
Assault     6945.165714
UrbanPop     209.518776
Rape          87.729159
dtype: float64

6945 對 18.97,差了 366 倍。看到這種數字就知道非標準化不行了。
注意載入方式是 get_rdataset('USArrests').data(statsmodels 去抓 R 的資料集),不是 load_data()——USArrests 不在 ISLP 套件裡。資料的索引是州名,所以 mean()var() 是逐欄算的。

來源:Ch12-unsup-lab-zh.ipynb · 儲存格 11、15、17
觀念釐清
Q:主成分的符號(正負)為什麼不唯一?這會影響結論嗎?

因為最佳化問題只約束了「方向」與「長度」,沒有約束「朝哪一邊」。$\phi_1$ 與 $-\phi_1$ 定義同一條直線;投影後 $Z_1$ 與 $-Z_1$ 的變異數相同,所以兩者都是最佳解,套件回傳哪一個取決於底層的 LAPACK 實作。同一份資料用 numpy.linalg.svdsklearnPCA() 跑,就可能拿到整組相反的符號(lab 儲存格 50 與 51 就差在這裡)。

不影響任何實質結論,但會影響你「怎麼說」。如果 PC1 的負荷量全是正的,你會說「PC1 高 = 犯罪率高」;符號翻掉之後,同一個主成分要說成「PC1 高 = 犯罪率低」。得分也一起翻,所以哪些州靠在一起、哪些州離得遠——完全一樣。

實務上的兩個建議:(1)自己定一個約定並寫在報告裡,例如「讓負荷量總和為正」或「讓某個指標變數的負荷量為正」;(2)比較兩次分析的結果時,先對齊符號再比,不然會誤以為結果不穩定。

Q:為什麼 PCA 之前幾乎一定要標準化?什麼情況下不該標準化?

因為 PCA 的目標函數是變異數,而變異數的大小跟單位有關。USArrests 的 Assault 變異數 6945、Murder 只有 18.97,不標準化的話 PC1 的負荷量在 Assault 上是 0.995、在 Murder 上是 0.042——第一主成分退化成「Assault 換個名字」,PCA 什麼都沒做。

更關鍵的是:這個結果會隨著單位改變。把 Assault 的單位從「每十萬人」改成「每百人」,它的變異數變成百萬分之一,立刻讓位給 UrbanPop。結論不該取決於資料當初是用什麼單位記錄的,所以標準化在這裡不是技巧,是為了讓答案有意義。

不該標準化的情形:變數同單位、而且變異數的差異本身是你想保留的資訊。基因表現量、影像的像素值、同一種感測器的多個通道都屬於這一類。還有一種情形是資料已經是比例(每欄都在 0 到 1 之間),再標準化沒什麼好處。判斷的準則很簡單:問自己「如果某一欄乘上 1000,我希望結論改變嗎?」不希望就標準化。

QUIZ · 尺度與符號

同一份 USArrests,A 同學算出 PC1 的負荷量是 [0.54, 0.58, 0.28, 0.54],B 同學算出 [-0.54, -0.58, -0.28, -0.54]。發生了什麼事?

(A) 兩人算的是同一個主成分,只差整組符號;只要得分也跟著反號,所有結論都一樣
(B) B 同學一定弄錯了,因為負荷量的平方和要等於 1,不能是負的
(C) B 同學忘了標準化,所以符號才會反過來
PART 06 · 矩陣補全

把缺失值當成主成分問題解 ISLP §12.3講義 12 · p.30–38

手上的資料矩陣有缺失值,怎麼辦?兩個常見的做法都不太好: 整列刪掉太浪費(也不現實——缺一格就丟掉一整個州), 用該欄的平均填補則完全沒有用到變數之間的相關

P03 說過前 M 個主成分是資料矩陣的最佳秩 M 近似。 那反過來想:如果 $x_{ij} \approx \sum_m z_{im}\phi_{jm}$, 那缺掉的那一格也可以用這個式子算出來。 這就是矩陣補全(matrix completion)。

問題是要算主成分得先有完整的矩陣,要有完整的矩陣得先補值——雞生蛋蛋生雞。 ISLP 的解法是輪流做(演算法 12.1):先用欄平均粗填, 算主成分、用低秩近似覆蓋缺失格、再算主成分…直到目標函數不再下降。 只在觀測到的格子上算誤差:

$$\min_{A,B} \sum_{(i,j)\in\mathcal{O}} \Big( x_{ij} - \sum_{m=1}^{M} a_{im} b_{jm} \Big)^2$$

$\mathcal{O}$ 是觀測到的位置集合。跟 P03 的式子唯一的差別就是求和範圍—— 但這一改就沒有封閉解了,只能迭代。

圖表需要連網載入 Chart.js。此圖的重點:演算法 12.1 的目標函數(觀測格上的均方誤差)每一輪都下降,USArrests 上大約八輪就收斂。
按「單步」跑演算法 12.1 的一輪:算秩一近似 → 覆蓋缺失格 → 算目標函數。
20
這一輪
缺失格數20 / 200
迭代次數0
觀測格上的 MSS
相對改善
補值與真值的相關
上面那張圖在看什麼
每一欄是一個州(依字母序),四列是四個變數。顏色是標準化後的數值(藍 = 低、紅 = 高)。白色虛線框是被挖掉的格子;按「單步」之後它們會被填上顏色,外框變成橘色。橘框裡的顏色跟旁邊的真值像不像,就是這個方法準不準。
這是本頁自己跑的,不是 lab 的數字 ISLP §12.3
缺失位置由前端的固定種子決定,跟 lab 的 np.random.seed(15) 不同,所以相關係數不會剛好是 0.7114。lab 的實跑數字在下面的 .deck-extra 卡裡。
課本另外報告了 100 次重複的平均:相關 0.63 ± 0.11;如果作弊用完整資料算,是 0.79 ± 0.08。
三個前提,少一個就不要用 1. 缺失必須是隨機的(missing at random)。 「電子秤剛好沒電」可以補;「病人太重上不了秤」不行——缺失本身帶著資訊, 補出來的值會系統性偏低。
2. 變數之間要有相關。低秩近似能work是因為欄與欄之間可以互相預測; 四個互相獨立的變數,補值不會比欄平均好。
3. M 要選。選太小補不出細節,選太大會把雜訊也配進去。 課本第 11 題就是叫你把缺失比例從 5% 掃到 30%、M 從 1 掃到 8,看誤差怎麼變。

講義完整實作:演算法 12.1 的三十行

講義 12 · 挖掉 20 格,然後用主成分反覆填補
n_omit = 20 np.random.seed(15) r_idx = np.random.choice(np.arange(X.shape[0]), n_omit, replace=False) c_idx = np.random.choice(np.arange(X.shape[1]), n_omit, replace=True) Xna = X.copy() Xna[r_idx, c_idx] = np.nan def low_rank(X, M=1): U, D, V = np.linalg.svd(X) L = U[:,:M] * D[None,:M] return L.dot(V[:M]) Xhat = Xna.copy() Xbar = np.nanmean(Xhat, axis=0) Xhat[r_idx, c_idx] = Xbar[c_idx] thresh = 1e-7 rel_err = 1 count = 0 ismiss = np.isnan(Xna) mssold = np.mean(Xhat[~ismiss]**2) mss0 = np.mean(Xna[~ismiss]**2) while rel_err > thresh: count += 1 # Step 2(a) Xapp = low_rank(Xhat, M=1) # Step 2(b) Xhat[ismiss] = Xapp[ismiss] # Step 2(c) mss = np.mean(((Xna - Xapp)[~ismiss])**2) rel_err = (mssold - mss) / mss0 mssold = mss print("Iteration: {0}, MSS:{1:.3f}, Rel.Err {2:.2e}" .format(count, mss, rel_err))
預期輸出(儲存格 64)
Iteration: 1, MSS:0.395, Rel.Err 5.99e-01
Iteration: 2, MSS:0.382, Rel.Err 1.33e-02
Iteration: 3, MSS:0.381, Rel.Err 1.44e-03
Iteration: 4, MSS:0.381, Rel.Err 1.79e-04
Iteration: 5, MSS:0.381, Rel.Err 2.58e-05
Iteration: 6, MSS:0.381, Rel.Err 4.22e-06
Iteration: 7, MSS:0.381, Rel.Err 7.65e-07
Iteration: 8, MSS:0.381, Rel.Err 1.48e-07
Iteration: 9, MSS:0.381, Rel.Err 2.95e-08

讀法:low_rank(Xhat, M=1) 是步驟 2(a)(用 SVD 取秩一近似)、Xhat[ismiss] = Xapp[ismiss] 是 2(b)(只覆蓋缺失格)、mss 是 2(c) 的目標函數。
MSS 從 0.395 掉到 0.381 就幾乎不動了,第 8 輪相對誤差跌破 1e-7 收工。注意分母用的是 mss0 而不是 mss——這樣收斂輪數就不會因為把整個 X 乘上一個常數而改變。
挖法也有講究:先隨機選 20 個州、每州再隨機挑一個變數,所以每一列至少留三個觀測值。整列都空的話,什麼方法都補不出來。

來源:Ch12-unsup-lab-zh.ipynb · 儲存格 56、58、60、62、64
講義 12 · 補得準不準
np.corrcoef(Xapp[ismiss], X[ismiss])[0,1]
預期輸出
np.float64(0.7113567434297361)

20 個補值與真值的相關係數 0.711。lab 儲存格 68–69 換成 fancyimputeSoftImpute(max_rank=1) 再跑一次,相關係數幾乎一樣——說明這支三十行的迴圈沒有偷工減料,而真的要上線時直接用套件(它有更好的收斂控制與正則化)就好。

來源:Ch12-unsup-lab-zh.ipynb · 儲存格 66、68、69
QUIZ · 矩陣補全

演算法 12.1 的步驟 2(b) 只把缺失的格子換成低秩近似值,觀測到的格子保持原值。為什麼不乾脆全部換掉?

(A) 觀測值是真實資料,是唯一的資訊來源;換掉它們就沒有東西可以把近似「拉住」了
(B) 全部換掉在數學上也對,只是會多算幾輪比較慢
(C) 因為觀測格沒有誤差,低秩近似在那些位置一定完全等於原值
PART 07 · K-means

指派、更新、再指派:目標函數單調下降 ISLP §12.4.1講義 12 · p.54–66

換一種化簡方式:不找低維座標,直接把資料分成 K 群。 好的分群是「群內盡量像」,寫成式子就是把群內變異的總和最小化:

$$\min_{C_1,\dots,C_K} \left\{ \sum_{k=1}^{K} W(C_k) \right\}, \qquad W(C_k) = \frac{1}{|C_k|} \sum_{i,i' \in C_k} \sum_{j=1}^{p} (x_{ij} - x_{i'j})^2$$

$W(C_k)$ 是第 k 群內所有兩點之間的平方歐氏距離總和除以群的大小。 看起來要算 $|C_k|^2$ 個距離,但 ISLP 式 12.18 給了一個很好用的恆等式:

$$\frac{1}{|C_k|} \sum_{i,i' \in C_k} \sum_{j=1}^{p} (x_{ij} - x_{i'j})^2 = 2 \sum_{i \in C_k} \sum_{j=1}^{p} (x_{ij} - \bar x_{kj})^2$$

右邊只需要算每個點到群心的距離。這個恆等式不只省算力, 它直接告訴你演算法該長什麼樣:

演算法 12.2(K-means) 步驟 1:隨機給每一筆資料一個 1 到 K 的編號。
步驟 2:重複下面兩件事,直到指派不再改變:
  (a) 算出每一群的形心(群內每個特徵的平均)。
  (b) 把每一筆資料指派給最近的形心。
兩步都保證讓目標函數下降:(a) 因為平均是讓平方偏差最小的常數; (b) 因為換到更近的形心只會讓自己那一項變小。所以目標函數單調不增,一定會停。
選 K 之後按「單步」,交替執行「算群心」與「重新指派」。
演算法 12.2 CODE
隨機指派 1..K 給每一點 while 指派還在變: # 2(a) 群心 = 群內平均 # 2(b) 每點 → 最近的群心 回報這組指派
目前狀態
K3
第幾步
這一步在做什麼
群內平方和
有幾點換了群
換過的初始值 圖 12.9
試過幾組0
最好的收斂值
最差的收斂值
重點在右邊那條曲線
右邊畫的是群內平方和隨步數的變化。它只會往下,不會往上——這就是式 12.18 保證的事。曲線壓平就是收斂了。
但收斂到的是局部極小。按「換初始值」幾次,你會看到同樣的 K 收斂到不同的值(課本圖 12.9 在同一份資料上跑六次,得到三個不同的局部極小)。

講義完整實作:KMeans()

講義 12 · K = 2 的模擬資料
np.random.seed(0); X = np.random.standard_normal((50,2)); X[:25,0] += 3; X[:25,1] -= 4; kmeans = KMeans(n_clusters=2, random_state=2, n_init=20).fit(X) kmeans.labels_
預期輸出(儲存格 107)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
       0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1], dtype=int32)

資料是刻意造的:前 25 筆的平均被平移過,所以真的有兩群。labels_ 幾乎完美地把前 25 與後 25 分開——但注意群的編號是任意的,0 與 1 交換不代表結果不同。這也是為什麼比較兩種分群結果要用 pd.crosstab,不能直接比對標籤。

來源:Ch12-unsup-lab-zh.ipynb · 儲存格 103、105、107
講義 12 · n_init 為什麼要設大
kmeans1 = KMeans(n_clusters=3, random_state=3, n_init=1).fit(X) kmeans20 = KMeans(n_clusters=3, random_state=3, n_init=20).fit(X); kmeans1.inertia_, kmeans20.inertia_
預期輸出
(76.85131986999251, 75.06261242745386)

inertia_ 就是群內平方和(式 12.17 要最小化的那個)。n_init=1 得到 76.85n_init=20 得到 75.06——同一份資料、同一個 K、同一個 random_state,差別只在試了幾組初始值。
76.85 是一個局部極小,不是錯誤,程式不會警告你。所以 lab 的建議是:n_init 設 20 或 50,並且一定要設 random_state 讓結果可重現。

來源:Ch12-unsup-lab-zh.ipynb · 儲存格 113
觀念釐清
Q:K-means 為什麼每次跑可能給不同答案?該怎麼辦?

因為演算法 12.2 的第 1 步是隨機指派。之後的每一步都只保證目標函數下降,不保證下降到全域最小——它會滑進離初始位置最近的那個「盆地」就停住。把 n 筆資料分成 K 群大約有 $K^n$ 種方式,要真的找到全域最小得全部列舉,這不可能,所以我們接受局部極小。

ISLP 圖 12.9 把同一份資料跑六次,得到三個不同的局部極小:目標函數 235.8(四次)、320.9、310.9。其中 235.8 明顯把三群分得最開。重點是:如果你只跑一次,剛好抽到 320.9 那組初值,程式不會告訴你有問題。

標準做法就是多重初始化:跑很多組不同的初值,回報目標函數最小的那一次。scikit-learnn_init 就是這件事(預設 10,lab 建議設 20 或 50)。另外一定要設 random_state——不是為了「挑一個好看的種子」,而是為了讓別人能重現你的數字。上面那張元件的「換初始值」按鈕,按幾次就會看到這個現象。

QUIZ · K-means

為什麼 K-means 的群內平方和一定會單調下降,最後一定會停?

(A) 步驟 2(a) 用群內平均使平方偏差最小、步驟 2(b) 把點移到更近的形心,兩步都不會讓目標變大
(B) 因為每一步都會減少群數,群數減到 K 就停了
(C) 因為 scikit-learn 設了 max_iter 上限,跑到上限就停
PART 08 · 階層式分群

不用先決定 K:dendrogram 與四種 linkage ISLP §12.4.2講義 12 · p.67–90

K-means 有個明顯的麻煩:你得先決定 K。 階層式分群不必——它一次把 1 到 n 群的所有結果都算出來,畫成一棵樹, 你要幾群就切在對應的高度。

做法(凝聚式,agglomerative,也叫 bottom-up)簡單到不像演算法:

演算法 12.3(階層式分群) 步驟 1:每一筆資料自己是一群, 算出所有 $\binom{n}{2}$ 對的相異度。
步驟 2:從 i = n 做到 2:
  (a) 在目前 i 群裡找最相似的一對,把它們合併。 這一對的相異度就是樹上合併的高度
  (b) 重算剩下 i − 1 群之間的相異度。

樹狀圖(dendrogram)的讀法有一條鐵律,很多人第一次都會讀錯:

看高度,不要看左右 兩筆資料有多相似,看的是它們所在的分支第一次合併的高度不是它們在水平方向上有多近。
ISLP 圖 12.12 的例子:第 9 號與第 2 號在圖上左右相鄰, 但第 9 號跟第 2、8、5、7 號都是在同一個高度(約 1.8)才合併的, 所以它跟這四個的相似度完全一樣。
原因是每一次合併都可以把左右兩支對調而不改變樹的意義, n 個葉子有 $2^{n-1}$ 種等價的畫法。水平位置只是其中一種排法而已。

剩下的問題是:兩之間的相異度怎麼定?這叫做 連結方式(linkage),四種常見的定義在下面那張表。 換 linkage,樹的形狀會整個變——這是這一節最重要的實驗。

拖動橘色切線改變群數,換 select 看四種 linkage 的差別。
這一刀切出什麼
linkagecomplete
切在高度
切出幾群
最高的合併
「一次只黏一顆」的合併次數
怎麼玩
拖動橘色虛線(或用滑桿)上下移動切線,左邊的散佈圖會同步上色。往上切群數變少、往下切變多。
重點在那個 select:把 linkage 換成 single,看樹的形狀怎麼垮掉。
single linkage 的鏈狀效應 圖 12.14
single 取兩群之間最小的距離,所以只要有一個點靠近某個大群,整群就被拉過去。結果是一個很大的群不斷把單一觀測值一顆一顆黏上去(trailing cluster),切下去往往得到「一大群 + 幾個孤兒」。右側那個「一次只黏一顆」的次數就是在量這件事。
centroid 的反轉
把 linkage 換成 centroid,注意有些合併會出現反轉(inversion):兩群合併的高度比它們各自的高度還低,線段變成往上長。這種樹很難解讀,所以統計上偏好 complete 與 average。
Linkage群間相異度的定義樹的形狀評語
Complete兩群之間最大的那個距離平衡、群大小相近最常用;對離群值不算敏感
Average所有跨群配對距離的平均平衡最常用;統計上性質較好
Single兩群之間最小的那個距離鏈狀、拖尾容易產生一大群 + 一堆孤兒,少用
Centroid兩群形心之間的距離可能出現反轉基因體學常用,但反轉讓樹難以解讀

相異度也要選:歐氏距離還是相關係數?

前面一直用歐氏距離。但有時候你在意的是輪廓的形狀而不是高低: 兩位顧客一個買很多、一個買很少,但買的品項比例一致—— 歐氏距離很大,相關係數距離($1 - r_{ii'}$)很小。 ISLP 圖 12.15 就是這個對比。哪個對,取決於你的科學問題,沒有預設答案。

講義完整實作:AgglomerativeClusteringcut_tree

講義 12 · 建樹、畫樹、切樹
HClust = AgglomerativeClustering hc_comp = HClust(distance_threshold=0, n_clusters=None, linkage='complete') hc_comp.fit(X) cargs = {'color_threshold':-np.inf, 'above_threshold_color':'black'} linkage_comp = compute_linkage(hc_comp) fig, ax = plt.subplots(1, 1, figsize=(8, 8)) dendrogram(linkage_comp, ax=ax, **cargs); cut_tree(linkage_comp, n_clusters=4).T
預期輸出(儲存格 127)
array([[0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 2, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 2,
        0, 2, 2, 3, 2, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3, 3,
        3, 3, 3, 3, 3, 3]])

distance_threshold=0n_clusters=None 是「把整棵樹算完、先不要切」的寫法。
scikit-learn 不直接給 scipy 畫圖要的 linkage matrix,所以要用 ISLP.cluster.compute_linkage() 轉一次。color_threshold=-np.inf 是關掉 dendrogram() 預設的自動上色(預設會暗示一個切法,容易誤導)。
cut_tree(..., n_clusters=4) 回傳每一筆資料的群編號。也可以給 height=5 用高度切——本頁那條橘色虛線做的就是這件事。

來源:Ch12-unsup-lab-zh.ipynb · 儲存格 117、119、123、127
QUIZ · 讀樹狀圖

在一棵樹狀圖上,第 3 號與第 7 號葉子左右緊鄰,但它們所在的分支要到高度 8 才合併;第 3 號與第 20 號隔了很遠,卻在高度 2 就合併了。誰跟第 3 號比較相似?

(A) 第 20 號,因為相似度看的是「第一次合併的高度」,2 比 8 低
(B) 第 7 號,因為在樹狀圖上相鄰代表被歸在同一個小群
(C) 看不出來,樹狀圖只能看群數,不能比較個別觀測值
PART 09 · 分群的實務問題

要不要標準化、離群值怎麼辦、結果穩不穩 ISLP §12.4.3講義 12 · p.91–98

演算法都很乾淨,麻煩全在做決定的地方。ISLP §12.4.3 把它們列成一張清單, 每一項都會實質改變結果:

下面這個元件是課本圖 12.16 的可玩版本:一家網路商店只賣兩種東西——襪子與電腦。 八位顧客的購買紀錄一樣,只是換一種尺度,K = 2 的分群就換一組答案

換一種尺度,同樣八位顧客的 K = 2 分群結果就變了。
K = 2 的結果
目前的尺度原始次數
第 1 群
第 2 群
分群其實由誰決定
群內平方和
三種尺度在做什麼 圖 12.16
原始次數:襪子 0–11 雙、電腦 0–1 台。襪子的變異大得多,距離幾乎只由襪子決定,電腦等於沒參與。
標準化:兩個變數都變成變異數 1,電腦終於有影響力——分群變成「有買電腦」與「沒買電腦」。
花費金額:電腦一台 1400 元、襪子一雙 2 元,換算成金額之後反過來由電腦主宰
離群值那個 toggle
按下去會加入第 9 位顧客:買了 60 雙襪子、沒買電腦。K-means 一定要把每一點分進某一群,所以這一個點會硬生生把一整群拉過去,剩下八位全部被擠進另一群。
課本的建議是改用混合模型(mixture model,K-means 的「軟」版本),或者先把明顯的離群值挑出來單獨處理。
課本第 5 題就是這一題 第 5 題
ISLP 第 12.6 節第 5 題:「用圖 12.16 的三種尺度各跑一次 K = 2,描述你預期看到什麼。」把上面的 select 切三次就是答案。

「分群結果對不對」有客觀標準嗎?

沒有。這不是敷衍,是這一類方法的本質限制。 任何時候把資料丟去分群,它都會給你群——即使資料是純雜訊。 真正想問的是「這些群在獨立的新資料上也會出現嗎」, 文獻上有給群一個 p 值的做法,但沒有共識(細節在 ESL)。

能做的是幾件比較樸素的事:

做法怎麼做在檢查什麼
換設定重跑換 linkage、換距離、換 K、標準化與否哪些結構每次都出現(那些比較可信)
抽子樣本重跑隨機丟掉 10–20% 的資料再分群一次分群對擾動穩不穩(通常不太穩)
對照外部標籤有領域標籤時用 crosstab 或 ARI 比對分群有沒有抓到已知的結構(這是事後檢查,不是調參依據)
看得出解釋嗎每一群的變數平均長什麼樣,能不能講成一句話群有沒有實質意義,還是只是切開了連續的雲

講義完整實作:K-means 與階層式分群給的答案不一樣

講義 12 · NCI60 上兩種分群的交叉表
NCI60 = load_data('NCI60') nci_labs = NCI60['labels'] nci_data = NCI60['data'] nci_kmeans = KMeans(n_clusters=4, random_state=0, n_init=20).fit(nci_scaled) pd.crosstab(pd.Series(comp_cut, name='HClust'), pd.Series(nci_kmeans.labels_, name='K-means'))
預期輸出(儲存格 176)
K-means  0   1   2  3
HClust               
0        1  20  10  9
1        0   7   0  0
2        8   0   0  0
3        0   0   9  0

同一份 NCI60(64 個細胞株 × 6830 個基因)、同樣切 4 群,兩種方法的結果只是「略有不同」而不是相同:K-means 的第 3 群等於階層式的第 2 群,但 K-means 的第 0 群混了階層式第 0 群的一部分加上整個第 1 群。
先看群編號是任意的(所以要用 crosstab 而不是直接比標籤)。lab 儲存格 172 另外把階層式的 4 群對上真實癌症類型:所有白血病落在同一群,但乳癌散在三群——分群抓到了一部分結構,不是全部。

來源:Ch12-unsup-lab-zh.ipynb · 儲存格 152、172、176
觀念釐清
Q:分群結果「對不對」要怎麼判斷?沒有 y 的時候有沒有客觀標準?

沒有一個像測試誤差那樣的單一數字。原因很直接:測試誤差需要正確答案,而分群問題裡「正確的群」並不存在(如果存在,那就是分類問題了)。

常見的內部指標(silhouette、Calinski–Harabasz、gap statistic)能算,但它們量的是幾何上的緊密與分離,不是「這些群是不是真的」。一份純雜訊的資料照樣可以有不錯的 silhouette;反過來,兩個真實但形狀狹長交錯的子群,silhouette 會很難看。所以這些指標可以用來在同一個方法內部比較 K,不能用來宣告「分群成功」。

比較誠實的做法是三件事併用:(1)穩定性——換設定、抽子樣本重跑,看哪些群每次都在;(2)可解釋性——每一群能不能用領域語言講成一句話;(3)外部驗證——在獨立的新資料上重做一次,或對上事後才知道的標籤。ISLP 的結語值得抄下來:分群結果不該當成資料的絕對真相,而是形成科學假設的起點

Q:PCA 與分群都在「找結構」,差在哪?

差在產出的東西是連續還是離散。PCA 給每一筆資料一組新的連續座標(得分),資料在低維空間裡還是一片雲;分群給每一筆資料一個離散的群編號,雲被切成幾塊。

對應的假設也不同。PCA 假設「大部分變異集中在少數幾個方向」,它不假設資料裡有子群——如果真的只有一片橢圓形的雲,PCA 照樣給你很有用的答案。分群則假設「資料由幾個同質的子群組成」,如果實際上是連續漸變的,切出來的界線就是人造的。

實務上兩者常常串起來用,而且順序有講究:先 PCA 再分群是很常見的做法(lab 儲存格 178 就對 NCI60 的前五個得分向量做階層式分群),理由是前幾個主成分可以看成資料的低雜訊版本。反過來也有用:分群完之後,用前兩個主成分的散佈圖把群畫出來,因為 p > 2 的時候你沒別的辦法看。

QUIZ · 分群的實務決策

資料裡有兩三個明顯的離群值(例如那位買 60 雙襪子的顧客)。對 K-means 與階層式分群,下面哪個處理方式最站得住腳?

(A) 兩種方法都會被離群值扭曲,因為它們強迫每一點都進某一群;該先辨識並單獨處理,或改用允許「不屬於任何群」的方法
(B) 階層式分群不受影響,因為離群值會自己形成一個單獨的分支
(C) 只要把資料標準化,離群值的影響就會被消掉
PART 10 · 流形學習與 t-SNE

非線性降維:t-SNE 好用但很會騙人 講義 12 · p.39–53ESL §14.9 · 進階ESL 進階

這一節是課堂沒細講的延伸(講義 12 · p.39–53),第一輪可以直接跳過去看 EX 練習。t-SNE 在論文裡到處都是,值得知道它會怎麼騙人。

PCA 是線性投影:它只能把資料壓到一個平面上。 可是很多高維資料的結構是彎的——想像一張捲起來的紙, 紙上相鄰的兩點在三維空間裡可能隔得很遠,而 PCA 只會把整捲紙壓扁,把不該相鄰的點壓在一起。 流形學習(manifold learning)就是假設資料落在一個低維的彎曲流形上, 想辦法把它攤平。

最有名的是 t-SNE(t-distributed stochastic neighbor embedding)。 它的想法完全不是「找方向」,而是「保住鄰居關係」:

  1. 在高維空間把「j 是 i 的鄰居」轉成機率 $p_{ij}$(距離近的機率大,用高斯核, 寬度由 perplexity 控制)。
  2. 在低維空間對同一對點也定一個機率 $q_{ij}$,但用重尾的 t 分佈
  3. 調整低維座標,讓兩個分佈的 KL 散度最小。

第 2 步為什麼要換成 t 分佈?因為高維空間「裝得下」的鄰居比低維多得多, 硬要用高斯核會讓所有點擠在一起(crowding problem); t 分佈的尾巴重,允許中距離的點被推得比較遠,圖才會散開。

圖表需要連網載入 Chart.js。此圖的重點:PCA 的線性投影把十個數字混在一起,t-SNE 則把它們分成清楚的團——但團的大小與團之間的距離都不能當真。
同一批 500 張手寫數字,換方法看嵌入結果怎麼變。
目前這張圖
方法PCA(線性投影)
點數
原始維度8 × 8 = 64
類別數10
怎麼比
同一批 500 張手寫數字(load_digits,8×8 灰階)用三種方法壓到 2 維,顏色是真實的數字標籤——標籤沒有參與計算,只用來上色。
切到 perplexity = 5 再切到 30,看同一份資料可以長得多不一樣。
t-SNE 的四個陷阱 講義 p.51–53
1. 座標沒有意義,軸也沒有單位,不要說「往右邊是什麼」。
2. 團的大小不可信——t-SNE 會把稀疏的團擴張、密的團壓縮。
3. 團之間的距離不可信,全域結構不保證被保留。
4. 換參數就換一張圖:perplexity、學習率、初始化、隨機種子都會變。所以要多跑幾組再下結論。
t-SNE 不是萬能,也不是 PCA 的替代品 t-SNE 幾乎只能用來「看」。 它沒有 transform()(新資料無法投影到既有的嵌入上, openTSNE 之類的套件才另外提供近似做法), 也不像 PCA 有負荷量可以解讀「這個方向由哪些變數組成」。
要當前處理放進 pipeline,UMAP 比較合適——它有 transform(), lab 儲存格 86–94 就示範了「先 UMAP 再分類」, 而且 SVC 的正確率從 0.62 拉到 0.98。但那已經是監督式的評估了, 能這樣調就是因為有 y 可以看。

講義完整實作:TSNE

講義 12 · digits 的 t-SNE
tsne = TSNE( n_components=2, perplexity=30, init="pca", learning_rate="auto", random_state=0, verbose=True ) embedding = tsne.fit_transform(X)
預期輸出
[t-SNE] Computing 91 nearest neighbors...
[t-SNE] Indexed 1797 samples in 0.001s...
[t-SNE] Computed neighbors for 1797 samples in 0.393s...
[t-SNE] Computed conditional probabilities for sample 1000 / 1797
[t-SNE] Computed conditional probabilities for sample 1797 / 1797
[t-SNE] Mean sigma: 11.585657
[t-SNE] KL divergence after 250 iterations with early exaggeration: 61.325920
[t-SNE] KL divergence after 1000 iterations: 0.753624

init="pca" 是重要的細節:用 PCA 的結果當初始位置,比隨機初始化穩定得多,也讓結果比較可重現(配上 random_state=0)。
輸出的兩個 KL 散度值得注意:早期誇張階段(early exaggeration)250 輪之後是 61.3,跑完 1000 輪降到 0.754KL 散度只能用來比較同一份資料的不同次執行,它不是「分得好不好」的分數。
lab 後面還示範了 openTSNE(更快)、UMAP(有 transform())與 PHATE(保留軌跡結構)。

來源:Ch12-unsup-lab-zh.ipynb · 儲存格 71、72、74、75
QUIZ · t-SNE 的讀法

一張 t-SNE 圖上,A 團與 B 團距離很遠,A 團看起來比 B 團大三倍。可以下什麼結論?

(A) 幾乎什麼都不能下:團的大小與團間距離都不是 t-SNE 保證保留的量
(B) A 群的樣本數大約是 B 群的三倍
(C) A 與 B 距離遠,代表它們在原始 64 維空間裡也離得很遠
EXERCISES · 練習

動手驗證:ISLP 第 12 章精選題 ISLP §12.6 習題

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

EXERCISE 1 · ISLP §12.6 第 1 題(b)

課本第 1 題要你先證明恆等式 12.18,再用它說明演算法 12.2 每一輪都讓目標函數 12.17 下降。這個論證的關鍵是什麼?

(A) 式 12.18 把「群內兩兩距離」換成「各點到群心的距離」,於是步驟 2(a) 取平均與步驟 2(b) 取最近,各自都在最小化那個和
(B) 因為每一輪都會有點換群,換群一定讓目標下降,所以會一直下降到 0
(C) 因為 K-means 的目標函數是凸的,梯度下降保證收斂到全域最小
EXERCISE 2 · ISLP §12.6 第 4 題(b)

single linkage 與 complete linkage 各做一棵樹。在 single 的樹上$\{{5\}}$ 與 $\{{6\}}$ 這兩群在某個高度合併;complete 的樹上它們也會合併。哪一棵的合併位置比較高?

(A) 一樣高,因為兩群都只有一個點,最大距離與最小距離都是 d(5,6)
(B) complete 比較高,因為 complete linkage 的高度總是大於或等於 single
(C) 資訊不足,要看資料才知道
EXERCISE 3 · ISLP §12.6 第 5 題

課本第 5 題:用圖 12.16 的三種尺度各跑一次 K = 2(襪子與電腦),分別預期看到什麼?

(A) 原始次數 → 由襪子決定;標準化 → 變成「有買電腦 / 沒買電腦」;花費金額 → 由電腦決定
(B) 三種尺度會給同樣的分群,因為 K-means 對線性變換是不變的
(C) 標準化之後電腦的影響會消失,因為 0/1 變數標準化後變異數變成 1 太小
EXERCISE 4 · ISLP §12.6 第 8 題

課本第 8 題要你在 USArrests 上用兩種方式算 PVE:(a) 讀 explained_variance_ratio_;(b) 拿 components_ 直接套式 12.10。提示裡特別警告了什麼?

(A) 兩邊必須用同一份資料:(a) 用標準化後的資料跑 PCA,(b) 就也得先標準化再套公式
(B) 警告 components_ 的符號可能跟公式的推導相反,要先把符號翻回來
(C) 警告要用 ddof=1 算變異數,否則兩邊差一個 n/(n−1) 的因子
REFERENCE · 總覽

非監督式學習速查表 ISLP Ch.12

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

PCA 與分群:同樣在化簡,問的問題不同

PCAK-means階層式分群
產出連續的低維座標(得分)K 個離散群標籤一棵樹(1 到 n 群都在裡面)
要先決定M(留幾個主成分)K相異度、linkage、切在哪
有隨機性嗎沒有(只差符號)(初始指派)沒有
結果唯一嗎唯一,最多差符號局部極小,換初值會變唯一(但畫法有 2ⁿ⁻¹ 種)
要標準化嗎幾乎一定要幾乎一定要幾乎一定要
對離群值會被拉走(變異最大化)強迫入群,會扭曲常自己掛高處,吃掉群額度
常見用途視覺化、去雜訊、補值、當特徵市場區隔、量化子群探索階層結構、基因體學

四種 linkage

Linkage群間相異度形狀反轉?建議
Complete跨群距離的最大平衡不會預設首選
Average跨群距離的平均平衡不會預設首選
Single跨群距離的最小鏈狀拖尾不會少用,除非真的要找細長結構
Centroid兩群形心的距離不定基因體學常用,讀圖要小心

公式速查

名稱式子備註
第一主成分$\max \frac1n\sum_i(\sum_j \phi_{j1}x_{ij})^2$ s.t. $\sum_j\phi_{j1}^2=1$式 12.3
得分$z_{im} = \sum_{j=1}^{p} \phi_{jm} x_{ij}$式 12.2、12.4
最佳低維近似$\min_{A,B}\sum_{j}\sum_i (x_{ij}-\sum_m a_{im}b_{jm})^2$式 12.6,解就是主成分
PVE$\dfrac{\sum_i z_{im}^2}{\sum_j\sum_i x_{ij}^2} = 1-\dfrac{\mathrm{RSS}}{\mathrm{TSS}}$式 12.10,加起來是 1
變異分解總變異 = 前 M 個 PC 的變異 + M 維近似的 MSE式 12.11
矩陣補全$\min_{A,B}\sum_{(i,j)\in\mathcal O}(x_{ij}-\sum_m a_{im}b_{jm})^2$式 12.12,只在觀測格上算
K-means 目標$\min\sum_k \frac{1}{|C_k|}\sum_{i,i'\in C_k}\sum_j (x_{ij}-x_{i'j})^2$式 12.17
關鍵恆等式$\frac{1}{|C_k|}\sum_{i,i'\in C_k}\sum_j (x_{ij}-x_{i'j})^2 = 2\sum_{i\in C_k}\sum_j (x_{ij}-\bar x_{kj})^2$式 12.18,演算法 12.2 的根據

USArrests 的實測數字

主成分PC1PC2PC3PC4
負荷量 Murder0.536−0.418−0.341−0.649
負荷量 Assault0.583−0.188−0.2680.743
負荷量 UrbanPop0.2780.873−0.378−0.134
負荷量 Rape0.5430.1670.818−0.089
得分的變異數2.53091.01000.36380.1770
PVE62.0%24.7%8.9%4.3%
累積 PVE62.0%86.8%95.7%100%

負荷量與 lab 儲存格 29 的 components_ 逐位相同、PVE 與儲存格 39 的 explained_variance_ratio_ 相同。四個變數的原始變異數是 18.97 / 6945.17 / 209.52 / 87.73(儲存格 17)——所以標準化不是選項而是必要。

三個一定要記住的觀念 1. PCA 的兩種解釋是同一件事。 「變異最大的方向」=「離資料最近的低維平面」,式 12.11 就是它們的橋; PVE 因此也可以讀成近似的 R²。
2. 尺度會決定答案,符號不會。不標準化,PC1 就退化成變異數最大的那個變數; 符號整組翻掉則什麼結論都不變(前提是得分與負荷量一起翻)。
3. 分群一定會給你群,但那不代表群是真的。 K-means 只保證局部極小(要設 n_init)、樹狀圖只能看高度不能看左右、 結果對標準化與 linkage 都很敏感。換設定多跑幾次,看什麼結構每次都出現。

本頁「預期輸出」逐字取自課程 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 · 關鍵詞彙卡

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

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