정방 행렬 $A$에 대해 다음 식을 만족하는 단위 벡터 $v$, 스칼라 $\lambda$을 여러 개 찾을 수 있다.
$$ Av = \lambda v $$$ A \in \mathbf{R}^{M \times M} $ 정방행렬
$ \lambda \in \mathbf{R} $
$ v \in \mathbf{R}^{M} $
이러한 실수 $\lambda$를 고유값(eigenvalue), 단위 벡터 $v$ 를 고유벡터(eigenvector) 라고 하며 고유값과 고유벡터를 찾는 작업을 고유분해(eigen-decomposition)라고 한다.
$ A \in \mathbf{R}^{M \times M} $ 에 대해 최대 $M$개의 고유값-고유벡터 쌍이 존재할 수 있다.
예를 들어 다음 행렬 $A$
$$ A= \begin{bmatrix} 1 & -2 \\ 2 & -3 \end{bmatrix} $$에 대해 다음 단위 벡터와 스칼라 값은 고유벡터-고유값이 된다.
복수 개의 고유 벡터가 존재하는 경우에는 다음과 같이 고유벡터 행렬 $V$와 고유값 행렬 $\Lambda$로 표기할 수 있다.
$$ A \left[ v_1 \cdots v_M \right] = \left[ \lambda_1 v_1 \cdots \lambda_M v_M \right] = \left[ v_1 \cdots v_M \right] \begin{bmatrix} \lambda_{1} & 0 & \cdots & 0 \\ 0 & \lambda_{2} & \cdots & 0 \\ \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & \cdots & \lambda_{M} \\ \end{bmatrix} $$$$ AV = V\Lambda $$여기에서
$$ V = \left[ v_1 \cdots v_M \right] $$$$ \Lambda = \begin{bmatrix} \lambda_{1} & 0 & \cdots & 0 \\ 0 & \lambda_{2} & \cdots & 0 \\ \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & \cdots & \lambda_{M} \\ \end{bmatrix} $$numpy linalg 서브패키지에서는 고유값과 고유벡터를 구할 수 있는 eig
명령을 제공한다. (eigen-decomposition)
정수로 치면 일종의 소인수분해라고 할 수 있다.
In [1]:
w, V = np.linalg.eig(np.array([[1, -2], [2, -3]]))
In [2]:
w
Out[2]:
In [3]:
V
Out[3]:
행렬 $A$가 대칭(symmetric) 행렬이면 고유값 벡터 행렬 $V$는 다음과 같이 전치 행렬이 역행렬과 같아진다.
$$ V^T V = V V^T = I$$이 때는 고유 분해가 다음과 같이 표시된다.
$$ A = V\Lambda V^T = \sum_{i=1}^{M} {\lambda_i} v_i v_i^T$$$$ A^{-1} = V \Lambda^{-1} V^T = \sum_{i=1}^{M} \dfrac{1}{\lambda_i} v_i v_i^T$$확률 변수의 공분산 행렬 $\Sigma$ 은 대칭 행렬이므로 위의 관계식이 성립한다.
따라서 다변수 가우시안 정규 분포의 확률 밀도 함수는 다음과 같이 표시할 수 있다.
$$ \begin{eqnarray} \mathcal{N}(x \mid \mu, \Sigma) &=& \dfrac{1}{(2\pi)^{D/2} |\Sigma|^{1/2}} \exp \left( -\dfrac{1}{2} (x-\mu)^T \Sigma^{-1} (x-\mu) \right) \\ &=& \dfrac{1}{(2\pi)^{D/2} |\Sigma|^{1/2}} \exp \left( -\dfrac{1}{2} (x-\mu)^T V \Lambda^{-1} V^T (x-\mu) \right) \\ &=& \dfrac{1}{(2\pi)^{D/2} |\Sigma|^{1/2}} \exp \left( -\dfrac{1}{2} (V^T(x-\mu))^T \Lambda^{-1} (V^T (x-\mu)) \right) \\ \end{eqnarray} $$즉 변환 행렬 $V^T$로 좌표 변환하면 서로 독립인 성분들로 나누어진다.
In [4]:
mu = [2, 3]
cov = [[2, 3],[3, 7]]
rv = sp.stats.multivariate_normal(mu, cov)
xx = np.linspace(0, 4, 120)
yy = np.linspace(1, 5, 150)
XX, YY = np.meshgrid(xx, yy)
plt.grid(False)
plt.contourf(XX, YY, rv.pdf(np.dstack([XX, YY])))
x1 = np.array([0, 2])
x1_mu = x1 - mu
x2 = np.array([3, 4])
x2_mu = x2 - mu
plt.plot(x1_mu[0] + mu[0], x1_mu[1] + mu[1], 'bo', ms=20)
plt.plot(x2_mu[0] + mu[0], x2_mu[1] + mu[1], 'ro', ms=20)
plt.axis("equal")
plt.show()
In [5]:
w, V = np.linalg.eig(cov)
In [6]:
w
Out[6]:
In [7]:
V
Out[7]:
In [8]:
rv = sp.stats.multivariate_normal(mu, w)
xx = np.linspace(0, 4, 120)
yy = np.linspace(1, 5, 150)
XX, YY = np.meshgrid(xx, yy)
plt.grid(False)
plt.contourf(XX, YY, rv.pdf(np.dstack([XX, YY])))
x1 = np.array([0, 2])
x1_mu = x1 - mu
x2 = np.array([3, 4])
x2_mu = x2 - mu
x1t_mu = V.T.dot(x1_mu) # 좌표 변환
x2t_mu = V.T.dot(x2_mu) # 좌표 변환
plt.plot(x1t_mu[0] + mu[0], x1t_mu[1] + mu[1], 'bo', ms=20)
plt.plot(x2t_mu[0] + mu[0], x2t_mu[1] + mu[1], 'ro', ms=20)
plt.axis("equal")
plt.show()
정방 행렬이 아닌 행렬 $M$에 대해서도 고유 분해와 유사한 분해가 가능하다. 이를 특이값 분해(singular value decomposition)이라고 한다.
여기에서
이고 행렬 $U$와 $V$는 다음 관계를 만족한다.
$$ U^T U = UU^T = I $$$$ V^T V = VV^T = I $$예를 들어
$$\mathbf{M} = \begin{bmatrix} 1 & 0 & 0 & 0 & 2 \\ 0 & 0 & 3 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 \\ 0 & 2 & 0 & 0 & 0 \end{bmatrix} $$에 대한 특이값 분해 결과는 다음과 같다.
$$ \begin{align} \mathbf{U} &= \begin{bmatrix} 0 & 0 & 1 & 0 \\ 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & -1 \\ 0 & 1 & 0 & 0 \\ \end{bmatrix} \\ \boldsymbol{\Sigma} &= \begin{bmatrix} \sqrt{5} & 0 & 0 & 0 & 0 \\ 0 & 2 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 \end{bmatrix} \\ \mathbf{V}^T &= \begin{bmatrix} 0 & 0 & \sqrt{0.2} & 0 & \sqrt{0.8} \\ 0 & 1 & 0 & 0 & 0 \\ 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & -\sqrt{0.8} & 0 & \sqrt{0.2} \\ 0 & 0 & 0 & 1 & 0 \\ \end{bmatrix} \end{align}$$이는 다음과 같이 확인 할 수 있다.
$$\begin{align} \mathbf{U} \mathbf{U^T} &= \begin{bmatrix} 0 & 0 & 1 & 0 \\ 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & -1 \\ 0 & 1 & 0 & 0 \\ \end{bmatrix} \cdot \begin{bmatrix} 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 \\ 0 & 0 & -1 & 0 \\ \end{bmatrix} = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} = \mathbf{I}_4 \\ \mathbf{V} \mathbf{V^T} &= \begin{bmatrix} 0 & 0 & \sqrt{0.2} & 0 & \sqrt{0.8} \\ 0 & 1 & 0 & 0 & 0 \\ 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & -\sqrt{0.8} & 0 & \sqrt{0.2} \\ 0 & 0 & 0 & 1 & 0 \\ \end{bmatrix} \cdot \begin{bmatrix} 0 & 0 & 1 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 \\ \sqrt{0.2} & 0 & 0 & -\sqrt{0.8} & 0\\ 0 & 0 & 0 & 0 & 1 \\ \sqrt{0.8} & 0 & 0 & \sqrt{0.2} & 0 \\ \end{bmatrix} = \begin{bmatrix} 1 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 1 \end{bmatrix} = \mathbf{I}_5 \end{align}$$
In [9]:
from pprint import pprint
M = np.array([[1,0,0,0,0],[0,0,2,0,3],[0,0,0,0,0],[0,2,0,0,0]])
print("\nM:"); pprint(M)
U, S0, V0 = np.linalg.svd(M, full_matrices=True)
print("\nU:"); pprint(U)
S = np.hstack([np.diag(S0), np.zeros(M.shape[0])[:, np.newaxis]])
print("\nS:"); pprint(S)
print("\nV:"); pprint(V)
V = V0.T
print("\nU.dot(U.T):"); pprint(U.dot(U.T))
print("\nV.dot(V.T):"); pprint(V.dot(V.T))
print("\nU.dot(S).dot(V.T):"); pprint(U.dot(S).dot(V.T))
In [10]:
A = np.array([[0.8, 0.3], [0.2, 0.7]])
In [11]:
L, V = np.linalg.eig(A)
In [12]:
L
Out[12]:
In [13]:
V
Out[13]:
In [14]:
l1 = L[0]
l2 = L[1]
v1 = V[:, 0]
v2 = V[:, 1]
In [15]:
v1
Out[15]:
In [16]:
A.dot(v1)
Out[16]:
In [17]:
l1 * v1
Out[17]:
In [18]:
A.dot(v2)
Out[18]:
In [19]:
l2 * v2
Out[19]:
In [20]:
A = np.array([[2, -1], [-1,2]])
In [21]:
L, V = np.linalg.eig(A)
In [22]:
L
Out[22]:
In [23]:
V
Out[23]:
In [24]:
l1 = L[0]
l2 = L[1]
v1 = V[:, 0]
v2 = V[:, 1]
In [25]:
A.dot(v1)
Out[25]:
In [26]:
l1* v1
Out[26]:
In [27]:
A.dot(v2)
Out[27]:
In [28]:
l2 * v2
Out[28]:
In [29]:
V.dot(V.T)
Out[29]:
In [30]:
A = np.array([[3,1,-1], [1,3,-1], [-1,-1,5]])
A
Out[30]:
In [31]:
L, V = np.linalg.eig(A)
L
Out[31]:
In [32]:
V
Out[32]:
In [33]:
l1 = L[0]
l2 = L[1]
l3 = L[2]
v1 = V[:, 0]
v2 = V[:, 1]
v3 = V[:, 2]
In [34]:
A.dot(v1)
Out[34]:
In [35]:
l1 * v1
Out[35]:
In [36]:
A.dot(v2)
Out[36]:
In [37]:
l2 * v2
Out[37]:
In [38]:
A.dot(v3)
Out[38]:
In [39]:
l3 * v3
Out[39]:
In [40]:
V.dot(V.T)
Out[40]: