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.

固有値・固有ベクトルの解釈・意味

線形代数的な解釈

いまいちど定義を振り返る

定義より、線形変換AxA \boldsymbol{x}と、ベクトルの定数倍λx\lambda \boldsymbol{x}が等しい。つまり、

と解釈できる。

統計学/機械学習的な解釈

データを行列で表したときの話

学習データの分散が最大になる方向への線形変換を求める手法である 主成分分析 を例に考える。

主成分分析

DD次元のデータx=(x1,,xD)T\boldsymbol{x}=(x_1, \cdots, x_D)^TNN個あるとする。ii番目の観測値を行ベクトルxi\boldsymbol{x}_iとして表し、データを行列X=(x1,,xN)TX = (\boldsymbol{x}_1, \cdots, \boldsymbol{x}_N)^Tと表す。

各変数の平均のベクトルxˉ=(xˉ1,...,xˉD)T\bar{\boldsymbol{x}}=(\bar{x}_1, ..., \bar{x}_D)^Tを引き算した行列をXˉ=(x1xˉ,...,xNxˉ)T\bar{\boldsymbol{X}}=(\boldsymbol{x}_1 - \bar{\boldsymbol{x}}, ..., \boldsymbol{x}_N - \bar{\boldsymbol{x}})^Tとおけば、共分散行列Σ\boldsymbol{\Sigma}

Σ=Var[Xˉ]=1NXˉTXˉ\boldsymbol{\Sigma} = \operatorname{Var}[\bar{\boldsymbol{X}}] = \frac{1}{N} \bar{\boldsymbol{X}}^T \bar{\boldsymbol{X}}

で定義される。

係数ベクトルaj=(aj1,...,ajD)T (j=1,...,D)\boldsymbol{a}_j = (a_{j1}, ..., a_{jD})^T \ (j=1, ..., D)を用いてXˉ\bar{X}を線形変換したベクトルをsj\boldsymbol{s}_jとする。

sj=(s1j,...,sNj)T=Xˉaj\boldsymbol{s}_j = (s_{1j}, ..., s_{Nj})^T = \bar{\boldsymbol{X}} \boldsymbol{a}_j

このデータの分散は

Var[sj]=1NsjTsj=1N(Xˉaj)TXˉaj=1NajTXˉTXˉaj=ajTVar[Xˉ]aj\begin{aligned} \operatorname{Var}[\boldsymbol{s}_j] &= \frac{1}{N} \boldsymbol{s}_j^T \boldsymbol{s}_j\\ &= \frac{1}{N} (\bar{\boldsymbol{X}} \boldsymbol{a}_j)^T \bar{\boldsymbol{X}} \boldsymbol{a}_j\\ &= \frac{1}{N} \boldsymbol{a}_j^T \bar{\boldsymbol{X}}^T \bar{\boldsymbol{X}} \boldsymbol{a}_j\\ &= \boldsymbol{a}_j^T \operatorname{Var}[\bar{\boldsymbol{X}}] \boldsymbol{a}_j\\ \end{aligned}

となる。

このままmaxajVar[sj]\max_{\boldsymbol{a}_j} \operatorname{Var}[\boldsymbol{s}_j]を解くと単にaj=\boldsymbol{a}_j=\inftyが解になってしまうので、係数ベクトルaj\boldsymbol{a}_jのノルム制約条件をかけた最大化問題を解くことにする。

この分散が最大となる射影ベクトルは、ラグランジュ関数

L(aj)=ajTVar[Xˉ]ajλ(ajTaj1)L(\boldsymbol{a}_j) = \boldsymbol{a}_j^T \operatorname{Var}[\bar{\boldsymbol{X}}] \boldsymbol{a}_j - \lambda (\boldsymbol{a}_j^T \boldsymbol{a}_j - 1)

を最大にするaj\boldsymbol{a}_jである。(λ\lambdaはラグランジュ未定乗数)

微分して0とおけば

L(aj)aj=2Var[Xˉ]aj2λaj=0\frac{\partial L(\boldsymbol{a}_j)}{\partial \boldsymbol{a}_j} = 2 \operatorname{Var}[\bar{\boldsymbol{X}}] \boldsymbol{a}_j - 2 \lambda \boldsymbol{a}_j = 0

より

Var[Xˉ]aj=λaj\operatorname{Var}[\bar{\boldsymbol{X}}] \boldsymbol{a}_j = \lambda \boldsymbol{a}_j

となる。

これは固有値・固有ベクトルの定義で見かけたAx=λxAx = \lambda xと同じ形になっている。このλ\lambdaaj\boldsymbol{a}_jは固有値問題を解くことにより得られる。

主成分分析は、データXXと係数aj\boldsymbol{a}_jの線形変換sj\boldsymbol{s}_jの分散を最大化するような係数aj\boldsymbol{a}_jを求める問題

maxaj Var[sj]subject to aj22=1\max_{\boldsymbol{a}_j} \ \operatorname{Var}[\boldsymbol{s}_j]\\ \text{subject to} \ ||\boldsymbol{a}_j||_2^2 = 1

を解析的に解くために

Var[Xˉ]aj=λaj\operatorname{Var}[\bar{\boldsymbol{X}}] \boldsymbol{a}_j = \lambda \boldsymbol{a}_j

という式を立てて固有ベクトルaj\boldsymbol{a}_jを求めるものだった。なので、

と捉えることができる。

数値例

このようなデータがあったとする

Source
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm

w = 0.3
n = 300
x1 = norm.rvs(loc=0, scale=1, size=n, random_state=0)
x2 = w * x1 + (1 - w) * norm.rvs(loc=0, scale=1, size=n, random_state=1)
X = np.append(x1.reshape(-1, 1), x2.reshape(-1, 1), axis=1)

fig, ax = plt.subplots()
ax.scatter(x1, x2)
ax.set(xlabel="x1", ylabel="x2")
fig.show()
<Figure size 640x480 with 1 Axes>

固有値問題を解いてλ\lambdaaj\boldsymbol{a}_jを推定していく。

x_bar = X.mean(axis=0)
X_bar = X - x_bar
Sigma = (1 / n) * X_bar.T @ X_bar
lambdas, vectors = np.linalg.eig(Sigma)
print(f"""
λ={lambdas}
a1={vectors[:, 0].round(3)}
a2={vectors[:, 1].round(3)}
""")

λ=[1.17427995 0.37150396]
a1=[0.886 0.464]
a2=[-0.464  0.886]

主成分を表す固有ベクトルの傾きに直線をプロットすると以下の通り。

係数ベクトルaja_jはノルムが1になるように制約がかけられているので、図にしても長さは同じ。

PC1方向の変換s1s_1aja_jに対してλ1=1.17\lambda_1 = 1.17倍ということ。

Source
o = [0, 0]
a1 = vectors[:, 0]
a2 = vectors[:, 1]

fig, ax = plt.subplots()
ax.scatter(x1, x2)
ax.arrow(*o, *a1, width=0.02, color="coral", length_includes_head=True, alpha=0.7, label="PC1")
ax.arrow(*o, *a2, width=0.02, color="orange", length_includes_head=True, alpha=0.7, label="PC2")
ax.set(xlabel="x1", ylabel="x2")
ax.legend()
fig.show()
<Figure size 640x480 with 1 Axes>

推定できたa\boldsymbol{a}の任意の次元数を使って線形変換s=Xˉa\boldsymbol{s} = \boldsymbol{\bar{X}} \boldsymbol{a}を作って散布図にするとこうなる

Source
S = X_bar @ vectors

fig, ax = plt.subplots()
ax.scatter(S[:, 0], S[:, 1])
ax.set(xlabel="s1", ylabel="s2")
fig.show()
<Figure size 640x480 with 1 Axes>

新しい座標での分散の大きさ=固有値

Source
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib

n = 1000
np.random.seed(0)

# いくつかの相関係数で試す
rhoset = [1, 0.5, 0]
fig, axes = plt.subplots(figsize=[12, 3.5], ncols=len(rhoset))

for i, rho in enumerate(rhoset):
    true_cov = np.array([[1, rho],
                         [rho, 1]])
    X = np.random.multivariate_normal(mean=[0,0], cov=true_cov, size=n)
    # Cov = np.cov(X, rowvar=False)
    Corr = np.corrcoef(X, rowvar=False)
    # 固有値分解で主成分を取得(共分散を最大化する軸が固有ベクトルになるという定理のため)
    # 共分散より相関係数を使うほうが対角成分が1になって安定するので、相関を使うことにする
    lambdas, vectors = np.linalg.eig(Corr)

    axes[i].scatter(X[:, 0], X[:, 1])
    axes[i].axline(xy1=(0, 0), xy2=(vectors[:, 0]), color="coral", label=f"PC1={vectors[:, 0].round(3)}")
    axes[i].axline(xy1=(0, 0), xy2=(vectors[:, 1]), color="orange", label=f"PC2={vectors[:, 1].round(3)}")
    axes[i].set(xlabel="x1", ylabel="x2", xlim=(-3, 3), ylim=(-3, 3), title=f"ρ={rho}, 固有値λ={lambdas.round(3)}")
    axes[i].legend()
# fig.show()
<Figure size 1200x350 with 3 Axes>