02.7.2
SVD
scipy.linalg.svd で分解し、rank を 1 から 50 まで変えて復元すると、ぼやけた画像から細部まで戻る様子を確かめます。標準化したデータ行列に SVD をかけると \(V\) の列が PCA の主成分と一致するので、PCA の内部計算としても、推薦システムや LSA の基盤としても使われます。- 主成分分析(PCA) の概念を先に学ぶと理解がスムーズです
直感 #
グレースケールの画像は、ピクセルの明るさを並べた 163 × 372 の行列です。この行列を「ぼやけた基本パターン」の重ね合わせとして表し直すのが SVD です。1 枚目のパターン \(u_1 v_1^\top\) は文字のだいたいの位置を表す大きな濡れ跡のような絵で、2 枚目、3 枚目と足していくほど線が細く見えてきます。各パターンにどれだけの重みを掛けるかが特異値 \(\sigma_i\) で、重みの大きい順に 10 枚ほど残せば、163 × 372 = 60,636 個の数値を 10 × (163 + 372 + 1) = 5,360 個で近似できます。
何が起きているか(ステップで見る) #
コードを読む前に、この手法が図の上で何をしているかを追ってみましょう。「再生」を押すか、スライダーを動かすと 1 手順ずつ進みます。
見るポイント:点を軸に射影した散らばりが最大の向きが第 1 主成分。情報を最も失わない 1 本の軸。SVD の第 1 特異ベクトル \(v_1\) は、標準化したデータではこの第 1 主成分と同じ向きになる。
詳細な解説 #
1. 直感:行列を「基本パターン」に分解する #
SVD は、データ行列 \(A\) を「基底ベクトル」と「重み」に分解して表す方法です。画像なら「ぼやけた基本的なパターン」を重ね合わせて元画像を作るイメージで、推薦システムのユーザー × アイテム行列なら「好みのパターン」の重ね合わせになります。特異値が大きい要素から順に「情報量の多いパターン」を表すので、上から何枚残すかが圧縮率を決めます。
2. 数式でみる SVD #
任意の行列 \(A \in \mathbb{R}^{m \times n}\) は、3 つの行列の積に分解できます。
$$ A = U \Sigma V^\top $$\(U \in \mathbb{R}^{m \times m}\) は左特異ベクトルを列に持つ直交行列で、画像なら「縦方向のパターン」です。\(\Sigma \in \mathbb{R}^{m \times n}\) は特異値を対角成分にもつ対角行列で、各パターンの重みです。\(V \in \mathbb{R}^{n \times n}\) は右特異ベクトルを列に持つ直交行列で、画像なら「横方向のパターン」です。特異値 \(\sigma_1 \ge \sigma_2 \ge \dots\) は「データの強いパターン」順に並ぶので、上位の特異値だけ残すと「低ランク近似」ができます。
3. 実験用のデータ(画像) #
「実験」という文字画像をグレースケール化し、163 × 372 の行列として扱います。
| |
4. 特異値分解を実行 #
画像を numpy 配列にして linalg.svd にかけ、3 つの行列の形を表示します。
| |
A: (163, 372), U: (163, 163), Σ:(163,), V^T:(372, 372)
5. 低ランク近似で画像を復元 #
特異値の上位 rank 個だけを残して \(U_k \Sigma_k V_k^\top\) を計算し、rank を 1 から 50 まで変えて復元画像を並べます。
| |
ランクが大きいほど細部が復元され、ランクが小さいほどぼやける。
6. 特異ベクトルの解釈 #
各特異値に対応する \(U, V\) の列は「画像のパターン」を表しています。\(u_1\) は「最も大きな構造」、\(u_2\) は「補助的な構造」です。次のコードは、1 番目から 5 番目までの成分 \(\sigma_i u_i v_i^\top\) を 1 枚ずつ描き、その合計も表示します。
| |
7. 実務での応用 #
SVD の応用は 4 つの分野で定番です。画像圧縮では、上の例のように rank=20 程度の少数の特異値だけで近似して容量を削減します。ノイズ除去では、小さい特異値はノイズに対応することが多いので、それを 0 にすると画像や信号のざらつきが減ります。推薦システムでは、ユーザー × アイテムの評価行列を分解し、\(U\) と \(V\) の行を「潜在的な好み」のベクトルとして使います。自然言語処理では LSA(潜在意味解析)が単語 × 文書行列を分解します。同じ話題の単語が LSA の座標上で近くに集まるのが利点です。
特異値 \(\sigma_k\) と \(\sigma_{k+1}\) が似た大きさの場合、どこで打ち切るかによって結果が大きく変わります。累積寄与率(上位k個の特異値の二乗和 / 全特異値の二乗和)を確認し、80〜90%を目安にランクを決めてください。また、欠損値(NaN)がある行列にはそのまま適用できないため、事前に補完が必要です。
大規模データにはsklearn.decomposition.TruncatedSVDを使うとメモリ効率よく上位k成分だけを計算できます。テキストデータの潜在意味解析(LSA)では、TF-IDF行列にTruncatedSVDを適用するのが定番です。
まとめ #
SVD は任意の行列を直交行列 \(U\)・特異値の対角行列 \(\Sigma\)・直交行列 \(V^\top\) の積に分解し、特異値の大きい順にデータの強いパターンを取り出します。163 × 372 の文字画像では rank=5 で文字が読め、rank=20 で元とほぼ同じになりました。上位の特異値だけを残す低ランク近似で、圧縮やノイズ除去ができます。標準化したデータ行列に SVD をかけると \(V\) の列が PCA の主成分と一致するので、scikit-learn の PCA も内部では SVD を使っています。打ち切るランクは特異値の 2 乗和の累積寄与率 80〜90% を目安に決め、大規模な疎行列には TruncatedSVD を使います。
発展:SVDと他手法との関係 #
低ランク近似の最適性として、ランク \(k\) の近似 \(A_k\) は次のように表せ、同じランクのどんな行列よりも Frobenius ノルムで元の \(A\) に近い(Eckart–Young の定理)ことが知られています。
$$ A_k = \sum_{i=1}^k \sigma_i u_i v_i^\top $$PCA との関係では、データ行列を標準化して SVD を行えば \(V\) の列が PCA の主成分と一致し、特異値の 2 乗を \(n\) で割ったものが固有値(各主成分の分散)になります。計算の工夫として、数万 × 数万の大規模データでは全成分を求めるのではなく、ランダム化 SVD や TruncatedSVD で上位 \(k\) 成分だけを効率よく計算します。
- 主成分分析(PCA) — SVD を活用した次元削減
- Kernel-PCA — カーネル行列の固有値分解で非線形構造へ広げる拡張
- 主成分回帰 — SVD/PCAの回帰応用
ランクと SVD #
スライダーで打ち切りランク n_components を 2, 5, 10, 20, 40 と変えると、手書き数字(10 クラス)の 2D 射影と保持される分散の割合がどう変わるかを確認できます。2 成分で全分散の 24%、5 で 47%、10 で 67%、20 で 85%、40 で 98% を保持し、20 付近で 90% の目安に届きます。