Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

応用数学 ch6メモ(主軸変換とその応用:主成分分析、特異値分解)

6.1 主成分分析

主軸変換

ベクトルxxを単位ベクトルuuの延長上の線llに射影した長さは、それらの内積

(u1,xα)=u1xαcosθα=xαcosθα\left(\boldsymbol{u}_1, \boldsymbol{x}_\alpha\right)=\left\|\boldsymbol{u}_1\right\| \cdot\left\|\boldsymbol{x}_\alpha\right\| \cos \theta_\alpha=\left\|\boldsymbol{x}_\alpha\right\| \cos \theta_\alpha

に等しい

原点OOを平均とするNN{xα}\{x_{\alpha} \}ll上に射影した長さの平均は常に零である

1Nα=1N(u1,xα)=(u1,1Nα=1Nxα)=(u1,0)=0\frac{1}{N} \sum_{\alpha=1}^N\left(u_1, x_\alpha\right) =\left(u_1, \frac{1}{N} \sum_{\alpha=1}^N x_\alpha\right) =\left(u_1, 0 \right) = 0

原点OOを平均とするNN{xα}\{x_{\alpha} \}ll上に射影した長さの 二乗の平均

S=1Nα=1N(u1,xα)2=1Nα=1Nu1xαxαu1=u1(1Nα=1Nxαxα)u1\begin{aligned} S &= \frac{1}{N} \sum_{\alpha=1}^N\left(\boldsymbol{u}_1, \boldsymbol{x}_\alpha\right)^2\\ &= \frac{1}{N} \sum_{\alpha=1}^N \boldsymbol{u}_1^{\top} \boldsymbol{x}_\alpha \boldsymbol{x}_\alpha^{\top} \boldsymbol{u}_1\\ &= \boldsymbol{u}_1^{\top}\left(\frac{1}{N} \sum_{\alpha=1}^N \boldsymbol{x}_\alpha \boldsymbol{x}_\alpha^{\top}\right) \boldsymbol{u}_1\\ \end{aligned}

となる。このとき、

V:=1Nα=1NxαxαV:= \frac{1}{N} \sum_{\alpha=1}^N \boldsymbol{x}_\alpha \boldsymbol{x}_\alpha^{\top}

を分散共分散行列とよぶ。

分散SSを最大化する方向u1u_1主方向 と呼ぶ。

共分散行列Vは半正値対称行列

(x,Vx)=(x,(1Nα=1Nxαxα)x)=1Nα=1N(x,xαxαx)=1Nα=1N(x,xα)(xα,x)=1Nα=1N(x,xα)20\begin{aligned} (\boldsymbol{x}, \boldsymbol{V} \boldsymbol{x}) & =\left(\boldsymbol{x},\left(\frac{1}{N} \sum_{\alpha=1}^N \boldsymbol{x}_\alpha \boldsymbol{x}_\alpha^{\top}\right) \boldsymbol{x}\right)=\frac{1}{N} \sum_{\alpha=1}^N\left(\boldsymbol{x}, \boldsymbol{x}_\alpha \boldsymbol{x}_\alpha^{\top} \boldsymbol{x}\right) \\ & =\frac{1}{N} \sum_{\alpha=1}^N\left(\boldsymbol{x}, \boldsymbol{x}_\alpha\right)\left(\boldsymbol{x}_\alpha, \boldsymbol{x}\right)=\frac{1}{N} \sum_{\alpha=1}^N\left(\boldsymbol{x}, \boldsymbol{x}_\alpha\right)^2 \geq 0 \end{aligned}

NN{xα}\{x_{\alpha} \}の主方向はVの最大固有値λ1\lambda_1に対する固有ベクトルu1u_1の方向であり、その方向の分散はλ1\lambda_1である

主軸を座標系にとるとその座標系では共分散行列はどうなるか

元の座標系の点 xα\boldsymbol{x}_\alpha は,新しい座標系では xα=Uxα\boldsymbol{x}_\alpha^{\prime}=\boldsymbol{U}^{\top} \boldsymbol{x}_\alpha と書ける.その共分散行列は次のようになる。

V=1Nα=1Nxαxα=1Nα=1N(Uxα)(Uxα)=1Nα=1NUxαxαU=U(1Nα=1Nxαxα)U=UVU=(λ1λ2λn)\begin{aligned} \boldsymbol{V}^{\prime} &=\frac{1}{N} \sum_{\alpha=1}^N \boldsymbol{x}_\alpha^{\prime} \boldsymbol{x}_\alpha^{\prime \top}\\ &=\frac{1}{N} \sum_{\alpha=1}^N\left(\boldsymbol{U}^{\top} \boldsymbol{x}_\alpha\right)\left(\boldsymbol{U}^{\top} \boldsymbol{x}_\alpha\right)^{\top}\\ &=\frac{1}{N} \sum_{\alpha=1}^N \boldsymbol{U}^{\top} \boldsymbol{x}_\alpha \boldsymbol{x}_\alpha^{\top} \boldsymbol{U}\\ &=\boldsymbol{U}^{\top}\left(\frac{1}{N} \sum_{\alpha=1}^N \boldsymbol{x}_\alpha \boldsymbol{x}_\alpha^{\top}\right) \boldsymbol{U}\\ &=\boldsymbol{U}^{\top} \boldsymbol{V} \boldsymbol{U}\\ &=\left(\begin{array}{cccc} \lambda_1 & & & \\ & \lambda_2 & & \\ & & & \\ & & \ddots & \\ & & & \lambda_n \end{array}\right) \end{aligned}

すなわち、共分散行列VVの固有値を対角要素とする対角行列になる。

このように主軸方向に新しい座標系をとることを 主軸変換 という。

6.2 画像の表現

画像の展開

m×mm\times m画素の大きさの画像があるとし、(i,j)(i,j)画素の濃淡値がfijf_{ij}の画像をfij=(fij)\boldsymbol{f}_{ij} = (f_{ij})とする。

画像の内積とノルム

画像fij=(fij)\boldsymbol{f}_{ij} = (f_{ij})gij=(gij)\boldsymbol{g}_{ij} = (g_{ij})の内積と画像fij=(fij)\boldsymbol{f}_{ij} = (f_{ij})のノルムを次のように定義する

(f,g)=i,j=1mfijgij,f=(f,f)=i,j=1mfij2(\boldsymbol{f}, \boldsymbol{g})=\sum_{i, j=1}^m f_{i j} g_{i j}, \quad\|\boldsymbol{f}\|=\sqrt{(\boldsymbol{f}, \boldsymbol{f})}=\sqrt{\sum_{i, j=1}^m f_{i j}^2}

内積が0となる2つの画像は互いに直交するという

画像の基底

m2m^2 個の画素を持つ任意の画像がある m2m^2 個の画像 e1,e2,,em2\boldsymbol{e}_1, \boldsymbol{e}_2, \ldots, \boldsymbol{e}_{m^2} の線形結合でただ一通りに表せるとき,{ei}\left\{e_i\right\} を基底と呼び,各 eie_i を基底画像と呼ぶ。 これらが互いに直交するとき,その基底を直交基底と呼び,さらに各画像の ノルムがすべて 1 のとき正規直交基底と呼ぶ.

画像の展開

一部の基底画像によって

fc1e1+c2e2++cnen,n<m2\boldsymbol{f} \approx c_1 \boldsymbol{e}_1+c_2 \boldsymbol{e}_2+\cdots+c_n \boldsymbol{e}_n, \quad n<m^2

と近似することを 展開 とよぶ。

近似の尺度として二乗誤差fi=1nciei2\left\|\boldsymbol{f}-\sum_{i=1}^n c_i \boldsymbol{e}_i\right\|^2を用いると、各係数cic_i

ci=(f,ei),i=1,,nc_i=\left(\boldsymbol{f}, \boldsymbol{e}_i\right), \quad i=1, \ldots, n
証明

この誤差関数を最小化する cic_i を求める:

E(c1,,cn)=fi=1nciei2E\left(c_1, \ldots, c_n\right)=\left\|f-\sum_{i=1}^n c_i e_i\right\|^2

これは内積を用いて次のように展開できる:

E=(fi=1nciei,fj=1ncjej)=(f,f)2i=1nci(f,ei)+i=1nj=1ncicj(ei,ej)\begin{gathered} E=\left(f-\sum_{i=1}^n c_i e_i, f-\sum_{j=1}^n c_j e_j\right) \\ =(f, f)-2 \sum_{i=1}^n c_i\left(f, e_i\right) + \sum_{i=1}^n \sum_{j=1}^n c_i c_j\left(e_i, e_j\right) \end{gathered}

ここで基底が正規直交なので:

(ei,ej)={1i=j0ij\left(e_i, e_j\right)= \begin{cases}1 & i=j \\ 0 & i \neq j\end{cases}

よってi=1nj=1ncicj(ei,ej)\sum_{i=1}^n \sum_{j=1}^n c_i c_j\left(e_i, e_j\right)の項は i=1nci2\sum_{i=1}^n c_i^2 となり、したがって誤差関数は

E=f22i=1nci(f,ei)+i=1nci2E=\|f\|^2-2 \sum_{i=1}^n c_i\left(f, e_i\right)+\sum_{i=1}^n c_i^2

となる。これを各 ckc_k について偏微分してゼロとおくと

Eck=2(f,ek)+2ck=0ck=(f,ek)\frac{\partial E}{\partial c_k}=-2\left(f, e_k\right)+2 c_k=0 \quad \Rightarrow \quad c_k=\left(f, e_k\right)

画像の基底

自明な基底

m×mm \times m 画像の (i,j)(i, j) 画素のみが 1 で,残りの画素がすべて 0 である画像を eij\boldsymbol{e}_{i j} とすると,任意の画像 f=(fij)\boldsymbol{f}=\left(f_{i j}\right) は次のように {eij}\left\{\boldsymbol{e}_{i j}\right\} の線形結合で表せる.

f=i,j=0m1fijeij\boldsymbol{f}=\sum_{i, j=0}^{m-1} f_{i j} e_{i j}

この m2m^2 枚の画像 {eij},i,j=0,,m1\left\{\boldsymbol{e}_{i j}\right\}, i, j=0, \ldots, m-1 を自明な基底という.しかし,各 eij\boldsymbol{e}_{i j} は 1 点のみが光る画像であり,画像としての意味はない.

アダマール変換の基底

次のような基底を考える.

  1. すべての画素が 1 の画像を考える.

  2. 画像を (m/2)×(m/2)(m / 2) \times(m / 2) 画素の 4 枚の小画像に分割する

  3. その内の 2 枚のすべて の画素を 1 ,残りの 2 枚のすべての画素を -1 とする。ただし,すでに作った画像と同じ,または 1 と -1 を反転すると同じになるものは除く

  4. 各々 の (m/2)×(m/2)(m / 2) \times(m / 2) 小画像をさらに 4 枚の (m/4)×(m/4)(m / 4) \times(m / 4) 小画像に分割

  5. 以下同様にする

このような基底による画像の展開を アダマール変換という

別の言い方

アダマール変換(Hadamard Transform)とは、 「入力ベクトルに対して、非常にシンプルな +1 と -1 のみを使った線形変換」

  • 行列要素がすべて +1 か -1(ゼロはない)

  • 直交行列(行同士・列同士が直交している)

  • フーリエ変換の簡易版ともいえる(周波数解析に近い)

from scipy.linalg import hadamard

print(hadamard(2))
[[ 1  1]
 [ 1 -1]]
Source
import numpy as np
import matplotlib.pyplot as plt
from scipy.linalg import hadamard

# アダマール行列を作成(サイズは2のべき乗)
n = 4
H = hadamard(2**n)

# プロット
plt.figure(figsize=(3, 3))
plt.imshow(H, cmap='gray', interpolation='nearest')
plt.title(f"Hadamard Matrix (size {2**n}×{2**n})")
plt.show()
<Figure size 300x300 with 1 Axes>

離散コサイン変換の基底

次のように定義した基底 {ekl},k=0,1,,m1;l=0,1,,m1\left\{\boldsymbol{e}_{k l}\right\}, k=0,1, \ldots, m-1 ; l=0,1, \ldots, m-1 ,は正規直交基底である。

ekl=(2αkαlmcosπk(2p+1)2Ncosπl(2q+1)2N)\boldsymbol{e}_{k l}=\left(\frac{2 \alpha_k \alpha_l}{m} \cos \frac{\pi k(2 p+1)}{2 N} \cos \frac{\pi l(2 q+1)}{2 N}\right)

右辺のカッコの中は画像 ekl\boldsymbol{e}_{k l}(p,q)(p, q) 画素の値を表す.ただし,次のように置 いた。

αk={12k=01k0\alpha_k=\left\{\begin{array}{cc} \frac{1}{\sqrt{2}} & k=0 \\ 1 & k \neq 0 \end{array}\right.

この基底による展開を,画像の離散コサイン変換と呼ぶ.これは,式(4.79) の離散コサイン変換を x,yx, y の 2 方向に適用したものである。図 6.8 に 8×88 \times 8画像の場合の基底を示す.

画像の固有空間

アダマール変換や離散コサイン変換の基底画像は規則的な模様であり、画像としての意味はない

意味のある画像からの正規直交基底を作ることを考える

多数の顔写真 {fα},α=1,,N\left\{\boldsymbol{f}_\alpha\right\}, \alpha=1, \ldots, N があるとする。これらの平均をとれば、平均的な顔の画像

g0=1Nα=1Nfαg_0=\frac{1}{N} \sum_{\alpha=1}^N f_\alpha

が得られる。

また個々の画像と平均顔との差分

fα=fαg0f_\alpha^{\prime}=f_\alpha-g_0

をとれば、個々の画像の平均からの差異を意味する

もし個々の顔の差の代表的な特徴が見つかれば、fαf_\alpha^{\prime}はその画像の定数倍で近似できる。

例えば顔の縦横比が違いなら、額と顎の部分がプラスで、頬の両側がマイナスの画像を代表的な差画像g1g_1を作ることができる

そしてfαf_\alpha^{\prime}g1g_1の定数倍で最良に近似した画像との差画像をさらにべつの代表的な特徴g2g_2の定数倍で近似して・・・を繰り返していく。このときg1,g2,g3,g_1,g_2,g_3,\dotsが正規直交系であるなら、画像fαf_\alpha^{\prime}g1,g2,g3,\boldsymbol{g}_1, \boldsymbol{g}_2, \boldsymbol{g}_3, \ldotsに関して展開して次の表現が得られる

fα=g0+cα1g1+cα2g2+cα3g3+\boldsymbol{f}_\alpha=\boldsymbol{g}_0+c_{\alpha 1} \boldsymbol{g}_1+c_{\alpha 2} \boldsymbol{g}_2+c_{\alpha 3} \boldsymbol{g}_3+\cdots

各画像 fαf_\alpha の平均画像からの差 fαf_\alpha^{\prime} をよく表す画像が gg であるとすると, これは fαf_\alpha^{\prime}

fαCαg\boldsymbol{f}_\alpha^{\prime} \approx C_\alpha \boldsymbol{g}

の形で近似できるという意味である。

  1. 近似誤差を二乗誤差 fαCαg2\| \boldsymbol{f}_\alpha^{\prime} - C_\alpha \boldsymbol{g}\|^2 で表すとすると、この解は解析的に Cα=(fα,g)C_\alpha=\left(\boldsymbol{f}_\alpha^{\prime}, \boldsymbol{g}\right) となる(しかしggが未知なのでこれを求める必要がある)。

  2. また、g\boldsymbol{g} に適当な定数を掛けて g=1\|\boldsymbol{g}\|=1 であるように定めてあると仮定する。

この2点を使うと二乗誤差は

J=α=1NfαCαg2=α=1N(fαCαg,fαCαg)=α=1N((fα,fα)2Cα(fα,g)+Cα2(g,g))=α=1N((fα,fα)2(fα,g)2+(fα,g)2(g,g))=α=1N(fα2(fα,g)2)\begin{aligned} J & =\sum_{\alpha=1}^N\left\|\boldsymbol{f}_\alpha^{\prime}-C_\alpha \boldsymbol{g}\right\|^2 =\sum_{\alpha=1}^N\left(\boldsymbol{f}_\alpha^{\prime}-C_\alpha \boldsymbol{g}, \boldsymbol{f}_\alpha^{\prime}-C_\alpha \boldsymbol{g}\right) \\ & =\sum_{\alpha=1}^N\left(\left(\boldsymbol{f}_\alpha^{\prime}, \boldsymbol{f}_\alpha^{\prime}\right)-2 C_\alpha\left(\boldsymbol{f}_\alpha^{\prime}, \boldsymbol{g}\right)+C_\alpha^2(\boldsymbol{g}, \boldsymbol{g})\right) \\ & =\sum_{\alpha=1}^N\left(\left(\boldsymbol{f}_\alpha^{\prime}, \boldsymbol{f}_\alpha^{\prime}\right)-2\left(\boldsymbol{f}_\alpha^{\prime}, \boldsymbol{g}\right)^2+\left(\boldsymbol{f}_\alpha^{\prime}, \boldsymbol{g}\right)^2(\boldsymbol{g}, \boldsymbol{g})\right) \\ & =\sum_{\alpha=1}^N\left(\left\|\boldsymbol{f}_\alpha^{\prime}\right\|^2-\left(\boldsymbol{f}_\alpha^{\prime}, \boldsymbol{g}\right)^2\right) \end{aligned}

と整理できる。

JJを最小にするには、α=1N(fα,g)2\sum_{\alpha=1}^N\left(f_\alpha^{\prime}, g\right)^2を最大化すればいい。

m×mm \times m 画像 fα,g\boldsymbol{f}_\alpha^{\prime}, \boldsymbol{g}m2m^2 次元列べクトル に並べ換えたものをそれぞれ f~α,g~\tilde{\boldsymbol{f}}_\alpha^{\prime}, \tilde{\boldsymbol{g}} とすると次のようになる。

α=1N(fα,g)2=α=1N(f~α,g~)2=α=1Ng~f~αf~αg~=(g~,(α=1Nf~αf~α)g~)=(g~,M~g~)\begin{aligned} \sum_{\alpha=1}^N\left(\boldsymbol{f}_\alpha^{\prime}, \boldsymbol{g}\right)^2 & =\sum_{\alpha=1}^N\left(\tilde{\boldsymbol{f}}_\alpha^{\prime}, \tilde{\boldsymbol{g}}\right)^2=\sum_{\alpha=1}^N \tilde{\boldsymbol{g}}^{\top} \tilde{\boldsymbol{f}}_\alpha^{\prime} \tilde{\boldsymbol{f}}_\alpha^{\prime \top} \tilde{\boldsymbol{g}} \\ & =\left(\tilde{\boldsymbol{g}},\left(\sum_{\alpha=1}^N \tilde{\boldsymbol{f}}_\alpha^{\prime} \tilde{\boldsymbol{f}}_\alpha^{\prime\top}\right) \tilde{\boldsymbol{g}}\right) =(\tilde{\boldsymbol{g}}, \tilde{\boldsymbol{M}} \tilde{\boldsymbol{g}}) \end{aligned}

ここで

M~:=α=1Nf~αf~α\tilde{\boldsymbol{M}}:=\sum_{\alpha=1}^N \tilde{\boldsymbol{f}}_\alpha^{\prime} \tilde{\boldsymbol{f}}_\alpha^{\prime \top}

である。行列 M~\tilde{\boldsymbol{M}} の固有値を λ1,,λm2\lambda_1, \ldots, \lambda_{m^2} ,対応する単位固有ベクトルを g~1,,g~m2\tilde{\boldsymbol{g}}_1, \ldots, \tilde{\boldsymbol{g}}_{m^2} と する.各ベクトル g~κ\tilde{\boldsymbol{g}}_\kappam2m^2 個の成分を m×mm \times m 画素に配置し直したものを gκ\boldsymbol{g}_\kappa とし, g1,g2,,gm2\boldsymbol{g}_1, \boldsymbol{g}_2, \ldots, \boldsymbol{g}_{m^2}固有画像 と呼ぶ。これらは対称行列の固有ベクトル から作られているので,正規直交基底となる.

α=1N(fα,g)2\sum_{\alpha=1}^N\left(\boldsymbol{f}_\alpha^{\prime}, \boldsymbol{g}\right)^2を最大化する単位ベクトルg~\tilde{\boldsymbol{g}}M~\tilde{\boldsymbol{M}}の最大固有値に対する固有ベクトルである。したがって,g~\tilde{\boldsymbol{g}} は符号を除いて g~1\tilde{\boldsymbol{g}}_1 に一致する。

このような、画像における主成分分析は画像処理の領域では 固有空間法 と呼ばれる。

6.3 特異値分解

固有画像を作るにはM~\tilde{\boldsymbol{M}}の固有値と固有ベクトルを計算する必要があるが、m2×m2m^2\times m^2と巨大な行列であるため計算量が非常に多くなる。

固有値が0の固有ベクトルは応用上必要ないため、0でない固有値と固有ベクトルのみ計算できれば良い。そこで効率よく計算する方法が特異値分解。

問題は,NN 個の n(=m2)n\left(=m^2\right) 次元ベクトル p1,,pN\boldsymbol{p}_1, \ldots, \boldsymbol{p}_N があるとき,n×nn \times n 行列

M=α=1Npαpα\boldsymbol{M}=\sum_{\alpha=1}^N \boldsymbol{p}_\alpha \boldsymbol{p}_\alpha^{\top}

の固有値,固有ベクトルを計算することである.

ベクトル p1,,pN\boldsymbol{p}_1, \ldots, \boldsymbol{p}_N を列とする n×Nn \times N 行列を

P=(p1p2pN)\boldsymbol{P}=\left(\boldsymbol{p}_1 \quad \boldsymbol{p}_2\quad \cdots \quad \boldsymbol{p}_N\right)

とすると、M=PP\boldsymbol{M}=\boldsymbol{P} \boldsymbol{P}^{\top}となる(ベクトルの直積)

行列MMの固有値・固有ベクトルは、

N=PP\boldsymbol{N}=\boldsymbol{P}^{\top} \boldsymbol{P}

で定義される行列NNの行列の固有値・固有ベクトルを計算する方法でも求められる

MMNNのゼロでない固有値は一致する

MMの固有値と固有ベクトルをそれぞれλ,u\lambda, uとすると

PPT=Mu=λu\underbrace{ PP^T }_{=M} u = \lambda u

左からPTP^Tをかけると

PTP=NPTu=λPTu    N(PTu)=λ(PTu)\underbrace{ P^T P}_{=N} P^T u = \lambda P^T u\\ \iff N (P^T u) = \lambda (P^T u)

NNの固有値と固有ベクトルをそれぞれλ,v\lambda, vとすると

PTP=Nv=λv\underbrace{ P^T P }_{=N} v = \lambda v

左からPPをかけると

PPT=MPv=λPv    M(Pv)=λ(Pv)\underbrace{ P P^T }_{=M} P v = \lambda P v\\ \iff M (P v) = \lambda (P v)

MMの固有値λ(>0)\lambda (> 0)に対する単位ベクトルをuuNNの固有値λ(>0)\lambda(> 0)に対する単位ベクトルをvvとすると

u=±Pvλ,v=±Puλ\boldsymbol{u}=\frac{ \pm \boldsymbol{P} \boldsymbol{v}}{\sqrt{\lambda}}, \quad \boldsymbol{v}=\frac{ \pm \boldsymbol{P}^{\top} \boldsymbol{u}}{\sqrt{\lambda}}

となる。

例えばMMの固有値λ\lambdaに対する固有ベクトルPv\boldsymbol{P v}のノルムの二乗は

Pv2=(Pv,Pv)=(v,PPv)=(v,Nv)=(v,λv)=λv2=λ\left\|\boldsymbol{P v}\right\|^2=(\boldsymbol{P v}, \boldsymbol{P v})=\left(\boldsymbol{v}, \boldsymbol{P}^{\top} \boldsymbol{P v}\right)=(\boldsymbol{v}, \boldsymbol{N v})=(\boldsymbol{v}, \lambda \boldsymbol{v})=\lambda\|\boldsymbol{v}\|^2=\lambda

であるため、λ\sqrt{\lambda}で割って単位ベクトルにする

行列 M(=PP)\boldsymbol{M}\left(=\boldsymbol{P P}^{\top}\right) の固有値を大きい順に並べたものを λ1,λ2,,λn\lambda_1, \lambda_2, \ldots, \lambda_n とし,対応する nn 次元単位固有ベクトルの正規直交系を u1,u2,,un\boldsymbol{u}_1, \boldsymbol{u}_2, \ldots, \boldsymbol{u}_n とする。こ れらを列として並べた n×nn \times n 行列を

U=(u1u2un)\boldsymbol{U}=\left(\begin{array}{llll} \boldsymbol{u}_1 & \boldsymbol{u}_2 & \cdots & \boldsymbol{u}_n \end{array}\right)

とする.同様に,行列 N(=PP)\boldsymbol{N}\left(=\boldsymbol{P}^{\top} \boldsymbol{P}\right) の固有値を大きい順に並べたものを λ1,λ2,,λN\lambda_1, \lambda_2, \ldots, \lambda_N とし,対応する NN 次元単位固有ベクトルの正規直交系を v1,v2,,vNv_1, v_2, \ldots, v_N とする.これらを列として並べた N×NN \times N 行列を

V=(v1v2vN)\boldsymbol{V}=\left(\begin{array}{llll} \boldsymbol{v}_1 & \boldsymbol{v}_2 & \cdots & \boldsymbol{v}_N \end{array}\right)

とする.行列 M\boldsymbol{M} および N\boldsymbol{N} の(共通の)ランク(=0でない固有値の個数) を rr とすると,i>ri>r に対して λi=0\lambda_i=0 である。

PV=(Pv1Pv2PvN)=(±λ1u1±λrur00)\boldsymbol{P} \boldsymbol{V}=\left(\begin{array}{llll} \boldsymbol{P} \boldsymbol{v}_1 & \boldsymbol{P} \boldsymbol{v}_2 & \cdots & \boldsymbol{P} \boldsymbol{v}_N \end{array}\right)=\left(\begin{array}{lllll} \pm \sqrt{\lambda_1} \boldsymbol{u}_1 & \cdots & \pm \sqrt{\lambda_r} \boldsymbol{u}_r & \mathbf{0} & \cdots & \mathbf{0} \end{array}\right)

M\boldsymbol{M} の単位固有ベクトル u1,u2,,ur\boldsymbol{u}_1, \boldsymbol{u}_2, \ldots, \boldsymbol{u}_r の符号を上式の右辺の ± がすべて + に なるように選べば

PV=(u1un)(λ1λr)=U(σ1σr)\boldsymbol{P} \boldsymbol{V}=\left(\boldsymbol{u}_1 \cdots \boldsymbol{u}_n\right)\left(\begin{array}{ccc} \sqrt{\lambda_1} & & \\ & \ddots & \\ & & \sqrt{\lambda_r} \end{array}\right)=\boldsymbol{U}\left(\begin{array}{ccc} \sigma_1 & & \\ & \ddots & \\ & & \\ & & \sigma_r \end{array}\right)

右から V\boldsymbol{V}^{\top} を掛けると

P=U(σ1σr)V\boldsymbol{P}=\boldsymbol{U}\left(\begin{array}{ccc} \sigma_1 & & \\ & \ddots & \\ & & \sigma_r \end{array}\right) \boldsymbol{V}^{\top}

これを行列PP特異値分解 といい、σi\sigma_i特異値 という。

import numpy as np
P = np.array([
    [1, 2],
    [3, 4],
    [5, 6],
])

M = P @ P.T
print("M:\n", M)
eigenvalues, eigenvectors = np.linalg.eig(M)
print("固有値:", eigenvalues.round(2))
print("固有ベクトル:\n", eigenvectors.round(2))
M:
 [[ 5 11 17]
 [11 25 39]
 [17 39 61]]
固有値: [90.74  0.26  0.  ]
固有ベクトル:
 [[-0.23 -0.88  0.41]
 [-0.52 -0.24 -0.82]
 [-0.82  0.4   0.41]]
N = P.T @ P
print("N:\n", N)
eigenvalues, eigenvectors = np.linalg.eig(N)
print("固有値:", eigenvalues.round(2))
print("固有ベクトル:\n", eigenvectors.round(2))
N:
 [[35 44]
 [44 56]]
固有値: [ 0.26 90.74]
固有ベクトル:
 [[-0.78 -0.62]
 [ 0.62 -0.78]]
u1 = P @ eigenvectors[0] / np.sqrt(eigenvalues[0])
u2 = P @ eigenvectors[1] / np.sqrt(eigenvalues[1])
u2
array([-0.09974884, -0.13444826, -0.16914768])
import numpy as np

def svd_from_eig(A):
    AtA = A.T @ A

    # 固有値分解(V: 右特異ベクトル)
    eigenvalues, V = np.linalg.eig(AtA)
    
    # 固有値の実数部分とインデックスを昇順で並び替え
    idx = np.argsort(eigenvalues)[::-1]
    eigenvalues = eigenvalues[idx]
    V = V[:, idx]

    # 特異値の計算(負値を0に修正)
    singular_values = np.sqrt(np.clip(eigenvalues.real, 0, None))

    # 左特異ベクトルの計算
    U = []
    for i in range(len(singular_values)):
        if singular_values[i] > 1e-10:
            u = A @ V[:, i] / singular_values[i]
        else:
            # ランク欠損時の直交補完(ここではゼロベクトル)
            u = np.zeros(A.shape[0])
        U.append(u)
    U = np.column_stack(U)

    # 必要ならUの直交補完を追加(ここでは省略)

    # Σ 行列の構築
    m, n = A.shape
    Sigma = np.zeros((m, n))
    for i in range(min(m, n)):
        Sigma[i, i] = singular_values[i]

    return U, Sigma, V


U, S, V = svd_from_eig(P)

# 検証
print("U:\n", U)
print("Σ:\n", S)
print("V:\n", V)
print("再構成:\n", U @ S @ V.T)
U:
 [[-0.2298477   0.88346102]
 [-0.52474482  0.24078249]
 [-0.81964194 -0.40189603]]
Σ:
 [[9.52551809 0.        ]
 [0.         0.51430058]
 [0.         0.        ]]
V:
 [[-0.61962948 -0.78489445]
 [-0.78489445  0.61962948]]
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[31], line 45
     43 print("Σ:\n", S)
     44 print("V:\n", V)
---> 45 print("再構成:\n", U @ S @ V.T)

ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 3 is different from 2)