本日は機械学習を学ぶ上では、逃げては通れない固有値分解、特異値分解について解説します。
固有値分解って聞いたことはあるけど、、、やり方は、、
なんで機械学習に特異値分解が必要なの??
本記事ではそのような疑問に回答します。
そもそもなぜ固有値、特異値分解が機械学習を学ぶ上で必要となってくるのかその背景も踏まえて説明しますので、ぜひ参考にしてください。
E検定では数学の問題も出題されます、固有値/特異値分解もその出題範囲のひとつです。
やり方を覚えてしまえば簡単ですので、ぜひ本記事を参考に身に付けていってください。
Pythonでの固有値分解/特異値分解を行う方法
PythonではNumpyのlinalg.eig()関数を用いることで固有値分解、同じくNumpyのlinalg.svd()関数で特異値分解ができます。
でもそもそも固有値分解と特異値分解ってなんなん?と思う方が大半かと思います。
生活する上では全く不要ですが、機械学習を学ぶ上ではまずは定義をしっかり理解しておきましょう!
固有値分解の定義
まずは固有値分解の定義を説明する前に固有値、固有ベクトルの定義について確認しておきましょう!
固有値 / 固有ベクトルの定義
n次正方行列\(A\)に対して
$$\large{A\nu = \lambda\nu}$$
を満たすようなスカラー(*1)\(\lambda\)を固有値、非零ベクトル\(\nu\)を固有ベクトルと呼びます。
(*1) スカラー : 「大きさのみで表され、方向をもたない量」つまりベクトルではなく単なる数字
この固有値、固有ベクトルをもとに定義される2次正方行列の固有値分解の定義は以下です。
固有値分解の定義
2次正方行列\(A\)の固有値\(\lambda\)が\(\lambda_1\)、\(\lambda_2\)である場合、これらを対角成分に持つ行列\(D\)
$$D=\begin{pmatrix}
\lambda_1 & 0 \\
0 & \lambda_2
\end{pmatrix}$$
と対応する固有ベクトルを列として並べた行列
$$P = (\nu_1 \ldots\nu_2) $$
に対して、\(A = PDP^{-1}\)が成立する。これを行列Aの「固有値分解」、または「対角化」と呼びます。
次元数が増えれば同様に行列\(D\)、\(P\)の次元も増えると理解ください。
Numpyを用いた固有値分解
それでは実際にNumpyのlinalg.eig()関数を用いて固有値分解を行ってみましょう。
使い方自体は非常に簡単ですので、ぱっと覚えてしまいましょう!
以下のコードでは2次の正方行列
$$A=\begin{pmatrix}
5 & 2 \\
2 & 5
\end{pmatrix}$$
に関して固有値分解を行っています。
# linalgモジュールはLAとしてimportする
import numpy as np
import numpy.linalg as LA
#2次正方行列Aを定義する
a = np.array([[5, 2],[2, 5]])
# 2 次正方行列 Aの固有値、固有ベクトルPを計算する
l, p = LA.eig(a)
print("固有値")
print(l) # 固有値
print("固有ベクトル P ")
print(p) # 固有ベクトル(正規化済)
#対角行列D、Pの逆行列P-1を定義
d = np.array([[l[0],0],[0,l[1]]])
pinv = LA.inv(p)
#固有値分解の確認(P*D*P-1) 行列Aが算出される
print("固有値分解 確認 A = P x D x P-1")
print(np.dot(np.dot(p,d),pinv))
固有値
[7. 3.]
固有ベクトル P
[[ 0.70710678 -0.70710678]
[ 0.70710678 0.70710678]]
固有値分解 確認 A = P x D x P-1
[[5. 2.]
[2. 5.]]
固有値分解にて2次正方行列\(A\)が算出されました!
固有値分解で行列Aのn乗計算が抜群にやりやすくなるね!
特異値分解の定義
同じようにまず特異値分解を定義する前に特異値、特異ベクトルの定義について確認しておきましょう!
特異値、特異ベクトルの定義
任意のゼロ行列ではない\(m \times n\)行列\(A\)に対して
$$A\nu = \sigma u, A^{\mathrm{T}}u = \sigma\nu $$
を満たすような正の数\(\sigma\)を特異値、m次元ベクトルuを左特異ベクトル、n次元ベクトル\(\nu\)を右特異ベクトルと呼びます。
ただし、\(\sigma\) > 0 かつ\(u\)、\(\nu\)はともにゼロベクトルではないことが前提です。
次は特異値分解とは何か理解していきましょう!
特異値分解
特異値、特異ベクトルの定義式から\(A^{\mathrm{T}}A\nu = \sigma_2 u, A A^{\mathrm{T}}u = \sigma_2\nu\)が得られるので、
行列\(A^{\mathrm{T}}A\)と\(A A^{\mathrm{T}}\)の固有値、固有ベクトルを求めることで、Aの特異値、および左右の特異ベクトルを計算できます。
このようにして求められた特異値を大きい順に(i,i) で成分に並べ、その他の成分を0で埋めた\(m \times n\)行列\(\Sigma\)と、左特異ベクトルを列として横に並べた\(m\)次正方行列\(U\)、右特異ベクトルを列として横に並べた\(n\)次正方行列\(V\)を用いて、
$$A = U\Sigma V^{\mathrm{T}}$$
と書けます。
この行列Aの分解をAの特異値分解と呼びます。
Numpyを用いた特異値分解
それでは同じようにNumpyのlinalg.svd()関数を用いて特異値分解を行ってみましょう。
以下のコードでは固有値分解と同様2次の正方行列
$$A=\begin{pmatrix}
5 & 2 \\
2 & 5
\end{pmatrix}$$
に関して特異値分解を行っています。
# linalgモジュールはLAとしてimportする
import numpy as np
import numpy.linalg as LA
#2次正方行列Aを定義する
a = np.array([[5, 2],[2, 5]])
# 2 次正方行列 U,Σ,V(転置行列)を求める
U, S, Vt = LA.svd(a, full_matrices=True)
print("左特異値ベクトルを列として並べた2次正方行列 U")
print(U)
print("特異値以外を0で埋めた2次正方行列 Σ")
print(np.diag(S))
print("右特異値ベクトルを列として並べた2次正方行列 V")
print(Vt)
#特異値分解の確認(U*Σ*Vt) 行列Aが算出される
print("固有値分解 確認 A = U x Σ x Vt")
print(np.dot(np.dot(U,np.diag(S)),Vt))
左特異値ベクトルを列として並べた2次正方行列 U
[[-0.70710678 -0.70710678]
[-0.70710678 0.70710678]]
特異値以外を0で埋めた2次正方行列 Σ
[[7. 0.]
[0. 3.]]
右特異値ベクトルを列として並べた2次正方行列 V
[[-0.70710678 -0.70710678]
[-0.70710678 0.70710678]]
固有値分解 確認 A = U x Σ x Vt
[[5. 2.]
[2. 5.]]
特異値分解にて2次正方行列\(A\)が算出されました!
固有値分解同様Numpyの関数で簡単に計算できるね!
機械学習における固有値/特異値分解のメリット
固有値分解、特異値分解の機械学習におけるメリットを以下に示します。
固有値/特異値分解で多次元行列の次元削減効果を得ることが最も機械学習で重要視される点です。
固有値分解のメリット
- 次元削減効果が期待できる。
算出された固有値は大きい値ほど行列全体に与える影響が大きい。
したがって、値の小さい固有値を無視することで、次元削減を行うことができる。
また次元削減することで、計算量を下げることもできる。 - 行列Aの階乗計算が容易になる。
\(A = PDP^{-1}\)の固有値分解の形状からも分かるように\(A^{n}\)の計算が楽になります。
特異値分解のメリット
- 行列Aが正方行列でなくても、固有値分解のメリットを享受できる。
固有値分解がn次正方行列にのみ対応するのに対して、特異値分解ではm x n 行列にも適応ができます。
特に深層学習においては次元削減は重要だね!
まとめ
本記事ではNumpyを用いた固有値分解、特異値分解について紹介しました。
定義を理解しても具体的に機械学習プロジェクト上で使ってみないとどれだけメリットが得られるのかイメージがしづらいかもしれません。
とりあえず次元削減には固有値分解、特異値分解が重要なんだなぁと頭の隅に入れておきましょう!
それでは本日は以上です。
今日があなたのスタートの日。明るい未来に向けて一緒に頑張りましょう!
本記事でも紹介したNumpyの基礎やオンライン上でのコーディング練習におススメなのが、
Data Campです。以下の記事でも紹介しているのでぜひ試してみてくださいね!