特異値分解 “Singular-Value Decomposition” は、行列の分解の中で、おそらくもっとも機械学習への応用範囲が広いものです。なぜなら固有値分解などと比べて、安定して解を求めることができるからです。そのためコンピュータ・サイエンス関連でも、データの次元削減やファイルの圧縮、ノイズの除去などさまざまなアプリケーションに使われています。
当ページでわかること
- 特異値分解とは
- 特異値分解のやり方
- Pythonで特異値分解
特異値分解とは
特異値分解は、以下のように行列を 3 つの構成要素にまで削減する行列分解方法です。なお、ここでは簡単化のために実数の行列を扱い、複素数の行列は無視することにします。
\[
A = U \Sigma V^T
\]
\(A\) は \(m \times n\) の行列です。\(U\) は \(m \times m\) の直交行列です。\(\Sigma\) は \(m \times n\) の対角行列です。そして \(V^T\) は \(n \times n\) の直交行列(ユニタリー行列)です。\(U\) と \(V^T\) は直交行列になっています。
以下が特異値分解の例です。
\[\begin{eqnarray}
\overset{A}{
\begin{pmatrix}
1 & 2 \\
3 & 4
\end{pmatrix}
}
=
\overset{U}{
\begin{pmatrix}
-0.40 & -0.91 \\
-0.91 & 0.40
\end{pmatrix}
}
\overset{\Sigma}{
\begin{pmatrix}
5.46 & 0 \\
0 & 0.37
\end{pmatrix}
}
\overset{V^T}{
\begin{pmatrix}
-0.58 & -0.82\\
0.82 & -0.58
\end{pmatrix}
}
\end{eqnarray}\]
\(\Sigma\) 行列の対角線の値をもともとの行列 \(A\) の特異値と言います。そして行列 \(U\) の列を、行列 \(A\) の左特異ベクトルと言います。同様に行列 \(V^T\) の列を、行列 \(A\) の右特異ベクトルと言います。
これが特異値分解です。
なお特異値分解には次のような性質があります。
- 行列 \(\Sigma\) は必ず 1 つに定まるが、直交行列 \(U\) と \(V\) はそうとは限らない。
- 特異値の数は、もともとの行列 \(A\) のランクと一致する。
正方行列でのみ可能な固有値分解と異なり、特異値分解はすべての長方行列で可能なため固有値分解より安定しており、そのためコンピューターのアプリケーションでは、特異値分解が広く使われています。具体的には、逆行列のような行列演算、機械学習における次元削減、最小二乗法、画像圧縮、データのノイズ削減などです。
なお元々の行列 \(A\) が対称行列のとき、その行列の固有値と特異値は一致します。
特異値分解のやり方
特異値分解の手計算の方法はかなり面倒です。『特異値分解の計算方法を手順ごとにまとめてみた』では、おおよそ以下のように手順がまとめられています。
- \(U, \Sigma, V\) の行列のサイズを把握する
- 転置行列 \(A^T\) を求める
- 行列積 \(AA^T\) を求める
- 固有方程式を解いて固有値を求める
- 固有値から固有ベクトルを求める
- 固有値と固有ベクトルから行列 \(V\) の固有ベクトルを求める
Pythonで特異値分解
Python では NumPy の linealg.svd()
関数を使うことで簡単に特異値分解を行うことができます。
import numpy as np
A = np.array([
[1,2],
[3,4],])
print(A)
u, s, vt = np.linalg.svd(A)
print(u)
print(s)
print(vt)
print(u @ np.diag(s) @ vt)