PCA와 다르게 SVD는 여러 행렬이 튀어나온다. 사실 PCA는 내부적으로 SVD를 이용하는데, SVD는 상황에 따라서 원본 행렬 크기 그대로 행렬을 만들수도 있고, 축소된 정보를 지닌 Truncated된 행렬을 가질수도 있다.
Singular Value Decomposition 을 통한 행렬분해¶
In [93]:
import numpy as np
array = np.random.randn(10, 3)
array
Out[93]:
linalg의 svd 메서드를 사용하면 다음과 같은 행렬로 나눠진다.¶
In [94]:
u, s, vh = np.linalg.svd(array, full_matrices=True)
In [96]:
print("u:" + str(u.shape))
print("s:" + str(s.shape))
print("vh:" + str(vh.shape))
행렬의 shape는 full_matrices를 False로 주면 곱이 가능하다.¶
In [28]:
u, s, vh = np.linalg.svd(array, full_matrices=False)
In [29]:
print("u:" + str(u.shape))
print("s:" + str(s.shape))
print("vh:" + str(vh.shape))
s는 항상 내림차순으로 정렬되어있다.¶
In [47]:
s
Out[47]:
In [38]:
us = np.matmul(u, np.diag(s))
us
Out[38]:
이 세개의 행렬을 곱한 결과로 오리지널 행렬이 다시 튀어나왔다.¶
In [40]:
a = np.matmul(us, vh)
a
Out[40]:
In [43]:
from sklearn.decomposition import TruncatedSVD
In [74]:
svd = TruncatedSVD(n_components=2)
svd.fit(array)
Out[74]:
사실 특이값들은 위에서 구한 대각행렬의 첫번째, 두번째 원소를 나열한것이나 다름없다!¶
In [75]:
print(svd.singular_values_)
차원축소가 된 행렬을 한번 살펴보자. 어디선가 많이 보던 행렬의 일부분이다.¶
In [76]:
svd.transform(array)
Out[76]:
이는 아까 위에서 봤던 us 의 앞 두번째 열과 의미가 같다.¶
In [77]:
np.matmul(u, np.diag(s))[:,:2]
Out[77]:
오리지널 행렬을 vh의 전치행렬과 곱한 결과와도 같다.¶
In [78]:
np.matmul(array, vh.T)[:,:2]
Out[78]:
분산을 얼마나 설명하는지도 확인 가능하다.¶
In [79]:
svd.explained_variance_ratio_
Out[79]: