SVD
将一个矩阵分解为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
SVD计算方式
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 ∗ ∑ ∗ V T A T = V ∗ ∑ ∗ U T A A T = U ∗ ∑ ∗ V T ∗ V ∗ ∑ ∗ U T
- 由于其为列正交向量,所以矩阵在非对角位置都为0, 因此当V的列向量是单位向量时,对角位为1,则为单位阵。
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
A
A
T
=
U
∑
2
U
T
A
A
T
U
=
U
∑
2
因此,U为
A A T AA^T
A
A
T
特征向量构成的矩阵,然后
∑ 2 {\sum}^2
∑
2
的对角元为特征值。
同理,可知, A T A A^TA A T A 对应于V的计算。
Python实现
- 导入包
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
- 非常的小了。