1. 特異値分解とは?
行列 A を
$$
A = U \Sigma V^{\top}
$$
という3つの部品に分ける分解のことです。
イメージでいうと:
- V … 入力ベクトルを「どの方向に見るか」を決める回転
- Σ … その方向にどれくらい「伸ばす/縮める」かを決める倍率(特異値)
- U … 伸ばした後に「最終的にどの方向に置き直すか」を決める回転
2. 各記号の役割
(1) Σ(シグマ)
伸び縮みの倍率だけが並んでいる行列。
対角成分に「特異値」という正の数が並びます。
この数字が「Aがどれくらい引き延ばすか」を表します。
例:
$$
\Sigma =
\begin{pmatrix}
3 & 0 & 0 \
0 & 1 & 0
\end{pmatrix}
$$
この場合、「ある方向には3倍、別の方向には1倍で変わらない」ことを意味します。
(2) V(ブイ)
入力側の座標軸をどう回すかを決める行列。
入力ベクトルを「特異値を測りやすい向き」に並べ替える役割があります。
イメージ:入力を「伸ばされる方向」と「そうでない方向」に合わせるための回転マップ。
(3) U(ユー)
出力側の座標軸をどう回すかを決める行列。
Σで伸ばされたベクトルを「最終的なAの出力の向き」に戻します。
イメージ:「伸ばした後、ゴールの方向に回す仕上げの変換」。
3. 特異値分解の例題
行列
$$
A =
\begin{pmatrix}
1 & 0 & 1 \\
-1 & 1 & 0
\end{pmatrix}
$$
を特異値分解して、
$$
A = U \Sigma V^{\top}
$$
の形にせよ。
手順
1. AA^T を計算
$$
A A^{\top} =
\begin{pmatrix}
1 & 0 & 1 \\
-1 & 1 & 0
\end{pmatrix}
\begin{pmatrix}
1 & -1 \\
0 & 1 \\
1 & 0\end{pmatrix}
=
\begin{pmatrix}
2 & -1 \\
-1 & 2
\end{pmatrix}
$$
2. 固有値を求める
$$
\det
\begin{pmatrix}
2-\lambda & -1 \\
-1 & 2-\lambda
\end{pmatrix}
= (2-\lambda)^2 – 1
= \lambda^2 – 4\lambda + 3
= 0
$$
したがって固有値は
$$
\lambda_1 = 3, \quad \lambda_2 = 1
$$
3. 特異値
特異値は固有値の平方根:
$$
\sigma_1 = \sqrt{3}, \quad \sigma_2 = 1
$$
よって
$$
\Sigma =
\begin{pmatrix}
\sqrt{3} & 0 & 0 \\
0 & 1 & 0
\end{pmatrix}
$$
U の計算
AA^T の固有ベクトルを求める。
- λ = 3 のとき
$$
u_1 = \frac{1}{\sqrt{2}}
\begin{pmatrix} 1 \ -1 \end{pmatrix}
$$ - λ = 1 のとき
$$
u_2 = \frac{1}{\sqrt{2}}
\begin{pmatrix} 1 \ 1 \end{pmatrix}
$$
したがって
$$
U =
\begin{pmatrix}
\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\
-\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}}
\end{pmatrix}
$$
V の計算
まず、特異値が √3 のとき:
$$
v_1 = \frac{1}{\sigma_1} A^{\top} u_1
= \frac{1}{\sqrt{6}}
\begin{pmatrix}
2 \ -1 \ 1
\end{pmatrix}
$$
次に、特異値が 1 のとき:
$$
v_2 = \frac{1}{\sigma_2} A^{\top} u_2
= \frac{1}{\sqrt{2}}
\begin{pmatrix}
0 \ 1 \ 1
\end{pmatrix}
$$
最後に、残り1列は直交補空間から求めると:
$$
v_3 = \frac{1}{\sqrt{3}}
\begin{pmatrix}
-1 \ -1 \ 1
\end{pmatrix}
$$
よって
$$
V =
\begin{pmatrix}
\frac{2}{\sqrt{6}} & 0 & -\frac{1}{\sqrt{3}} \\
-\frac{1}{\sqrt{6}} & \frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{3}} \\
\frac{1}{\sqrt{6}} & \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{3}}
\end{pmatrix}
$$
まとめ
- 特異値行列:
$$
\Sigma =
\begin{pmatrix}
\sqrt{3} & 0 & 0 \\
0 & 1 & 0
\end{pmatrix}
$$ - 左特異ベクトル行列:
$$
U =
\begin{pmatrix}
\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\
-\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}}
\end{pmatrix}
$$ - 右特異ベクトル行列:
$$
V =
\begin{pmatrix}
\frac{2}{\sqrt{6}} & 0 & -\frac{1}{\sqrt{3}} \\
-\frac{1}{\sqrt{6}} & \frac{1}{\sqrt{2}} & -\frac{1}{\sqrt{3}} \\
\frac{1}{\sqrt{6}} & \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{3}}
\end{pmatrix}
$$
Pythonで特異値分解を計算する
NumPy の np.linalg.svd を使うと、上の手計算と同じ結果を数行で確認できます。
import numpy as np
A = np.array([[1, 0, 1],
[-1, 1, 0]], dtype=float)
# full_matrices=True で U: 2x2, S: (2,), Vt: 3x3 が返る
U, S, Vt = np.linalg.svd(A, full_matrices=True)
print("U =\n", U)
print("特異値 σ =", S) # [sqrt(3), 1] と一致
print("Vᵀ =\n", Vt)
# 復元チェック: A ≒ U Σ Vᵀ
Sigma = np.zeros_like(A)
Sigma[:len(S), :len(S)] = np.diag(S)
print("復元誤差:", np.linalg.norm(A - U @ Sigma @ Vt)) # ~ 1e-15
固有値分解との関係を Python で確認
特異値分解は、AᵀA の固有値分解と密接な関係があります。AᵀA の固有値の平方根 = A の特異値、という関係を NumPy で確かめます。
# AᵀA の固有値 = 特異値の二乗
eigvals, _ = np.linalg.eigh(A.T @ A)
print("AᵀA の固有値:", np.sort(eigvals)[::-1]) # [3, 1, 0]
print("特異値の二乗:", S ** 2) # [3, 1]
応用:低ランク近似による画像圧縮の入り口
特異値分解の最大の応用は低ランク近似です。上位 k 個の特異値だけを残すと、行列を最小二乗の意味で最良の rank-k 行列で近似できます。画像圧縮・推薦システム・次元削減 (PCA) の基礎になります。
def low_rank_approx(A, k):
"""上位 k 個の特異値で A を近似する"""
U, S, Vt = np.linalg.svd(A, full_matrices=False)
return U[:, :k] @ np.diag(S[:k]) @ Vt[:k, :]
sklearn の PCA との関係 — SVD は PCA の内部実装
機械学習で頻出する PCA(Principal Component Analysis、主成分分析)は、教科書では「共分散行列の固有値分解」と紹介されますが、実装上は 「中心化したデータ行列の SVD」として計算するのが標準です。scikit-learn の sklearn.decomposition.PCA も内部で SVD を呼んでおり、svd_solver パラメータで 'full' / 'randomized' / 'arpack' / 'auto' の4種類から計算アルゴリズムを選べます。
「PCA が SVD で計算できる」ことを iris データセットで確認するコードがこちらです。sklearn.PCA の結果と、numpy.linalg.svd を直接呼んだ結果が機械精度で一致することを確かめます。
import numpy as np
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
X = load_iris().data # 150サンプル × 4特徴量
X_centered = X - X.mean(axis=0) # 中心化(PCA の前提)
# 方法1: sklearn.PCA(内部で SVD が走る)
pca = PCA(n_components=2, svd_solver="full")
scores_sklearn = pca.fit_transform(X_centered)
# 方法2: numpy.linalg.svd で直接
U, S, Vt = np.linalg.svd(X_centered, full_matrices=False)
scores_svd = U[:, :2] * S[:2] # = X_centered @ Vt[:2].T
# SVD は U,V の符号がペアで反転しても等価。符号を吸収して比較
sign = np.sign(scores_sklearn[0] * scores_svd[0])
print("最大差分:", np.abs(scores_sklearn - scores_svd * sign).max())
# → 1e-14 オーダー(機械精度)で一致
SVD は U と V の符号がペアで反転しても等価なため、sklearn と numpy で符号規約が違う場合があります。それを吸収すれば、両者の主成分スコアは機械精度で一致します。「sklearn の PCA を呼んでも実体は SVD」と理解しておくと、内部の挙動や警告メッセージの意味が掴みやすくなります。
svd_solver の使い分けは次の通りです。データ規模が小〜中なら 'full'(scipy.linalg.svd による厳密 SVD)、サンプル数・特徴量数とも500を超え主成分も上位だけ欲しいなら 'randomized'(乱択 SVD、Halko et al. 2011)、疎行列なら 'arpack'、判断を任せたいなら 'auto'(デフォルト、sklearn 内部のヒューリスティックで自動選択)です。
実応用編:投資データへの応用
本記事の SVD は、データ分析の基礎工事です。投資シリーズ #26(2026-06-30 公開予定)では、CAN-SLIM 銘柄群 × 財務特徴量10指標に PCA を適用し、業種クラスタの可視化と銘柄相関分析を実装します。本記事で学んだ svd_solver の使い分けや「PCA = 中心化データの SVD」という関係が、実際の銘柄スクリーニングでどう活きるかを示す実例として、E資格の数学と投資実装の橋渡しになります。
E資格頻出ポイント
- 特異値は 非負(固有値と違って負になることはない)
- 行列の 2-ノルム = 最大特異値、Frobenius ノルム = 特異値の二乗和の平方根
- PCA は中心化したデータ行列の SVD と等価(共分散行列の固有値分解と同じ結果)
- 正方行列でなくても適用できる点が固有値分解との最大の違い
コメント