特異値分解(singular value decomposition)でベクトルを直交化する
はじめに
特異値分解を使った直交化をする機会があったので書き留めておきます.数式で説明するか文章で説明するかはフィーリングです.
モチベーション
行列が与えられたとします.の列ベクトルを,変換後の空間のスケール(厳密な用語が分かりません...)を変えないように直交したベクトルに変換することを行いたいという話です.なぜかについては説明しません(面倒ですので・・・).
説明
間違ってたらご一報頂けると幸いです.
特異値分解
行列分解の一種.行列をのように分解します.ここで,は直交行列,は対角行列です.
直交行列の性質
行列が直交行列である,とは以下のことと同値です.
今回の直交化においてこの性質が大事になってきます.
特異値分解(SVD)による直交化
SVDによる直交化は を利用して のように直交化します.ここで,性質2より,Vの逆行列をかける代わりに転置行列をかけています.
特異値分解(SVD)による直交化の性質
SVDによる直交化では,被変換行列による変換後の単位円を変えずに各ベクトルを直交にすることができます.以下,説明です.全てのノルムが1のベクトルを考えたとき,座標とみなしたベクトルの集合によって円ができます.これを単位円と言います.によってその各座標を変換すると単位円の形が変わります(楕円もしくは円に).SVDによる直交化では,この楕円の形を変えないベクトルに直交化できるのです.もちろん,各ベクトルについて見てみれば直交化する前と後では値が変わってしまいます.ただ,ノルムが一定のベクトルによってできる,集合レベルでは変わらないようになっているということですね. この話の直感的な図がWikipediaにあります. en.wikipedia.org
この直交化を行列に対して行うと,
となり,SVDによって得られるとで変換後の行列を得られることになります(もちろん元の行列にをかけてもよい). 更にを見てみると直交行列と対角行列の行列積になっているので,性質1より,変換後の行列は列ベクトルが直交していることが分かります(行ベクトルは直交するとは限らない).
要するに,による変換をしてあげると,変換後の空間のスケール(厳密な用語がry)を変えずに列ベクトルを直交化させることができる,というわけですね.
実験
実際にSVDを使って得られるベクトルを眺めてみます.
実験条件
pythonで動かしていきます. まずimportします.numpyと可視化関連です(個人的な好みでseabornを使ってますがimportしなくてもこの後のコードは実行できます,figureの見た目が良くなるだけです).
import numpy as np import matplotlib.pyplot as plt import seaborn as sns sns.set()
適当な行列を作ります.
M = np.array([[1,4],[3,4]])
SVDしてを計算することでMを直交化します(numpyの関数だとは対角成分のみのベクトルで返ってくるためnp.diagで行列にしている).
U, sigma, V = np.linalg.svd(M, full_matrices=True)
M_prime = np.dot(U, np.diag(sigma))
一応直交しているか確認.
np.dot(M_prime.T, M_prime) # array([[ 4.04164878e+01, -1.21399145e-17], # [ -1.21399145e-17, 1.58351216e+00]])
大丈夫そう.最後に可視化します.
fig, ax = plt.subplots(1, 1, figsize=(5, 5)) ax.set_xlim([-6,5]) ax.set_ylim([-6,5]) ax.plot([0,M.transpose()[0][0]], [0,M.transpose()[0][1]], color='b') ax.plot([0,M.transpose()[1][0]], [0,M.transpose()[1][1]], color='b') ax.plot([0,M_prime.transpose()[0][0]], [0,M_prime.transpose()[0][1]], color='r') ax.plot([0,M_prime.transpose()[1][0]], [0,M_prime.transpose()[1][1]], color='r') plt.show()
直交化後のの列ベクトルが描く単位円が変わってなさそうなことが分かります(適当).