e資格対策(2) Numpyで線形代数

二回目 Numpyで線形代数 固有値分解

一回目↓に引き続き、

38pinn.hateblo.jp

前提準備として、PCにanacondaのインストールが済んでいること。 今回の操作はすべてWindowsコマンドプロンプトのみ。

やること

Numpyで特異値分解(SVD)を2つの方法で実行する
- SVDを手計算で手順を確認 (Texがうまく使えるようになったら追記する)

用語

固有値分解・・・正方行列を分解すること.正方行列Aに対してA=VΛV-1
特異値分解・・・(英: singular value decomposition)非正方行列を分解すること.非正方行列MにおいてM=USV-1
左特異ベクトル・・・単位ベクトルの直行行列.非正方行列MにおいてMMT固有値分解して求める.Uで表す
右特異クトル・・・単位ベクトルの直行行列.非正方行列MにおいてMMT固有値分解して求める.Vで表す
特異値・・・σで表す
直行行列・・・(orthogonal matrix)転置行列と逆行列が等しくなる正方行列.Rで表す
ユニタリ行列・・・(英: unitary matrix)直交行列を複素数体へ拡張したもの.Uで表現する.直行行列と同じ性質

numpy.linalg.svdを実行

以下、行列Mを特異値分解した形.
M=USV-1
※Uは左特異ベクトル、Sは特異値、Vは右特異ベクトル
※Mは正方でも非正方行列でもよい.UとVは必ず大きさが1のベクトルにする.UとVは直行行列になるのでUT=U-1になる.Vも同様. np.linalg.svdではUSVTが1ラインで求めることができる.Vは転置した状態(VT)で出力されるので変数名は明示的にVTと指定した.

>>> import numpy as np
>>> from numpy.linalg import inv
>>> from numpy import linalg as LA
>>>
>>> M = np.array([[1,2,3],[3,2,1]])
>>>
>>> M
array([[1, 2, 3],
       [3, 2, 1]])
>>>
>>> U, S, VT = np.linalg.svd(M, full_matrices=True)
>>>
>>> U
array([[-0.70710678, -0.70710678],
       [-0.70710678,  0.70710678]])
>>>
>>> S
array([4.89897949, 2.        ])
>>>
>>> np.diag(S)
array([[4.89897949, 0.        ],
       [0.        , 2.        ]])
>>>
>>> VT
array([[-5.77350269e-01, -5.77350269e-01, -5.77350269e-01],
       [ 7.07106781e-01,  1.66533454e-16, -7.07106781e-01],
       [ 4.08248290e-01, -8.16496581e-01,  4.08248290e-01]])
>>>
numpy.linalg.svdで求めたUSVTを逆に再結合してみる
>>> M = np.array([[1,2,3],[3,2,1]])
>>>
>>> U, S, VT = np.linalg.svd(M, full_matrices=True)
>>>
>>> U@S@VT
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
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)
### Mが非正方行列の為Sが(2×2)ではエラーになった。以下、0を追加して2×3に書き換える。
>>>
>>> np.diag(S)
array([[4.89897949, 0.        ],
       [0.        , 2.        ]])
### Sは(2×2)の行列
>>>
>>> S = np.array([[4.89897949,0,0],[0,2,0]])
### Sを(2×3)の行列に書き換え。
>>>
>>> S
array([[4.89897949, 0.        , 0.        ],
       [0.        , 2.        , 0.        ]])
>>>
>>> U@S@VT
array([[1., 2., 3.],
       [3., 2., 1.]])
### 元のMに戻ることを確認できた。
手計算で固有値分解を実行 (後日追加予定)

特異値分解固有値分解の仕組みを応用している.手計算で手順を追うことで仕組みを理解する.
以下、仕組み概要
前提:MV=USで且つMT(U)=VSが成り立てば固有値Sが求められる.
ここでM=USV-1の形に特異値分解するとき
MT=VSU-1
MMT=USV-1VSU-1

から
MMT=USSU-1
となる.これによりMMT固有値を求めることで、 Mの特異値であるSの二乗(S2)と左特異ベクトルUを求めることができる.また
MTM=VSU-1USV-1=VSSV-1
からMTMの固有値を求めることでMの特異値であるSの二乗(S2)と左特異ベクトルVを求めることができる.
※Sの二乗(S2)はMMTとMTMのどちらの固有値分解から求めても同じ値になるので計算しやすい方を選ぶのが良い.
※VとUは単位ベクトルになる,Numpyではもともと大きさが1になるように正則化されて出力される.手計算場合は注意.
固有値Sは対角行列で降順に並べる.これにより計算値うち影響の小さい部分(固有値の値の小さい)を次元削減し全体のデータ量を減らすことが可能.

`