将一个矩阵分解为U,V(U,V均为列正交矩阵,即列向量直接内积为0),中间的矩阵为对角阵,元素为奇异值。
A [ m ∗ n ] = U [ m ∗ r ] ∗ ∑ [ r ∗ r ] ∗ ( V [ n ∗ r ] ) T A_{[m*n]} = U_{[m*r]} * \sum_{[r*r]} *(V_{[n*r]})^T A[m∗n]=U[m∗r]∗[r∗r]∑∗(V[n∗r])T
A = U ∗ ∑ ∗ V T A T = V ∗ ∑ ∗ U T A A T = U ∗ ∑ ∗ V T ∗ V ∗ ∑ ∗ U T A = U * \sum * V^T \\ A^T = V * \sum * U ^T \\ AA^T = U * \sum * V^T * V * \sum * U^T A=U∗∑∗VTAT=V∗∑∗UTAAT=U∗∑∗VT∗V∗∑∗UT
A A T = U ∑ 2 U T A A T U = U ∑ 2 AA^T = U {\sum}^2U^T \\ AA^T U = U {\sum}^2 AAT=U∑2UTAATU=U∑2
因此,U为 A A T AA^T AAT特征向量构成的矩阵,然后 ∑ 2 {\sum}^2 ∑2的对角元为特征值。
同理,可知, A T A A^TA ATA对应于V的计算。
import numpy as np
A = np.linspace(0, 14, 15).reshape((3, -1))
A
array([[ 0., 1., 2., 3., 4.],
[ 5., 6., 7., 8., 9.],
[10., 11., 12., 13., 14.]])
def SVD(A, n):
M = np.dot(A, A.T)
eigval, eigvec = np.linalg.eig(M)
indexes = np.argsort(-eigval)[:n]
U = eigvec[:, indexes]
sigma_sq = eigval[indexes]
M = np.dot(A.T, A)
eigval, eigvec = np.linalg.eig(M)
indexes = np.argsort(-eigval)[:n]
V = eigvec[:, indexes]
sigma = np.diag(np.sqrt(sigma_sq))
# print(sigma)
return np.dot(np.dot(U, sigma), V.T)
A_ = SVD(A, 2)
A_
array([[2.01625019e-16, 1.00000000e+00, 2.00000000e+00, 3.00000000e+00,
4.00000000e+00],
[5.00000000e+00, 6.00000000e+00, 7.00000000e+00, 8.00000000e+00,
9.00000000e+00],
[1.00000000e+01, 1.10000000e+01, 1.20000000e+01, 1.30000000e+01,
1.40000000e+01]])
非常近了,然后量化判断下,用二范数来测量下:
np.linalg.norm(A_ - A)
1.8697717541841314e-14