SVD:轉一下、拉一下、再轉一下
這一關只講一件事:不管那台搬點機長得多奇怪,它做的事都只是「先轉一轉、再沿著兩條軸拉一拉、最後轉回來」。 三個動作,就這樣。看懂之後,連 04 關那把刀啃不動的長方形資料表都拆得開。
這一節開始會一直出現 V、Σ、U 三個字母(還有 V 右上角的小 T)。 它們只是三個動作的代號,不是新的數學。
V 唸「vee」、Σ 唸「sigma」、U 唸「you」; V 右上角的小 T 唸「transpose」,中文叫轉置(把欄改寫成列)。 先不用管細節 —— 接下來一節講一個動作,字母就是那個動作的名字。
⓪ 第 1 節:三個動作的第一個「轉」—— Vᵀ 到底在乘什麼
這一節不用任何先備知識。先看 SVD 的公式長怎樣、三個動作各是什麼, 再從「一個點被搬走」一路走到 Vᵀ × X。六步,每步一句話配一張會動的圖。
SVD 說的是一件事:任何一台「搬點機」A,都可以拆成「先轉一轉 → 沿兩根軸拉一拉 → 再轉回來」三步。 寫成公式就是這一行。
A 是要拆的那台機器;右邊三個是拆出來的三個動作。
出發:一個半徑 1 的圓,加上圓上的一個點。 灰虛線圓之後一直留著當比例尺,讓你看得出東西被拉大了還是縮小了。
① Vᵀ 轉(唸「V transpose」)—— 把座標軸轉到主軸上(主軸是什麼,STEP 3 講)。 圓還是圓:只換方向,一點都沒變大變小。 這一節 (1/3) 細講
② Σ 拉(唸「sigma」,就是希臘字母的 S)—— 沿兩根新軸各拉一個倍數,這台 A 是一根拉 3 倍、一根拉 1 倍(1 倍=不動)。 三個動作裡只有這一步會改變大小。 (2/3) 細講 →
③ U 轉回(唸「you」)—— 把拉好的形狀轉到最後該在的位置,這時候才等於「直接用 A 搬一次」。 形狀一樣沒變,只是換方向擺。 (3/3) 細講 →
同一個圓、同一個點,由左往右依序做完三個動作 —— 最右邊那格就等於「直接用 A 搬一次」。 每一格的灰虛線圓都是原本的圓,拿來比大小用。
原本的網格:橫線豎線整整齊齊,笑臉是正的。
先轉 45°、再橫向拉 3 倍(= ① Vᵀ + ② Σ):網格變成菱形,笑臉被拉扁。
直接用 A 搬一次(= ① Vᵀ + ② Σ + ③ U):網格變成斜的,笑臉斜著拉長。
這一張圖看的是整個空間被搬動:連網格線都在動,不是只有一個點。 動畫開始時,三格長得一模一樣(都是原本的網格):左格不動、留著當原本; 中格做完 ① Vᵀ(轉 45°)+ ② Σ(橫向拉 3 倍); 右格再多做 ③ U(轉回),等於直接用 A 搬一次。 一句話:左=原本的圖、中間=轉好拉好的圖、右=被 A 搬完的圖。
-
STEP 1
先講兩個字母:X 是一個點,A 是「對這個點做的事」
- X=平面上一個點,也可以看成從原點指出去的一根箭頭;它就是兩個數字,這裡取 X = (2, 1)。 (資料表的一列也是這種一串數字,只是不只兩個。)
- A=一台搬點機:一條固定規則,說「任何點該搬到哪」。規則全寫在四個數字裡。 (這種數字表叫矩陣;橫的一排叫列、直的一排叫欄。)
- A × X=把 X 搬走的結果。算法只有一句:一列配一個點,對位相乘再相加。 (下面圖上寫成「第一列 · X」——「·」和「×」在這裡是同一個意思:乘。)
- 算一次就懂:(2, 1) 被搬到 (5, 4)。 (原點 (0, 0) 永遠不動,乘出來還是 (0, 0)。)
- 下面那張表怎麼看:X 行文寫成 (2, 1) 是橫著寫省位置,真的拿去乘的時候要立成直的一欄(2 在上、1 在下),才跟 A 的「列」對得上位。
A = 2112 X = 21左:A 的第一列配上 X 得到 5、第二列配上 X 得到 4。 右:同一件事在平面上 —— 青箭頭是 X, 綠點被搬到 (5, 4)。
-
STEP 2
想看清楚 A 在幹嘛?丟一個圓進去當試紙
一個點只給你一個答案。圓上有各個方向的點,一次全丟進去,就看得出 A 對「每個方向」各做了什麼。
出來永遠是橢圓 —— 某個方向被拉長、另一個方向被壓扁。 (橢圓是我們用來觀察 A 的工具,不是 A 的一部分。)
橢圓好用的地方:它的長軸一眼就指出 A 最用力的方向。
灰虛線=丟進去的圓(試紙);青色=出來的橢圓。 圓上的 (1, 0) 落到橢圓上的 (2, 1)。
-
STEP 3
橢圓被拉最長的那個方向,就叫主軸 v₁
「主」的意思是這台 A 最用力的方向;v 是 vector(向量/箭頭)的縮寫,v₁ 唸「v one」。
垂直於它的那根叫 v₂,是拉最少的方向。這台 A 的 v₁ 在 45°。
紫線是長軸,方向就是 v₁(45°); 桃箭頭是 v₂,一定垂直於它。
-
STEP 4
V 就是「兩根主軸排成一張表」
- 兩根主軸各是兩個數字:v₁ = (0.71, 0.71)、v₂ = (−0.71, 0.71)。 (v₂ 為什麼往左上、帶負號?跟 v₁ 垂直的方向有兩個(左上、右下),習慣選逆時針轉 90° 的那個 —— 就是左上,所以第一個數字是負的。)
- 把它們直的寫進一張 2×2 的表,一根佔一欄 —— 這張表就叫 V。
- 欄=直的一排、列=橫的一排,這兩個字後面一直會用到。
- 0.71 哪來的?v₁ 在 45°,而 45° 就是 y = x 那條線,線上的點長這樣:(1, 1)。當軸用的方向規定長度要是 1 —— 軸只負責指方向,長度統一成 1,讀出來的數字才是純座標。(1, 1) 的長度是 √(1² + 1²) = √2 ≈ 1.41(這就是畢氏定理:兩股各平方相加再開根號),兩個數字各除以它就變成 0.71。
紫箭頭 v₁ 的兩個數字寫進第一欄、桃箭頭 v₂ 寫進第二欄。 灰虛線圓=半徑 1,提醒你這兩根箭頭的長度都剛好是 1。
-
STEP 5
把 V「翻一下」寫成 Vᵀ,才能拿去乘點
從整條公式看這一步A = U · Σ · VᵀVᵀ 是三個動作的第一個 —— 離 X 最近、第一個碰到點。這一節把「它在乘什麼」講完。
- Vᵀ 唸「V transpose」,中文叫轉置:同一組數字,把「欄」改寫成「列」,沒有新東西。
- 為什麼要翻?因為乘法是一列配一個點(STEP 1)。要問「這個點在 v₁ 上有多少」,v₁ 就得躺成一列。
- 翻完的兩列就是兩根新軸:c₁(第一列=v₁)、c₂(第二列=v₂)。 (c₁ 就是躺下來的 v₁:同一根軸、同樣兩個數字,換個名字只是提醒你「這是拿來乘的那一列」。)
- 所以座標變換就寫成:新座標 = Vᵀ × 舊座標。
Vᵀ = 0.710.71−0.710.71左:V 的兩欄(直的)翻成 Vᵀ 的兩列(橫的),數字一個都沒變。 右:Vᵀ 做的事 —— 兩根軸一起轉 45°,c₁ 停在橢圓的長軸上; 灰虛線是畫面本身的橫直方向,它不會動。 這張是「軸轉、點不動」;下一步 STEP 6 的右圖反過來畫成「點轉、軸不動」—— 兩張圖是同一件事的兩種畫法。
-
STEP 6 · 這一節的重點
Vᵀ × X:跟 STEP 1 同一種乘法,只是把 A 換成 Vᵀ
- 規則一模一樣:一列配一個點,對位相乘再相加。
- 第一個新座標 = 第一列 c₁ · 點 —— 在問「這個點在 v₁ 方向上有多少?」
- 第二個新座標 = 第二列 c₂ · 點 —— 同一句話問 v₂ 一次。
- 差別只在:A 會把點搬走,Vᵀ 只換讀數、不改長度(2.24 進、2.24 出)。 (2.24 是這根箭頭的長度,一樣用畢氏定理算:√(2² + 1²) = √5 ≈ 2.24。)
新座標 = (第一列 · 點, 第二列 · 點) x′ = 0.71×2 + 0.71×1 ≈ 2.12 · y′ = −0.71×2 + 0.71×1 = −0.71
x′、y′ 那一撇代表新座標(舊的就寫 x、y)。0.71 是 1/√2 四捨五入來的,所以第一行寫 ≈ —— 用精確值算是 3/√2 ≈ 2.12。左:兩列分別跟 (2, 1) 逐項乘加,亮出 2.12 跟 −0.71 (0.71 是四捨五入過的,所以第一個寫 ≈ 2.12)。 右:同一件事在平面上 —— 點往右轉 45°、新軸擺正不動,轉完就在 c₁ 軸上讀到 2.12、在 c₂ 軸上讀到 −0.71(跟著點一起轉的那兩條灰線是舊軸,留著讓你對照)。 把軸往左轉 45°(STEP 5 那張),跟把點往右轉 45°(這張),讀出來的數字一模一樣 —— 這張圖選了轉點,因為新軸擺正比較好讀。
Vᵀ × X 就是「先把座標軸轉到主軸上」—— SVD 的第一步。
下一節 (2/3) 就把 Σ 做完:轉好之後,沿著這兩根新軸各拉一個倍數(這台 A 是 3 倍跟 1 倍)。 Σ 裡面那兩個倍數,就寫成小寫的 σ₁、σ₂(唸「sigma one、sigma two」):σ₁ = 第一根軸 c₁ 拉幾倍、σ₂ = 第二根軸 c₂ 拉幾倍, 所以這台 A 是 σ₁ = 3、σ₂ = 1。 (3 跟 1 就是 STEP 2 那個橢圓的長、短半徑 —— 半徑 1 的圓被拉成長 3、短 1。)
接下來兩節把剩下兩個動作補完: ⓪ (2/3) Σ:沿兩根新軸各拉一個倍數, 然後 ⓪ (3/3) U:拉完轉回來,三個接起來就是 A。 (想先看整關的地圖,也可以直接往下走 ① 這關在解什麼問題; σ 跟 U 的進階版在 ④。)
預告:轉完之後,圓沿著 c₁ 被拉成 3 倍、沿 c₂ 不動。 圖右下的 σ₁ = 3 就讀成「第一根軸拉 3 倍」、σ₂ = 1 讀成「第二根軸拉 1 倍,也就是沒拉」。
⓪ 第 2 節:三個動作的第二個「拉」—— Σ 沿兩根新軸,各拉一個倍數
上一節把座標軸轉到主軸上了,圖形本身一點都還沒變大變小。 這一節做第二個動作:在新軸上把圖拉開。五步,每步一句話配一張會動的圖。
Σ 是三個動作的第二個 —— 中間這一步,把形狀拉開。
Σ 就是「把轉好的形狀,沿兩根新軸各拉一個倍數」 —— 三個動作裡只有這一步會改變大小,另外兩個都只是轉方向。
-
STEP 1
Σ 做的事:沿 c₁ 拉 3 倍、沿 c₂ 拉 1 倍
- 畫面上這兩根軸就是上一節轉好的 c₁、c₂ (c₁ 是躺下來的主軸 v₁,上一節 STEP 5 講過)。
- 丟進去的還是那個半徑 1 的圓(⓪ 的試紙)。
- 拉法很死板:只沿著這兩根軸拉,不歪不斜,所以圓被拉成一個「正的」橢圓。
- 1 倍就是不動 —— c₂ 那個方向乘 1,等於什麼都沒做。
灰虛線=原本的圓;青色=拉完的橢圓。 右邊那顆點從 (1, 0) 被拉到 (3, 0);上面那顆點在 (0, 1),從頭到尾沒動。
-
STEP 2
那兩個倍數有名字:σ₁、σ₂(唸「sigma one、sigma two」)
- 大寫 Σ 是那張表,小寫 σ 是表裡面的數字。 (同一個希臘字母的大小寫,就像 A 和 a。)
- σ₁ = 第一根軸 c₁ 拉幾倍、σ₂ = 第二根軸 c₂ 拉幾倍。這台 A 是 σ₁ = 3、σ₂ = 1。
- 正式名字叫奇異值。(「奇異」只是 singular 的直譯,跟「很奇怪」沒關係。)
- 兩條規矩:不會是負的(負號可以丟給旁邊的轉,所以拉的部分一律取正)、 而且大的排前面(σ₁ ≥ σ₂)。
紫條是 σ₁(c₁ 拉 3 倍)、桃條是 σ₂(c₂ 拉 1 倍)。 長條多長就是拉幾倍;σ₂ 只有一格,代表「乘 1 = 沒拉」。
-
STEP 3
Σ 寫成表:只有斜線上有數字,其他都是 0
- 把 σ₁ 放左上、σ₂ 放右下,其他兩格填 0。
- 那條「左上到右下」的斜線叫對角線;只有對角線有數字的表,叫對角矩陣。
- 為什麼其他格是 0?因為兩根軸各拉各的、互不干擾 —— c₂ 的讀數不會跑去影響 c₁ 的結果。
- (0 在這裡的意思是「這一格完全不參與」,不是「這裡沒東西」。)
Σ = 3001左上那格是 σ₁ = 3、右下那格是 σ₂ = 1, 斜線畫出來的就是對角線。另外兩個 0 是「這一格不參與」的意思。
-
STEP 4 · 這一節的重點
Σ × 新座標:還是「一列配一個點」那一招
- 上一節算出來的新座標是 (2.12, −0.71),直接拿來乘。
- 第一列 (3, 0) 配上點:3×2.12 + 0×(−0.71) —— 0 那一項直接消失。
- 第二列 (0, 1) 配上點:0×2.12 + 1×(−0.71) —— 只剩下原本那個數字。
- 所以乘一個對角矩陣,就是「每個座標各乘自己的倍數」,沒有別的。
拉完 = (σ₁ × 第一個座標, σ₂ × 第二個座標) 3 × 2.12 ≈ 6.36 · 1 × (−0.71) = −0.71
一樣提醒:2.12 是四捨五入過的,用精確值算是 9/√2 ≈ 6.36。跟 ⓪ STEP 6 完全同一種乘法,只是矩陣換成 Σ。 因為 Σ 有兩個 0,每一列其實只剩一項活著 —— 第一個座標乘 3、第二個座標乘 1,就這樣。
-
STEP 5
回頭看 ⓪ 那顆橢圓:長短半徑就是 σ₁ 和 σ₂
- ⓪ STEP 2 把圓當試紙丟進 A,出來一顆斜的橢圓。
- 現在拉出來的是一顆正的橢圓:長半徑 3、短半徑 1。
- 這兩顆是同一顆橢圓 —— 只差最後那一轉(下一節的 U 做的事)。
- 所以「橢圓被拉多長」這件事,答案一直都寫在 σ 裡: 長半徑 = σ₁、短半徑 = σ₂。
實線是這一節拉出來的「正橢圓」; 淡淡那顆斜的是 ⓪ STEP 2 直接用 A 搬出來的橢圓。 兩顆一樣胖一樣長,只差一個角度 —— 那個角度就是下一節 U 要補的。
Σ 就是「沿兩根新軸各拉一個倍數」,那兩個倍數叫 σ₁、σ₂。 它是三個動作裡唯一會改變大小的一步,寫成表就是「只有對角線有數字」。
現在圖已經被拉開了,但它還躺在「新軸」的世界裡、還是正的。 下一節 (3/3) 用 U 把它轉到最後的位置,並且把三個動作接起來對帳一次 → ⓪ (3/3) U。
⓪ 第 3 節:三個動作的第三個「轉回來」—— U 拉完再轉回來,三個動作接起來就是 A
前兩節轉完也拉完了,但東西還擺在半路上。 這一節做最後一個動作,然後把三個動作接起來對帳一次 —— 看它是不是真的等於「直接用 A 搬一次」。
U 是三個動作的最後一個 —— 把拉好的形狀轉到最終位置。
U 就是「把拉好的形狀,轉到最後該在的位置」。 跟 Vᵀ 一樣只轉方向、不改大小 —— 但它不是把 Vᵀ 那一轉抵銷掉, 因為中間已經拉過了。
-
STEP 1
現在的處境:形狀對了,方向還差一個角度
- 上一節拉出來的橢圓是正的:長軸躺在 c₁ 上。
- 但 ⓪ STEP 2 直接用 A 搬出來的橢圓是斜的:長軸指在 45° 那個方向。
- 兩顆一樣長、一樣胖,只差一個角度 —— 差的就是最後這一轉。
- 所以 U 要做的事只有一件:把整個形狀轉到那個角度去。
實線=上一節拉完的正橢圓;淡的那顆=⓪ 直接用 A 搬出來的斜橢圓。 兩顆的長短半徑完全一樣(3 和 1),差的只有角度。 (灰軸是兩顆共用的參考線:實線那顆的長軸躺在上一節那根 c₁ 上,淡的那顆是照原本的 x/y 軸畫的。 U 這一轉,就是把前者搬到後者。)
-
STEP 2
U 做的事:整個轉過去,剛好蓋住
- 把正橢圓整個轉 45°,它就跟 A 搬出來的那顆完全重合。
- 形狀一點都沒變 —— 轉不會把長的變短、也不會把胖的變瘦。
- 轉完之後,橢圓的長軸指向哪,就叫 u₁ 那個方向。 (u 是 vector 的另一組名字,跟 v 一樣是「一根箭頭」。)
- 到這裡三個動作全部做完,圖形就停在 A 該把它放的位置。
青色實線那顆整個轉 45°,轉完剛好蓋住淡色那顆。 青點跟著一起走,證明是「整張圖一起轉」,不是重畫一顆。 轉完長軸指的方向就是 u₁。 (這個 45° 是照原本的 x/y 軸量的 —— u₁ 一直都是用原本那套軸講的方向。)
-
STEP 3
「轉出去又轉回來」不是白忙一場嗎?因為中間拉過了
- 沒有中間那一拉:轉出去再轉回來,圖形一模一樣,等於什麼都沒發生 —— 那才叫白轉。
- 有中間那一拉:轉出去是為了「把要拉的方向擺正」,拉完再轉回來,圖形真的變形了。
- 順序不能換:先擺正、再拉、再擺回去。先拉再轉,拉的方向就錯了。
- 還有一件事要講清楚:U 跟 Vᵀ 不保證是同一個轉法。 這台 A 剛好是對稱矩陣(沿「左上 → 右下」那條對角線翻過來一模一樣: 右上角和左下角都是 1;⑧ 那裡會再用到這個詞), U 才剛好把 Vᵀ 的角度轉回去;一般的 A,兩邊轉的角度完全可以不一樣。
左邊沒有 Σ:先轉 45°、再轉回 45°,圓還是那個圓、青點也回到原位 —— 白轉。 右邊前半段一模一樣(也先轉 45°;圓轉了還是圓,所以只有青點看得出來轉過了), 只是中間多插一次「沿橫向拉 3 倍」,轉回來就變成一顆斜橢圓。 兩格唯一的差別就是中間那一拉。
-
STEP 4
U 寫成表:一根新方向佔一欄,跟 V 同一個規矩
- u₁ = 轉完之後長軸指的方向,這台 A 是 45°,也就是 (0.71, 0.71)。
- u₂ 垂直於它,是 (−0.71, 0.71)。(一樣選逆時針那個方向。)
- 把兩根直的寫進一張 2×2 的表,一根佔一欄 —— 這張表就叫 U。
- 這台 A 的 U 跟 V 剛好長得一模一樣,因為它是對稱矩陣 (沿「左上 → 右下」那條對角線翻過來一樣);一般的 A 不會這樣,U 和 V 是兩張不同的表。
U = 0.71−0.710.710.71淡色橢圓是轉完的結果,u₁ 就沿著它的長軸。 跟 STEP 4 的 V 一樣:一根方向寫成一欄,灰虛線圓提醒你兩根箭頭長度都是 1。 (⓪ STEP 1 那張表也用了這兩個顏色,但那裡標的是 A 的兩列。 顏色在每張圖裡只表示「第一個 / 第二個」,不代表跨圖是同一個東西。)
-
STEP 5
U 怎麼拿去乘:它不用翻,因為它做的是「組回來」
- 先擋掉一個一定會卡住的問題:V 要翻成 Vᵀ 才能乘,U 為什麼不用翻成 Uᵀ?
- Vᵀ 在問問題:「這個點在 v₁ 上有多少?」問一根方向,那根方向就得躺成一列 —— 所以 V 一定要翻(⓪ STEP 5、STEP 6 講過)。
- U 在組東西:把「沿 u₁ 走 6.36、沿 u₂ 走 −0.71」這兩段接回一個點。 u₁、u₂ 本來就直立擺在 U 的欄裡,直接拿來當方向剛剛好,不用翻。
- 同一件事兩種讀法,算出來一樣:照欄讀=兩根方向各按倍數走再相加; 照列讀=一列配一個點。下面的圖用「照列」那一種,跟前面每一次乘法同一招。
- 負號一定要原樣寫進去:U 的第一列是 (0.71, −0.71),點的第二個數字也是 −0.71, 兩個負號相乘變成加 —— 這是最容易算錯的一格。
- 「列」跟「欄」不要搞混:U 的第一列 (0.71, −0.71) 不是 u₁ —— u₁ 是 U 的第一欄 (0.71, 0.71)。(拿去乘的是「列」,方向本身是「欄」; 同一張表兩種讀法,STEP 4 那張圖標的是欄。)
第一列 (0.71, −0.71) · (6.36, −0.71) = 0.71×6.36 + (−0.71)×(−0.71) = 4.516 + 0.504 = 5.020 ≈ 5.02
第二列 (0.71, 0.71) · (6.36, −0.71) = 0.71×6.36 + 0.71×(−0.71) = 4.516 − 0.504 = 4.012 ≈ 4.01 中間那兩個數刻意不四捨五入,你才跟得上:0.71×6.36 = 4.5156 → 4.516、0.71×0.71 = 0.5041 → 0.504。 (如果中間只寫兩位,第二列會變成 4.52 − 0.50 = 4.02,跟答案 4.01 差一格,那是四捨五入的錯覺不是你算錯。)
照欄讀是同一個答案:6.36 × u₁ + (−0.71) × u₂ = 6.36×(0.71, 0.71) + (−0.71)×(−0.71, 0.71) = (4.516, 4.516) + (0.504, −0.504) = (5.020, 4.012)。
0.71 和 6.36 本身也是四捨五入過的;用精確值(1/√2、9/√2)算,剛好就是 5 跟 4。跟 ⓪ STEP 6、(2/3) STEP 4 完全同一種乘法,只是矩陣換成 U。 第一列那兩個 −0.71 相乘是正的 0.504,所以第一列是「4.516 加 0.504」;第二列才是「4.516 減 0.504」。 (中間值留三位小數是故意的 —— 只寫兩位的話第二列會算成 4.52 − 0.50 = 4.02, 跟答案 4.01 差一格,那是四捨五入的錯覺,不是你算錯。 另外 紫/桃在這張圖裡標的是「第一列 / 第二列」, 跟 STEP 4 那張標「u₁ 欄 / u₂ 欄」的顏色不是同一件事。)
-
STEP 6 · 這三節的高潮
三個動作接起來,真的等於 A
- 拿同一個點 X = (2, 1),照順序做三次乘法。
- Vᵀ 轉:(2, 1) → (2.12, −0.71) (⓪ STEP 6 算過)
- Σ 拉:(2.12, −0.71) → (6.36, −0.71) ((2/3) STEP 4 算過)
- U 轉回:(6.36, −0.71) → (5, 4) (上一步 STEP 5 一格一格拆給你看過:5.02 和 4.01,用精確值剛好是 5 跟 4。)
- 而 ⓪ STEP 1 直接算 A × X 就是 (5, 4) —— 一模一樣。 這就是 A = U · Σ · Vᵀ 在說的事。
同一個點被三個動作依序處理:轉 → 拉 → 轉回。 最後落在 (5, 4),跟 ⓪ STEP 1「直接用 A 搬一次」的答案完全一樣。
A = U · Σ · Vᵀ 現在每一個字母你都認識了:
- Vᵀ:把座標軸轉到主軸上(只轉方向)。
- Σ:沿兩根新軸各拉 σ₁、σ₂ 倍(唯一會改變大小的一步)。
- U:把拉好的形狀轉到最後的位置(只轉方向)。
接下來 ① 這關在解什麼問題 會告訴你「為什麼需要這個拆法」; ③ 讓你自己拉滑桿當那台機器; ④ 是把任何矩陣反過來拆開的完整版。
① 這關在解什麼問題
這一關只教一件事,而且結論現在就給你,後面才慢慢解釋為什麼:
拿任何一個矩陣,把它想成一台會把圖形弄變形的機器。 不管那台機器多奇怪,它做的事都可以拆成下面這三個動作,照順序做完:
把整張圖繞著原點轉一個角度。形狀完全沒變,只是換了個方向擺。
數學家寫成 Vᵀ · 白話:「轉」的那個矩陣橫向拉成幾倍、直向拉成幾倍,兩個方向各拉各的、互不干擾。只有這一步會改變大小。
數學家寫成 Σ · 白話:「拉」的那個矩陣再繞著原點轉一個角度,把拉好的東西擺到最後該在的位置。形狀一樣沒變。
數學家寫成 U · 白話:「轉回來」的那個矩陣把一個矩陣拆成這三個動作的作法,就叫 SVD (Singular Value Decomposition,中文譯「奇異值分解」; 「奇異」只是 singular 的直譯,跟「很奇怪」沒關係,不用被這個詞嚇到)。
如果你只想知道 SVD 是什麼,上面這樣就夠了。 接下來這一節要解釋的是另一個問題:已經有 04 關的特徵向量了,為什麼還需要它? (特徵向量:被矩陣搬完、方向不變的箭頭。) 答案是 04 關那把刀有三個地方會卡住。
卡點一:資料表通常是長方形的
你手上有一張表:200 個使用者 × 50 部電影的評分,共 10000 個數字。 你想問的問題很自然:
「這 10000 個數字裡,真正的骨架是什麼?是不是其實只有三、四種『口味』在主導 —— 有人愛動作片、有人愛文藝片、有人只看新片 —— 剩下的都只是這幾種口味的加權組合,再加一點雜訊?」
- 這張表排成 200 列 50 欄 —— 注意它是長方形,不是正方形。
- 這個問題 04 關回答過一半:矩陣=一台「搬點機」, 它只認得「被搬完方向不變的箭頭」(=特徵向量)。
- 但 04 關那把刀只吃正方形。特徵向量的定義式 Av = λv (λ 唸「lambda」;白話:把箭頭 v 餵進機器 A,出來的還是同一個方向的 v,只是長度變成 λ 倍), 等號兩邊要比,送進去跟吐出來就得裝一樣多個數字。
- 200×50 做不到:它吃 50 個數字、吐 200 個數字 (習慣說「50 維進、200 維出」;「維」=裡面有幾個數字, 平面上 (x, y) 有兩個數字,就叫 2 維)。
- 進去和出來裝的數字個數不一樣 —— 那個等式連寫都寫不出來。
卡點一:A 吃 50 個數字、吐 200 個數字。把「進去」跟「出來」攤平比長度 —— 50 格 vs 200 格, A v = λ v 連寫都寫不出來。
卡點二:就算是正方形,也不保證拆得開
04 關那一節你已經玩過兩個反例 —— 正方形一樣會卡:
- 純旋轉矩陣[[0, −1], [1, 0]]把每一個方向都轉歪了, 一根「方向不變的箭頭」都找不到。
- 剪切矩陣[[1, 1], [0, 1]]只找得到一根,湊不出一組完整的座標軸。
- 結論:04 關那把刀不只挑形狀,還會失敗。
卡點三:05 關的 PCA 會先造一張你不想要的大表
- 05 關的 PCA 是這樣做的:先組出共變異數矩陣 C (C = 把「每一對欄位一起變動的程度」整理成一張表,03 關那張表),再對 C 找特徵向量。
- C 的大小是欄數 × 欄數:欄數只有 2 → C 是 2×2,很可愛。
- 但你手上是 1536 欄的文字 embedding (embedding = 把文字變成一長串數字,讓電腦能比較它們「像不像」)時 ——
而且組 C 的過程中每個數字都被平方過一次,本來就很小的那些量會被電腦的小數點誤差直接吃掉。
SVD 一次解決這三個卡點
它吃任何形狀的矩陣(卡點一)、對任何矩陣都保證拆得開(卡點二)、 而且做 PCA 時不用把 C 造出來(卡點三)。
三個動作裡有兩個是「轉」。這種只會轉、絕對不改變任何長度、也不改變任何夾角的矩陣, 正式名字叫正交矩陣,就是 06 關那個東西 (書上常拿字母 Q 代表它,Q 就是「那個只會轉的矩陣」的代號,沒有別的意思)。 這一關的 U 和 Vᵀ 都是它。細節等到 ④ 再補。
另外,06 關結尾留了一句沒兌現的話:「秩」告訴你一個矩陣真正有幾層,卻沒告訴你每一層有多重要。 (秩 = 這個矩陣真正有幾層獨立的東西,06 關講過。) 這關就是來補這一刀的 —— 每一層有多重要,答案就藏在動作二的那些「拉幾倍」裡。
04 關的特徵分解是正方形專用、而且可能會失敗的拆法; SVD 是任何形狀都成立、永遠不會失敗的拆法。 它把矩陣拆成「轉 → 拉 → 轉」三個動作,然後告訴你每個動作的細節。
② 從一個方塊被打歪開始
先把所有專有名詞放一邊,回到 04 關那個最樸素的觀念:
矩陣就是一台「搬點機」。你給它一個點 (x, y),它照一條固定的規則把這個點搬到另一個位置。 一張圖上的每一個點都被同一台機器搬一次,整張圖就變形了。
那台機器的規則只有四個數字(2×2 的矩陣就四格), 而且它有三個「不管怎麼搬都不會壞掉」的性質:
- 原點不會動。(0, 0) 搬完還是 (0, 0)。
- 直線搬完還是直線。不會變成波浪、不會折彎。
- 本來平行的兩條線,搬完還是平行。所以正方形只會變成平行四邊形 (=四邊兩兩平行的四邊形),不會變成梯形。
下面就把一個正方形(裡面均勻放 25 個點)丟進去,看它被搬成什麼樣子。
你會看到什麼:灰虛線=搬家前的正方形+內接的圓 (內接的圓=剛好塞在正方形裡、四邊中點都碰得到的圓;灰虛線整場不動,當比例尺=拿來對照搬了多遠); 青色=搬家後(外框、圓、25 個點); 綠色大點=右上角那點,盯著它就知道圖被翻去哪; 紫箭頭/桃箭頭=「往右一格」「往上一格」兩根基準箭頭被搬到哪。
你可以動什麼:七顆按鈕,各是一台不同的搬點機。 (想逐格微調那四個數字,去 ④ 那裡拉滑桿,改了這裡會跟著變 —— 兩節共用同一台機器。)
要看出什麼:不管按哪顆,青色外框永遠是平行四邊形、青色圈圈永遠是橢圓 (橢圓=被拉長又壓扁的圓)—— 不會變方形、心形、波浪。 (兩個看起來像例外的按鈕,其實是橢圓的兩個極端:按「只轉不拉」時兩個方向拉一樣多, 出來的圓就是「長軸短軸一樣長」的橢圓;按「壓扁成一條線」時有一個方向被拉 0 倍, 出來的線段就是「短軸被壓到沒有寬度」的橢圓。④ 那裡會用數字再講一次。)
符號怎麼唸、怎麼翻:e₁ 唸「e one」=往右一格 (1, 0); e₂ 唸「e two」=往上一格 (0, 1)。 矩陣第一欄=e₁ 被搬到哪、第二欄=e₂ 被搬到哪,沒有別的意思。
為什麼「一定是橢圓」這件事這麼重要
因為橢圓好描述到不行。要把一個(中心在原點的)橢圓講完,只要三樣資料:
一個橢圓,三樣資料講完:① 長軸朝哪個方向(一個角度)→ ② 長軸多長 → ③ 短軸多長 (一定跟長軸垂直,不用另外講)。知道這三樣,橢圓就完全確定了。
換句話說:一台搬點機對圓做的所有事情,都能用「一個角度 + 兩個長度」講完。 這就是為什麼「轉 → 拉 → 轉」這三個動作夠用了 ——
「矩陣能做的事」比你想像的少很多:對一個圓,它只能轉 → 拉 → 轉。 下一節就讓你自己當那台機器,親手把這三個動作做一遍。
③ 主實驗:你自己當那台機器,三個動作組一個矩陣出來
拆東西之前,先學會組東西。這一節反過來做:不是拆矩陣,而是 自己決定三個動作,看它們合起來變成什麼矩陣。實驗品是同一個正方形(+內接的單位圓, 半徑 1)。(單位圓=半徑剛好是 1 的圓,拿來當「標準形狀」最方便,被拉幾倍一眼就看得出來。)
四根滑桿就是三個動作的全部參數:
- 動作一:先轉幾度 角度叫 θ(唸「theta」,中文就叫角度),正的往逆時針轉。
- 動作二:橫向拉幾倍、直向拉幾倍 倍數叫 σ(唸「sigma」),這裡就是「拉幾倍」; 兩個數字可以不一樣,這是重點。
- 動作三:再轉幾度 另一個 θ,負責把拉完的形狀轉回該在的角度。
跟旁邊的組裝台互補:組裝台讓你自己調三個動作的數字, 這張圖告訴你順序是固定的 —— 一定是「先轉、再拉、最後轉回來」,換了順序就不是同一台機器。
四格依序代表什麼:同一個正方形(+內接單位圓)依序做完三個動作 —— 格 1 出發 → 格 2 轉一轉 → 格 3 拉一拉 → 格 4 轉回來。
- 青色外框與 25 個點=目前的形狀。
- 綠色大點=右上角追蹤點,盯它就知道被轉到哪。
- 紫線/箭頭與桃線/箭頭=原本的橫軸、直軸被搬到哪 (跟著整張圖一起被搬,所以動作一那格看得到「軸真的跟著轉了」)。
- 灰虛線=出發時的正方形與圓,留著當比例尺;背景格線是畫面本身的橫直方向,不會動。
你可以動什麼:四根滑桿(轉角₁、橫向倍率、直向倍率、轉角₂);下面那排按鈕是值得一看的組合, 「▶ 播放三個動作」依序把四格點亮一次。
要看出什麼:格 1→2 形狀完全沒變、只是轉了;格 2→3 只有大小變、方向沒轉;格 3→4 又只是轉。 三個動作走完 =「直接用合成矩陣 M 一步搬到位」一模一樣(右邊讀數盤最下面三列就是現場對帳)。
- 兩倍率不一樣:正方形變長方形、圓變「正的」橢圓;一樣=整體放大縮小、形狀不變;有一個是 0=壓成線段。 (每一格的圖說會跟著實際數字改寫,不會跟畫面說反話。)
- 順帶看得到:紫線跟桃線本來垂直,被動作二拉完就不垂直了 —— 橫向拉 σ₁ 倍、直向拉 σ₂ 倍,斜著擺的東西當然被扯歪。 (那 SVD 憑什麼保證「進去垂直、出來還是垂直」?因為它專挑那兩根拉完仍垂直的方向 —— 就是 ④ 裡的 v₁、v₂。)
符號:σ(sigma)=「拉幾倍」,σ₁ 橫向、σ₂ 直向;θ(theta)=角度; M=三個動作合起來之後的那一台搬點機。
動作一:轉一轉(把 θ₁ 拖來拖去,其他三根不要動)
先只玩最左邊那根滑桿,盯著第 2 格:
- 整張圖繞著原點轉,紫色、桃色的軸線也一起轉了(軸畫在圖上,當然跟著走)—— 這是這一步的重點。
- 為什麼要先轉?因為動作二只會沿「橫」跟「直」拉,不會斜著拉。 想拉斜的方向(如 45°),就先把它轉到橫的位置,拉完再轉回去 —— 動作一=把想拉的方向搬到橫軸上。
把 σ₁、σ₂ 都調成 1.0(等於「不拉」),然後只拖 θ₁。 你會看到四格圖從頭到尾都只是同一個正方形在轉 —— 大小、形狀、角度全都沒變。 這就是「轉的矩陣不會製造也不會消滅大小」這句話的意思。
動作二:拉一拉,而且兩個方向可以獨立拉
整關最關鍵的一步。做的事簡單到好笑:把每個點的橫座標乘上 σ₁、直座標乘上 σ₂。就這樣。
也因為它們互不干擾,圓被拉出來的橢圓一定是「正的」—— 長軸躺在橫的、短軸站在直的,不會歪。
- 按「只拉橫向」(σ₂ 設成 1.0、σ₁ 是 2.4),再拖 σ₁:正方形只往左右長,高度一動不動,圓變躺著的橢圓。 (σ₂ 只是「設成」1.0,不是鎖住的 —— 還是能拖,但那就不是「一次只調一個」了。)
- 按「只拉直向」(σ₁ 設成 1.0、σ₂ 是 2.4):只往上下長,左右不動。
- 再把兩根都拉開:結果=前兩件事的疊加,橫照 σ₁、直照 σ₂,沒有第三件事發生。這就是「獨立」。
幾個一看就懂的特例,值得你親手拖到那個位置看一眼:
| 你把倍率設成 | 圓會變成 | 白話 |
|---|---|---|
| σ₁ = σ₂ = 1 | 還是原來的圓 | 沒拉,等於什麼都沒做 |
| σ₁ = σ₂ = 2 | 半徑 2 的圓 | 整體放大兩倍,形狀不變 |
| σ₁ = 2.4,σ₂ = 1 | 躺著的橢圓 | 只有橫向被拉 |
| σ₁ = 2.4,σ₂ = 0.4 | 又扁又長的橢圓 | 橫向拉長、直向壓扁 |
| σ₂ = 0 | 一條線段 | 直向被壓成 0,整張圖被拍平在一條線上 —— 回不去了 |
最後那一列最重要:σ = 0 = 這個方向被整個壓掉,所有差異通通變成同一個值 0,回不去了 —— 這就是 06 關講的「壓扁之後回不去」,也就是「這個矩陣沒有逆矩陣」的幾何意義。 (逆矩陣=把搬點機的動作完全倒回去的那台機器;有方向被壓成 0,資訊沒了,就沒辦法倒回去。)
動作三:轉回來
拉完之後橢圓是「正的」(長軸躺橫軸上)。最終結果通常不長這樣 —— 最後再轉一次,把它擺到該在的角度。
- 按「沿 45° 拉(三步全用)」:θ₁ = −45°、σ₁ = 2.6、σ₂ = 0.7、θ₂ = +45°。
- 一格一格看:倒轉 45°(把 45° 方向轉到橫軸上)→ 橫向拉 2.6 倍 → 再轉回 +45°(擺回原角度)。
- 結果:整張圖沿 45° 斜方向被拉長 2.6 倍。「沿斜方向拉」動作二自己做不到 —— 它只會橫著拉。 是三步湊起來才做得到,這就是為什麼需要三個動作,不是一個。
現場對帳:三個動作 vs 直接一步到位
右邊讀數盤最下面三列:拿右上角追蹤點(出發 (1, 1))當白老鼠,用兩條路線搬到終點再比對答案。
- 路線 A(三個動作):(1, 1) → 轉 θ₁ → 橫乘 σ₁、直乘 σ₂ → 轉 θ₂ → 終點。
- 路線 B(一步到位):三個矩陣先乘成一個 M,M 直接吃 (1, 1),一次搬到終點。
- 終點永遠是同一點,「兩者相差」永遠是 1e−16 這種等級 —— 那不是誤差,是電腦小數點算到底的極限。 三個動作 = 一個矩陣,是等號,不是近似。
你剛剛親手做的事情,就是 SVD 的反方向: 給三個動作,湊出一個矩陣。SVD 做的是正方向:給你一個矩陣,把三個動作反推出來。 而且它保證:不管那個矩陣多奇怪,這三個動作一定存在。下一節就來看它怎麼反推。
④ 反過來:任何矩陣都拆得回這三個動作
現在把 ② 那台被打歪的搬點機拿回來,讓 SVD 現場把它的三個動作算出來。
公式長這樣,只有五個符號 —— 每一個都是你剛剛在 ③ 親手拖過的東西:
VT(唸 V transpose)—— 最右邊,動作一「先轉一轉」的那個矩陣。
Σ(唸大寫 sigma)—— 中間,動作二「拉一拉」的那個矩陣,對角線上放著兩個倍率 σ₁、σ₂。
U —— 最左邊,動作三「轉回來」的那個矩陣。
記得從右邊往左讀:點先碰到 VT,再碰到 Σ,最後碰到 U。
四格依序代表什麼:同一個單位圓被 A 吃掉的三個中間步驟 —— 格 1 出發 → 格 2 套 Vᵀ → 格 3 套 Σ → 格 4 套 U。
- 青色輪廓/小點=目前的形狀(圓上 12 個等距記號)。
- 綠色大點=追蹤點,看它跑到哪就知道形狀被轉了多少。
- 紫箭頭 v₁=原圖上被拉最長的方向;桃箭頭 v₂=垂直於它的另一個方向。
你可以動什麼:四根滑桿是矩陣 A 的四個數字(左上、右上、左下、右下); 下面按鈕是幾台經典搬點機(跟 ② 同一組);「▶ 播放三步」依序點亮四格。
要看出什麼:格 1→2 圓還是圓(只轉),格 2→3 圓變成正的橢圓(只沿橫、直拉), 格 3→4 橢圓同樣胖瘦、只是轉了角度(只轉)。三步走完=直接算 A×圓(第 4 格綠虛線)完全重合。 (少數 A 的第 3 格不是橢圓:「只轉不拉」時 σ₁ = σ₂,圓拉完還是圓; 「壓扁成一條線」時 σ₂ = 0,圓被壓成線段 —— 每一格圖說會跟著實際數字改寫。)
符號:v₁/v₂(v one/v two)=進去端方向; u₁/u₂(u one/u two)=出來端方向;下標 1 是「拉最多」的那根。 (第 4 格裡 v₁ 轉完拉完再轉完,就落在 u₁ 上;u₁ = 那個橢圓的長軸方向。)
三個矩陣現在長什麼樣子
上面滑桿動的時候,下面這三個矩陣就是 SVD 現場算出來的答案。 把它們照順序乘起來,要一個數字不差地變回 A —— 這個「不差」就是讀數盤最後那行「還原誤差」在講的事。
用手算一次:一個你自己驗得動的整數例子
上面那些小數看久了會麻痺,所以這裡給一個全部都是整數、國中生拿紙筆就能驗算的例子。 按上面的「整數例 [[2,1],[1,2]]」按鈕,圖會切到這台機器:
這台機器把點 (x, y) 搬到 (2x + y, x + 2y)。(這剛好就是 04 關主實驗那個矩陣,你可以兩關對照著看。)
第一步:找「被拉最兇」的方向。怎麼找?回到 ② 那張圖: 把這個 A 按下去,看那個青色橢圓的長軸朝哪邊,那就是被拉最兇的方向 (② 的讀數盤直接印給你看:長軸朝哪個方向 = 45.00°)。 也可以用最土的方法:拿一圈半徑 1 的點一顆一顆送進 A,看哪一顆跑得最遠。
這個 A 的答案是右上 45° 那個方向。45° 上面最好算的點就是 (1, 1),拿它來代表。 把它送進機器:
第二步:找垂直於它的那個方向,也就是左上 135°,挑點 (−1, 1)。送進去:
第三步:對答案。把按鈕按下去看讀數盤,σ₁ 應該顯示 3.0000、σ₂ 顯示 1.0000,v₁ 的方向 45.00°。 還可以再驗一條帳:
翻成三個動作就是:先把整張圖倒轉 45°(把那個「要被拉 3 倍」的方向轉到橫軸上) → 橫向拉 3 倍、直向拉 1 倍 → 再轉回 45°。 這正是你在 ③ 按「沿 45° 拉」時做過的事,只是倍率換成了 3 和 1。
三個矩陣各自的規矩
U 跟 Vᵀ:只轉,絕對不變形。
06 關的正交矩陣,用一句話複述: 它的每一根欄向量長度都是 1、而且兩兩垂直,所以它作用在任何東西上都不會改變長度、也不會改變夾角。 它能做的只有「把整個平面像一塊硬紙板一樣轉一個角度」(外加可能翻一次面,像照鏡子)。
兩個副作用你會一直用到:
- QTQ = I —— 轉置就是逆矩陣。要把它做的事倒回去,不用解方程式,把矩陣翻過來就好。 (「轉置」= 把列變成欄,就是沿著左上到右下那條斜線把矩陣翻一次。)
- 它不會製造也不會消滅「大小」 —— 所以 A 把東西放大縮小的能耐,全部都在中間的 Σ 裡,一分不漏。
Σ:只沿著座標軸拉。
「對角矩陣」就是「只有左上到右下那條斜線上有數字,其他格子全是 0」的矩陣。它作用起來蠢得可愛:
那兩個倍率 σᵢ 到底是什麼
σᵢ = 第 i 個方向的拉伸倍率。講得精準一點: 把方向 vᵢ 送進 A,出來的東西會落在 uᵢ 這個方向上,長度變成原來的 σᵢ 倍。寫成一行就是:
這跟 04 關的 Av = λv 只差一個字:右邊換成了另一根向量 u。 正因為進去和出來的方向可以不一樣,A 才可以是長方形的。
v₁(紫)是單位圓上被拉最長的那個方向,長度就是 1。 A 把它搬到 u₁ 方向,長度直接變成 σ₁ 倍(因為出發長度是 1,出來就剛好是 σ₁)—— 這就是 A v₁ = σ₁ u₁ 那一行公式在講的事。
兩個規定,記住就好:
- σᵢ 一律 ≥ 0。它是「拉幾倍」,倍數沒有負的。想要「反方向」?那個負號被吸收進 uᵢ 裡了。
- σ₁ ≥ σ₂ ≥ … 由大到小排。這是慣例,也是後面「低秩近似」能成立的原因 —— 排好之後,「前 k 層」自動就是「最重要的 k 層」。 (③ 的組裝台不管這條規矩,那裡你想橫向拉多少、直向拉多少都隨你; 但等 SVD 把它拆回來的時候,會自動把大的排前面。)
跟 04 關的 λ 對比
| 特徵值 λ(04 關) | 奇異值 σ(這關) | |
|---|---|---|
| 定義式 | Av = λv | Av = σu |
| 進去 / 出來的方向 | 必須同一根 | 可以是兩根不同的 |
| 可以是負的嗎 | 可以(負 = 方向翻過去) | 不行,一律 ≥ 0 |
| 可以是複數嗎 | 可以(代表這動作在轉) | 不行,一律是實數 |
| 保證存在嗎 | 不保證 | 保證,任何矩陣都有 |
σ 和 λ 是兩種不同的數字,只有在一種情況下會撞在一起:A 本身是對稱且半正定 (對稱=沿「左上 → 右下」那條對角線翻過來一模一樣;半正定=一種特別乖的對稱矩陣, 它不會把任何方向翻面,所以特徵值全部 ≥ 0 —— ⑧ 有嚴格定義)(例如共變異數矩陣 C)。 那時候 σᵢ = λᵢ —— 上面那個整數例 [[2,1],[1,2]] 剛好就是這種,所以它的 σ(3 和 1)跟 04 關算的 λ(3 和 1)長一樣。 其他時候它們沒有簡單關係:例如剪切矩陣 [[1, 1], [0, 1]] 的 λ 是 1 和 1,σ 卻是 1.618 和 0.618。 (按「推歪(剪切)」按鈕就看得到。)
本頁符號速查
這關會出現的符號就這些。看到不認識的翻回來對一下:
| 符號 | 唸法 | 白話叫它什麼 | 它是什麼 |
|---|---|---|---|
| A | A | 那台搬點機 | 你要拆的那個矩陣。這關的互動裡是 2×2(四根滑桿),實務上是 m×n 的資料表。 |
| m, n | m、n | 幾列、幾欄 | A 的列數與欄數。m×n 就是「m 列 n 欄」,例:1000 個人 × 20 個欄位。 |
| VT | V transpose | 「轉一轉」的矩陣 | 動作一。V 的轉置(列欄互換)。因為 V 只會轉,VT 同時也是 V 的逆矩陣。 |
| Σ | 大寫 sigma | 「拉一拉」的矩陣 | 動作二。對角矩陣,只有對角線有值,放的是 σ₁, σ₂, … |
| U | U | 「轉回來」的矩陣 | 動作三。跟 V 一樣只會轉,不改變任何長度。 |
| σi | 小寫 sigma i | 拉幾倍 | 第 i 個奇異值=第 i 個方向的拉伸倍率,一律 ≥ 0,由大到小排。 |
| V | V | 進去端的兩根方向 | 欄向量 v₁, v₂ 是「要被拉的那兩根方向」,長度都是 1、互相垂直。 |
| ui, vi | u i、v i | 第幾根箭頭 | 第 i 根左 / 右奇異向量。它是一整根向量,不是一個數字(2×2 的情況裡,每根裝兩個數字)。下標 i 就是「第幾根」。 |
| Q | Q | 只會轉的矩陣 | 正交矩陣的通用代號:欄向量兩兩垂直、每根長度 1,所以只會轉、不改變長度與夾角。這關的 U 和 V 都是這種。 |
| det | determinant / 行列式 | 面積放大幾倍 | det A 是帶正負號的面積倍率;負號代表「還翻了一次面」。det = 0 就是被壓扁了。這關有 |det A| = σ₁ × σ₂。 |
| |x| | x 的長度 | 那根箭頭多長 | 兩根直槓包住一根向量=它的長度(用畢氏定理量),永遠 ≥ 0。包住一個數字時是「絕對值」(去掉負號)。 |
| 維 | 維 / dimension | 裡面有幾個數字 | 平面上的箭頭有 x、y 兩個數字 → 2 維;1536 維就是一根裡面裝 1536 個數字。 |
| T(右上角) | transpose / 轉置 | 沿斜線翻一次 | 把矩陣的列變成欄(直的變橫的)。兩個規矩:(AB)T = BTAT(順序倒過來)、對角矩陣轉置還是自己。 |
| θ | theta | 角度 | ③ 那兩根轉角滑桿。正的是逆時針。 |
| λ | lambda | 04 關的伸縮倍數 | 04 關的特徵值。這關只在 ⑦ 拿來對照。 |
| k | k | 留幾層 | 低秩近似時「保留幾層」的那個數字。k = 1 就是只留最重要的一層。 |
| C | C | 共變異數矩陣 | 03 關那張表,C = XTX /(n−1)。 |
| X | X | 去中心化後的資料表 | 每一列一個樣本,每一欄一個變數,而且每一欄的平均已經被減成 0。 |
| I | I | 什麼都不做 | 單位矩陣:對角線全 1、其他全 0,乘上去等於沒動。 |
| rank | rank / 秩 | 真正有幾層 | 06 關的秩:這個矩陣真正有幾層獨立的東西。= 不是 0 的 σ 有幾個。 |
SVD 把一台搬點機的能耐切成三份:方向的資訊全在 U 和 V 裡,「拉幾倍」的資訊全在 Σ 裡。 而且因為 U、V 只會轉不會變形,這種切法不會有任何遺漏、也不會有任何重複算到。
⑤ 換個讀法:把矩陣看成一層一層疊起來的
- 「A = UΣVᵀ」是三個矩陣相乘的寫法;同一件事還有第二種寫法 —— 把 A 拆成好幾層疊起來,這種寫法才是 SVD 在真實系統裡真正被用的樣子。
- 外積(outer product):一根直立的向量 × 一根橫躺的向量,結果不是一個數字,是一整張表(矩陣)—— 跟 01 關學的內積(橫躺乘直立,結果是一個數字)方向剛好相反。
- 秩 1 矩陣:一次外積生出來的矩陣就叫「秩 1」,意思是只有一層——攤開來雖然有一整格表,但骨子裡只帶一份方向的資訊。
- A = σ₁u₁v₁ᵀ + σ₂u₂v₂ᵀ + … 就是把 A 拆成好幾個秩 1 矩陣加起來,每一項是一層,σ 是這一層的權重,由大到小排。
左邊那根直的是 a(2、1、3),上面那根橫的是 b(1、3、2)。 每一格都是「左邊那個 × 上面那個」,9 格填滿就是一整張 3×3 的表 —— 這張表只靠 a、b 這 6 個數字就決定了,這正是「一層」的意思。 (這張圖刻意用「一根裝 3 個數字」來畫,讓你看到表可以更大; 下面那個滑桿版是「一根裝 2 個數字」的 2×2 版,規則一模一樣,只是格子少一點。)
要看懂「A = σ₁u₁v₁ᵀ + …」這個寫法,只要先搞懂上面那張表在幹嘛 —— 也就是為什麼 u₁v₁ᵀ 是一整張表,不是一個數字。慢慢來。
u₁ 不是一個數字,是一整根箭頭。上面那個式子裡的 u₁、v₁ 各是一整根向量(2×2 的情況下,每根裡面有兩個數字),下標 1 的意思是「第 1 根」,不是「第 1 個數字」。
所以 σ₁u₁v₁T 不是「三個數字相乘」,而是 「一個數字 σ₁」×「一整根 u₁」×「一整根放倒的 v₁」,結果是一整個矩陣。
正因為很容易混,下面練手的那張乘法表刻意改用別的字母:直立的那根叫 a(裡面兩個數字是 a₁、a₂),橫躺的那根叫 b(裡面兩個數字是 b₁、b₂)。 a、b 就是隨便兩根向量,跟 SVD 沒關係,純粹拿來練「直的 × 橫的」怎麼算。 學會之後再把 a 換成 u₁、b 換成 v₁ 就好。
先搞懂「直的 × 橫的」:其實就是小學的乘法表
你在 01 關學的內積,寫成矩陣是 aᵀb:橫躺的乘直立的, (1×2) × (2×1),結果是一個數字。
現在把順序倒過來,abᵀ:直立的乘橫躺的,(2×1) × (1×2), 結果是一整個 2×2 的矩陣。算法就是小學的九九乘法表 —— 左邊每一格,乘上上面每一格:
你會看到什麼:一張乘法表。左欄是 a 的兩個數字(直立擺), 上排是 b 的兩個數字(橫躺擺), 中間綠色四格就是 abᵀ 的四個數字,每一格都是「左邊那個 × 上面那個」。
你可以動什麼:四根滑桿,分別是 a₁、a₂、b₁、b₂ 這四個整數。
要看出什麼:不管你怎麼調,上下兩列一定「平行」 —— 也就是下面那一列剛好等於上面那一列乘上某個固定倍數(a₁ 不是 0 的時候,那個倍數就是 a₂ ÷ a₁; a₁ 是 0 的時候上面整列都是 0,兩列還是算平行)。 兩列平行 → 這個矩陣的秩是 1 → 它只有「一層」。 (唯一的例外:a 或 b 整根被拉成 0 —— 那整張表 4 格全是 0,一層都沒有,秩是 0。 所以嚴謹講是「秩最多 1」。)
符號怎麼唸、怎麼翻:aT 唸「a transpose」, 就是把直立的 a 放倒成橫躺的。所以 abT 唸「a 乘 b transpose」, 白話是「一根直的 × 一根橫的 = 一張乘法表」。 「秩」= 06 關那個「真正有幾層」; 「行列式」(det)= 這個矩陣把面積放大幾倍,是 0 就表示被壓扁了。
一張「直的 × 橫的」乘法表 = 秩 1 的矩陣 = 「一層」。 這裡練的是 abT,SVD 裡的每一層 uiviT 是一模一樣的算法,只差在 uᵢ、vᵢ 這兩根不是隨便挑的(長度都是 1,而且是 SVD 算出來的)。
一層明明攤開來有 m×n 格,卻只需要 m + n 個數字就能寫下來(直的那根 m 個、橫的那根 n 個)—— ⑥ 的省空間就是從這裡來的。
回到 A:疊上第二層
下面用的是 ④ 那個 A(同一台機器,改上面的滑桿這裡會跟著變)。 現在把它拆成兩層,讓你自己決定要疊幾層:
你會看到什麼:單位圓被「目前保留的層數」作用之後的形狀。 紫=第一層 σ₁u₁v₁ᵀ 的貢獻方向、桃=第二層的貢獻方向、 綠虛線=完整的 A 的結果(當作標準答案對照)。
你可以動什麼:兩顆按鈕切「只留第一層」/「兩層都留」。右邊的矩陣數字會同步換。
要看出什麼:只留第一層時,整個圓被壓扁成一根線段(因為秩 1 的矩陣把整個平面壓到一條線上); 加上第二層,線段才長出寬度、變回橢圓、跟綠虛線重合。σ₂ 越小,第一層就越接近完整的 A。
符號怎麼唸、怎麼翻:σ₁u₁v₁T 唸「sigma one、u one、v one transpose」, 白話就是「第一層那張乘法表,再乘上它的權重」。
矩陣不是一團 m×n 個彼此無關的數字,它是幾張乘法表疊起來的東西, 而 SVD 告訴你這幾張表分別長什麼樣、以及誰比較重要。 「只留一個方向」的意思,就是只留一張乘法表 —— 整個平面被壓到一條線上。
⑥ 只留前面幾層:把小的 σ 丟掉,能省多少
- 低秩近似:既然層是排好序的(第一層最重要、越後面越不重要),自然的想法就是只留前 k 層,後面全部丟掉——這個動作的正式名字。
- 這樣切有個很強的保證:在所有「只有 k 層」的矩陣裡面,這樣切出來的那一個離原矩陣最近,沒有更好的答案了。 (這個定理叫 Eckart–Young,這關不證,但你可以放心用。)
- 下面這張 12×12 的圖案不是隨便畫的,是用公式現場生出來的:兩顆模糊的亮點 + 一條斜著的亮帶。數字越大顏色越深。
生成公式寫在檔案裡的
genPattern,你可以改。
三格都是同一張圖(用同一套灰階方塊示意),差別只在疊了幾層:只留 σ₁ 只看得出模糊的輪廓, 加上 σ₂、σ₃ 之後對比越來越清楚。這裡的百分比是示意用,不是下面互動圖的真實數字。
你會看到什麼:三張 12×12 的方格圖。左=原圖(青色越深數字越大)、 中=只用前 k 層重建出來的圖、右=誤差圖(紅色越深代表這一格差越多)。 下面那排橫條是 12 個倍率 σ₁…σ₁₂ 的大小,被保留的是青色、被丟掉的是灰色。
你可以動什麼:一根滑桿,決定保留幾層(k 從 1 到 12)。
要看出什麼:σ 掉得非常快 —— 前兩層就吃掉 95.7% 的份量。 k 拉到 4、5 圖幾乎一樣,但這張 12×12 太小已經省不到什麼。 同時看右邊那欄的帳:k 太大反而比原本更佔空間。
符號怎麼唸、怎麼翻:k 就是「留幾層」; 「份量」是 σ 的平方加起來(正式名字叫「能量」),白話是「這些層加起來佔了整張圖的多少」; RMSE 是「每一格平均差多少」。
為什麼要平方?因為 σ 只講「拉幾倍」,正負號、方向都跟它無關,直接加總會有大有小互相抵消; 平方之後全部變正數,加起來才代表「這一層真正貢獻了多少能量」——這跟 02 關算變異數要先平方是同一個理由。
前面 ③④ 都在講「拉」,這一節請改用「層」來想,不要用「拉」來想。 12×12 的圖案不是什麼形狀被拉歪 —— 它是12 張乘法表疊起來的一張圖, 而你在做的事是「只留前幾張、其他不要」。σ 在這裡的角色不是「拉幾倍」,是「這張表有多重要」。
儲存成本怎麼算
這跟 05 關那筆帳是同一個算法:你不能只算「壓縮後的資料」, 還得把「還原時需要的參數」一起算進去,不然那堆數字根本還原不回來。
保留 k 層:k × (m + n + 1) 個數字 每一層需要:一根 uᵢ(m 個數字)+ 一根 vᵢ(n 個數字)+ 一個 σᵢ(1 個數字)。 k 層就乘上 k。
m = n = 12 的時候:原本 144,每多留一層要多花 25 個 —— 所以 k ≥ 6 就虧本了。 12×12 太小,本來就不是拿來壓縮的尺寸。
壓縮率怎麼算:拿「保留 k 層要花的數字」除以「原本 m×n 個數字」, 數字越小代表省得越多。真正划算的是細長或巨大的矩陣。把 ① 那張評分表代進去看:
| 矩陣 | 原本 m×n | k | k(m+n+1) | 剩下 |
|---|---|---|---|---|
| 資料表 1000 × 20 | 20,000 | 3 | 3,063 | 15.3% |
| 評分表 200 × 50 | 10,000 | 8 | 2,008 | 20.1% |
| embedding 100萬 × 1536 | 15.36 億 | 128 | 1.28 億 | 8.3% |
| 這節的 12 × 12 | 144 | 4 | 100 | 69.4% |
低秩近似省掉的不是「不重要的細節」,是排在後面的那幾層。 它們是不是真的「不重要」,取決於你接下來要問什麼問題 —— 這句話跟 05 關丟掉次軸那段是同一個道理。
⑦ SVD 跟 PCA、跟特徵分解到底什麼關係
先看差在哪
先把左欄那幾個符號講清楚,不然整張表看不懂:A = PDP⁻¹ 是 04 關那個對角化的寫法 —— P = 把特徵向量一根一根當欄排成的表 (=「換去骨架那套座標」的那張表)、D = 對角線上放特徵值 λ 的對角矩陣(=在骨架上各拉各的)、 P⁻¹ = P 的逆矩陣(把 P 的動作原封不動倒回去的那台機器,也就是「從骨架那套座標翻回原本的座標」)。
| 特徵分解 A = PDP⁻¹ | SVD A = UΣVᵀ | |
|---|---|---|
| 吃什麼形狀 | 只吃正方形 n×n | 任何 m×n |
| 保證存在嗎 | 不保證(旋轉、剪切就爆) | 保證,永遠存在 |
| 兩組軸互相垂直嗎 | 一般不垂直(A 對稱時才垂直) | U、V 兩組都垂直 |
| 對角線上的值 | λ,可正可負可複數 | σ,一律實數且 ≥ 0 |
| 進去 / 出來同一組軸嗎 | 同一組(P 和 P⁻¹) | 兩組不同(V 進、U 出) |
| 數值穩定嗎 | P⁻¹ 可能病態(ill-conditioned:P 快要不可逆, 算它的逆矩陣時輸入端一點點小誤差會被放大成很大的誤差,答案不能信) | 只會轉的矩陣,逆矩陣就是轉置,很穩 |
一句話對照:特徵分解是「同一組軸進、同一組軸出」,只對正方形有效,還可能失敗; SVD 是「一組軸進、另一組軸出」,任何形狀都保證拆得開。
再看它們在哪裡接上:PCA 那個等式
- 這是全關最實用的一條,把 05 關和這關焊死在一起。
- 設 X 是去中心化之後的資料表(n 列樣本 × d 欄變數,每一欄的平均已經被減成 0)。 03 關的共變異數矩陣就是下面這個公式。
現在對 X 直接做 SVD:X = UΣVT。把它代進去:
① 轉置會把乘法的順序倒過來:(ABC)T = CTBTAT。所以 (UΣVT)T 變成 VΣTUT。
② 對角矩陣轉置還是它自己:ΣT = Σ(沿斜線翻一次,斜線上的數字沒動,其他本來就是 0)。所以上面直接寫成 VΣUT。
③ 只會轉的矩陣,轉置乘自己等於「什麼都沒做」:UTU = I,所以中間那塊直接消失。
剩下 ΣΣ = Σ²(對角線上的數字各自平方)。所以 C = V (Σ²/(n−1)) VT,這正好就是 C 的特徵分解。
1. X 的右奇異向量 vᵢ,就是 C 的特徵向量(= 05 關的主軸)。
2. σᵢ² /(n−1) 就是 C 的特徵值 λᵢ(= 那根主軸上的變異數)。
這句話怎麼唸:「X 的奇異值平方、除以 n−1」就等於「XᵀX 對應的特徵值」—— 因為上面推出 C = XᵀX/(n−1) = V(Σ²/(n−1))Vᵀ,而 V(Σ²/(n−1))Vᵀ 這個寫法本身就是特徵分解的樣子, 所以對角線上那排 σᵢ²/(n−1) 一格一格對應著 C 的特徵值 λᵢ。
所以做 PCA 根本不用把 C 造出來,直接對去中心化的 X 做 SVD 就好 —— 這就是 ① 那個 236 萬格中間表可以直接跳過的原因,也是 sklearn 的 PCA 底層真的在做的事。
現場驗算:還是 05 關那 12 個人
你會看到什麼:左邊是 05 關那 12 個人的身高體重散佈圖(青點), 紫箭頭是用 SVD 算出來的 v₁。右邊兩欄數字並排:左欄走 SVD、右欄走 eig(C), 同一列的兩個數字應該一模一樣。
你可以動什麼:兩顆按鈕,切換「有去中心化(正確做法)」和「忘了去中心化」。 切過去的時候鏡頭會拉遠,好讓座標原點進到畫面裡。
要看出什麼:有去中心化時,σ₁²/(n−1) = 205.55、主軸 45.24°, 跟 05 關算出來的 λ₁ 和角度一個小數點都不差。 忘了去中心化的話,v₁ 會整根倒向「原點到資料重心」那一側(算出來是 19.59°,而重心方向本身是 19.46°), 算出來的東西根本不是 PCA —— 而且沒有任何錯誤訊息。
為什麼去中心化會改變主軸?沒去中心化的 X,每一列除了「跟其他人比起來的差異」還多帶了「離原點多遠」這件事; 對 XᵀX 做分解時,這股「離原點的距離」會混進去、蓋過原本資料真正散開的方向 —— 所以 v₁ 不再指向「資料散得最開」的方向,而是被拉去指向「資料重心離原點的方向」。
符號怎麼唸、怎麼翻:n − 1 這裡是 12 − 1 = 11; σ₁²/(n−1) 唸「sigma one 平方除以 n 減 1」, 白話是「把拉伸倍率換算成 05 關那個『沿這根主軸散得多開』的數字」。
切到「忘了去中心化」時鏡頭會自動拉遠,因為那時候箭頭是從座標原點 (0, 0) 出發的 —— 不拉遠你根本看不到起點在哪。
| 量 | 走 SVD | 走 eig(C) |
|---|
PCA 和 SVD 不是兩件事,是同一件事的兩條路。 「對 X 做 SVD」和「對 C 做特徵分解」給你完全一樣的軸, 但前者不用先造出 C、數值上也穩得多。 05 關是繞路,07 關是直達車,終點站同一個。
⑧ 數學長怎樣:這關的 SVD 是怎麼算出來的(選讀,可跳過)
這一節超綱,第一次讀可以整節跳過,直接跳到 ⑨。 它回答的是「電腦到底怎麼把那三個動作算出來」,屬於實作細節; 不知道這件事,完全不影響你用 SVD。
白話一句:要拆 A,先造 AᵀA —— AᵀA 拆得開,A 就拆得開。 而拆 AᵀA 只需要一個你已經會的工具:特徵分解。四步,一步一行:
- 造 AᵀA(唸「A transpose A」=「A 轉置後,再乘 A」)= 把 A 先搬一次、再用搬法的反向搬回來。 意義:不管 A 長得多怪,造出來的東西一定是對稱矩陣 —— 沿「左上 → 右下」那條對角線左右一模一樣的方陣。
- 對 AᵀA 做特徵分解:因為它對稱,特徵向量保證兩兩垂直,這組垂直向量就是 V。 特徵分解=把方陣拆成「每根方向各被拉幾倍」的工具(04 關那台機器)。 為什麼 AᵀA 一定拆得開:實對稱矩陣一定可以正交對角化(譜定理,沒有例外)→ 這步永遠不會失敗。
- 拉伸倍率 = 特徵值開根號:σ = √λ。 λ(唸「lambda」)是特徵值=「沿某根方向,AᵀA 把那根方向拉 λ 倍」的那個倍率。 AᵀA 半正定(=任何向量 v 送進去,長度平方 vᵀAᵀAv = |Av|² ≥ 0,平方不可能是負的)→ λ 一定 ≥ 0 → 根號裡不會是負的。
- 反推 U:把 vᵢ 送進 A,再除以 σᵢ —— ui = A vi / σi。
第 4 步有個守衛(σᵢ = 0 的時候),不是選配:
- 症狀:σᵢ = 0 = A 把 vᵢ 這個方向整個壓成 0 → A vi / σi 是 0 除以 0,算不出方向。
- 解藥:U 又必須是完整的正交矩陣 → 隨便補一根垂直於前面所有 uⱼ 的單位向量就行(反正它會被 σ = 0 乘掉)。
- ④ 的「壓扁成一條線」按鈕就是在測這條路徑。
符號版:
圖說:看三格怎麼接起來。① 是 A(一台搬點機);② AᵀA =「先搬一次、再用搬法的反向搬回來」,所以一定是對稱的,一定拆得開; ③ 拆出來的倍率 λ 開根號就是 σ。最後一行用本關整數例 [[2,1],[1,2]] 對帳: AᵀA = [[5,4],[4,5]] 的 λ₁ = 9、λ₂ = 1 → σ₁ = √9 = 3、σ₂ = √1 = 1,跟 ④ 那台 A 完全一致。
「造 AᵀA 再分解」在教學上最清楚,在數值上卻是最爛的做法之一:
平方一次,條件數就平方一次,小的 σ 會被浮點誤差直接吃掉。
真正的函式庫(LAPACK 的 dgesdd、numpy 的 np.linalg.svd)走的是
Golub–Kahan 雙對角化,全程不碰 AᵀA。
這一頁是教材,不是函式庫 —— 所以我用清楚的寫法,並且在頁面上印出還原誤差讓你自己檢查。
實測 2×2 的還原誤差在 1e−15 這個量級,教學用途完全夠。
這關的三段實作,都寫在這個檔案裡:
renderBuild()—— ③ 的組裝台。它不做分解,只是老老實實把 R(θ₂) · diag(σ₁, σ₂) · R(θ₁) 乘起來, 再拿追蹤點走兩條路線對帳。R(θ) 就是「轉 θ 度」的旋轉矩陣。svd2(A)—— 2×2 的分解,直接呼叫LAB.M.eig2拿 V,再由 A vᵢ 反推 U。 技巧:σᵢ 不用 √λ 而是直接取 |A vᵢ| 的長度,這樣還原誤差恆為浮點級別。jacobiEig(S)—— n×n 對稱矩陣的特徵分解(LAB.M只有 2×2 版)。 用 Jacobi 旋轉法:反覆挑一個非對角元素,用一個平面旋轉把它轉成 0,掃到全部非對角元素都夠小為止。 ⑥ 的 12×12 就是它算的,約 40 行,程式碼裡有逐行註解。
⑨ 工程師的「原來如此」
- 一百萬美金的題目:2006 年 Netflix 懸賞一百萬美金,要人把電影推薦的預測誤差降 10%;最後贏的那一套,核心就是這關的第二種寫法。
- 隱因子:把「使用者 × 電影」的評分表當成 A,SVD 之後 A ≈ σ₁u₁v₁ᵀ + σ₂u₂v₂ᵀ + …,每一層有了具體意義: v₁ 是一組「電影的口味權重」,u₁ 是一組「使用者對這種口味的偏好強度」。 你沒告訴系統什麼叫動作片,但第一層自己長出來的 v₁ 就會在動作片上給高分 —— 「隱因子」(latent factor)=沒人標註,是從資料的骨架裡掉出來的。
- 空格也能填:預測某人對某片的評分,就是把他的隱因子向量跟那部片的隱因子向量做內積。 200×50 的表壓成 8 層之後,你存的不是 10000 個評分,是 2008 個數字 —— 而且空格也能填了 (原表大部分是空的,你當然沒看過那部片;低秩結構會把它補出來)。 實務上因為空格太多,會用 ALS / SGD 只在有評分的格子上擬合,那叫 matrix factorization, 但骨架就是這裡的 uvᵀ 疊加。
- 文件 × 詞:把一堆文件做成「文件 × 詞」的次數表(1 萬篇 × 5 萬個詞),這張表大得離譜而且幾乎全是 0。 對它做 truncated SVD(truncated=截斷,只留前 k 層)留前 300 層,你會得到一件很妙的事: 「汽車」和「轎車」這兩個詞,在原表裡是完全不同的兩欄(內積 = 0),壓到 300 維之後卻靠得很近。
- 為什麼會靠近:低秩近似的本質 —— 前 300 層是「所有文件共用的骨架」, 而「汽車」跟「轎車」出現在同一批文件裡,所以它們在骨架上的座標幾乎一樣; 被丟掉的後面幾萬層,才是「這篇剛好用了這個詞」的個別雜訊。
- 同一招叫「降噪」:訊號有結構(低秩)、雜訊沒有(份量平均散在所有層)→ 砍掉小的 σ,砍掉的絕大部分是雜訊。 感測器陣列、金融因子模型、影像去雜訊都在用這一手。
- 名詞追認:這套東西叫 LSA(Latent Semantic Analysis),是今天所有 embedding(=把文字變成數字向量,讓機器能比「像不像」)的老祖宗;
sklearn 裡就叫
TruncatedSVD(專門處理稀疏矩陣,不需要去中心化)。 至於「拿 SVD 壓縮 JPG」那個經典教學例子 —— 它能跑,但沒人真的用, 因為 JPEG 的 DCT + 量化在同樣品質下小得多。SVD 在壓縮界的真實戰場是 「大模型權重矩陣的低秩壓縮」(LoRA 那一票)。
⑩ 踩坑
- 症狀:看到 σ 很小那幾層,直覺想砍掉 —— 以為「小 = 沒用」。
- 為什麼:σ 衡量的是「這一層佔了多少份量」,不是「這一層有多少資訊價值」。 在異常偵測裡,訊號正好躲在最小的那幾層 —— 前面幾層是所有人都一樣的共同行為, 「這個帳號跟大家不一樣」這件事只會出現在剩下的那點殘渣裡; 05 關那個「同身高下偏壯偏瘦」也是躲在次軸。
- 怎麼避:丟哪幾層,取決於你要問什麼,不是取決於 σ 的大小。
- 症狀:同一筆資料,換個函式庫、換個版本、換台機器,算出來的 v₁ 可能整根乘上 −1 —— 而且不會有任何錯誤訊息。
- 為什麼:SVD 不唯一:如果 (uᵢ, vᵢ) 是一組解,那 (−uᵢ, −vᵢ) 也是 —— 兩個負號在 σᵢuᵢvᵢᵀ 裡乘掉了,A 一模一樣。 當 σ₁ ≈ σ₂(兩層一樣重)時更糟:那時候 v₁、v₂ 可以在它們張成的平面裡任意旋轉,不只是翻號 (④ 的「只轉不拉」按鈕就是這種情況,σ₁ = σ₂ = 1)。
- 怎麼避:算完立刻做符號規範化(例如強迫某個指定分量為正),並且把它跟模型一起存起來 —— 跟 05 關講的一樣; 不然你存下來的隱因子分數整欄變號,下游那條「分數 > 0 就標成 A 類」的規則會全部反過來。
- 症狀:沒去中心化就做 PCA,主軸指錯方向 —— ⑦ 那個「忘了去中心化」按鈕按下去,主軸從 45.24° 倒到 19.59° (幾乎就是「原點 → 重心」那條線的方向 19.46°)。
- 為什麼:「X 的右奇異向量 = C 的特徵向量」這個等式,前提是 X 每一欄的平均都是 0。 沒去中心化的話,XᵀX 裡混進了「重心離原點多遠」這件事,而且它通常大到把真正的主軸壓掉 —— v₁ 會直接指向重心方向。
- 怎麼避:PCA 前先減掉每欄平均。唯一的反例是 LSA:處理稀疏的詞頻矩陣時故意不去中心化
(去了會把稀疏矩陣變稠密,1 萬 × 5 萬的表直接爆記憶體)—— 所以 sklearn 才要分成
PCA(會去中心化) 和TruncatedSVD(不會)兩個類別,不是重複造輪子,是兩個不同的東西。
- 症狀:完整 SVD 在大矩陣上跑不動、存不下 —— m×n 的完整 SVD 大約要 O(mn·min(m,n)) 的運算量, 而且會吐出一個 m×m 的 U:100 萬列的資料表,那個 U 是 10¹² 個數字,你根本存不下。
- 為什麼:你要的通常只有前 k 層,完整版卻把整個 m×m 的 U 也算出來、存起來。
- 怎麼避:只算你要的那幾層:
numpy.linalg.svd(A, full_matrices=False)(只算細長版)、scipy.sparse.linalg.svds(A, k=50)(只算前 50 個)、 或 randomized SVD(先隨機投影到 k+p 維再做,快一個數量級)。 只想要第一層的話,04 關那個「乘乘乘」的 power iteration 幾十次迭代就給你了,最省。
⑪ 這關回答了什麼
一句話講,SVD 到底在幹嘛?
它把一個矩陣拆成三個動作:先轉一轉(Vᵀ)→ 沿兩條垂直的軸拉一拉(Σ)→ 再轉回來(U)。 任何矩陣都拆得出來。而且只要那些「拉幾倍」的數字兩兩都不一樣,拆法就只有這一種 (唯一的自由度是 uᵢ、vᵢ 可以整根一起翻正負號,A 不變 —— 見 坑 2)。 如果剛好有兩個倍率一樣大,那就不唯一了:它們對應的那兩根方向可以在自己那個平面裡任意轉, 隨便選一組都對(坑 2 後半段)。
為什麼只要三個動作就夠?因為 ② 那個事實: 矩陣對一個圓做的事,永遠只會做出一個橢圓。而橢圓用「一個角度 + 兩個長度」就講完了。
為什麼不能只用一個動作?直接拉不行嗎?
因為「拉」只會沿著橫的跟直的拉,它不會斜著拉。 可是你想拉的方向常常是斜的 —— 這時候就得先把那個方向轉到橫的位置,拉完再轉回去。
③ 的「沿 45° 拉」按鈕就是現場示範: θ₁ = −45° 把 45° 方向轉到橫軸 → 橫向拉 2.6 倍 → θ₂ = +45° 轉回去。 三步湊起來才做得到「沿斜線拉」這件事。
「每個方向可以獨立拉伸」是什麼意思?
字面意思:橫座標只被 σ₁ 影響、直座標只被 σ₂ 影響,兩邊互不干擾。 點 (x, y) 變成 (σ₁x, σ₂y),沒有第三件事發生。
親手驗證:③ 按「只拉橫向」,σ₂ 被設成 1.0,你拖 σ₁ 的時候 正方形只往左右長、上下高度一動也不動。再按「只拉直向」換過來看一次。 兩個看完之後再把兩根都拉開 —— 結果就是前兩件事直接疊加。
奇異值 σ 跟特徵值 λ 差在哪?
定義式差一個字:λ 是 Av = λv(進去出來同一根方向), σ 是 Av = σu(進去出來可以是不同方向)。就因為這一個字, σ 不需要 A 是正方形的。
性質上:λ 可以是負的、可以是複數、可能根本不存在;σ 一律是 ≥ 0 的實數,而且一定存在。 兩者只在「A 對稱且半正定」時會相等 (半正定=一種特別乖的對稱矩陣,不會把任何方向翻面,所以 λ 全部 ≥ 0; 嚴格定義在 ⑧)。完整對照看 ④ 那張表。
為什麼說「任何矩陣都有 SVD」?憑什麼這麼強?
因為它把難題轉嫁給了一個一定成立的定理。看 ⑧ 的算法: SVD 不直接處理 A,而是先造 AᵀA。不管 A 是什麼形狀、多歪多爛, AᵀA 一定是對稱的方陣((AᵀA)ᵀ = AᵀA,兩行就證完),而且半正定 (因為 vᵀAᵀAv = |Av|² ≥ 0,是個平方,不可能是負的)。
而「實對稱矩陣一定可以正交對角化、特徵值一定是實數」是譜定理保證的,沒有例外。 所以 V 一定存在、λ 一定 ≥ 0、σ = √λ 一定算得出來。 SVD 的「永遠成立」是從對稱矩陣借來的。
把矩陣拆成「一層一層」又是什麼意思?跟三個動作衝突嗎?
不衝突,是同一個等式的兩種讀法。三個動作是「A = UΣVᵀ」; 一層一層是把同一個等式攤開寫成 A = σ₁u₁v₁ᵀ + σ₂u₂v₂ᵀ + …。
每一層 uvT 就是一張小學乘法表, σ 由大到小告訴你哪張比較重要。 「只留第一層」= 只留一張乘法表 = 只沿一個方向拉,整個平面被壓成一條線。
低秩近似到底丟了什麼?
丟了「排在第 k 名之後的那幾層」,也就是那些 σ 比較小的 uvᵀ 薄片。 丟掉之後的誤差有個乾淨的公式:剩餘誤差的平方 = 被丟掉那些 σ 的平方和。 ⑥ 那張誤差圖畫的就是這個。
但「σ 小」只代表份量小,不代表沒價值。異常偵測、殘差分析要的正好是被丟掉的那部分 (坑 1)。判斷能不能丟的標準永遠是: 你接下來要回答的問題,會不會剛好落在你丟掉的那幾層上。
什麼時候該用 SVD,什麼時候用特徵分解?
一句話:不確定的時候用 SVD(它不會失敗);只有問題本身就是「方陣重複作用很多次會怎樣」時,才需要 λ。
- 用 SVD:矩陣是長方形的(資料表、評分表、詞頻表);要做低秩近似 / 降維 / 降噪; 要算偽逆、最小平方、條件數;矩陣可能奇異或病態。
- 用特徵分解:你要問的問題本身就是「這個方陣重複作用很多次會怎樣」—— 馬可夫鏈的穩態、微分方程、PageRank、矩陣冪(04 關那個乘乘乘), 因為要的就是「方向不變、只縮放」這件事,只有 λ 回答得了; 另外 A 是對稱矩陣時(共變異數矩陣、Gram 矩陣),特徵分解又快又穩,沒必要繞去 SVD。
SVD 跟 PCA 是同一件事嗎?
幾乎是,但差一個步驟:去中心化。 PCA = 先把每一欄減掉自己的平均,再對結果做 SVD,然後把右奇異向量當主軸。 少了「減平均」這一步,你算的就只是 SVD,不是 PCA(坑 3 那個 19.59° 就是現場示範)。
接上去之後兩者完全等價:X 的右奇異向量 vᵢ = C 的特徵向量、 σᵢ²/(n−1) = λᵢ。⑦ 拿 05 關那 12 個人現場驗算過: σ₁ = 47.5504 → 47.5504²/11 = 205.5489,跟 05 關的 λ₁ 一個小數點都不差。
實務上一律走 SVD 那條路:不用造 C(省掉 d×d 的中間表)、數值上穩得多,
這也是 sklearn PCA 底層真正在做的事。
U、Σ、V 的尺寸到底各是多少?(長方形的時候很容易搞混)
A 是 m×n 的話:U 是 m×m、Σ 是 m×n、V 是 n×n,這叫「完整 SVD」。 Σ 是長方形的對角矩陣 —— 對角線上有 min(m,n) 個 σ,其他全是 0。
但那些 0 對應的 U 欄向量乘出來也是 0,存了沒用。所以實務上都用「精簡 SVD」:
U 是 m×r、Σ 是 r×r、V 是 n×r,r = min(m, n)。
1000×20 的表,完整版的 U 是 1000×1000(一百萬個數字),精簡版只有 1000×20。
numpy 裡就是 full_matrices=False 這個參數。
到這裡,「一個矩陣把圓拉成什麼形狀的橢圓」你已經拆得乾乾淨淨了。 但整關我們都在看形狀 —— 從來沒把它拿來用。
下一關反過來:機率統計 05 關把共變異數矩陣 C 畫出來的那顆橢圓當成一把尺。 同樣是「離重心 3 公分」,在資料鋪得很開的方向上是家常便飯,在資料很緊的方向上就是異常。 這把尺叫馬氏距離,而它量出來的等距線,就是這關那顆橢圓。