定义
拖了很久没写这篇奇异值分解文章,今天把它给写了。因为奇异值分解太重要了。任意矩阵都有奇异值分解,它是将矩阵分解为三部分相乘:
A
m
×
n
=
U
m
×
m
(
Σ
r
×
r
0
0
0
)
m
×
n
V
n
×
n
H
A_{m \times n}=U_{m \times m}\begin{pmatrix} \Sigma_{r \times r} & \bold 0 \\ \bold 0 & \bold 0\end{pmatrix}_{m \times n}V^H_{n \times n}
Am×n=Um×m(Σr×r000)m×nVn×nH
其中
U
U
U是m阶酉矩阵,
V
V
V是n阶酉矩阵,
Σ
\Sigma
Σ是所有奇异值从大到小排列组成的对角阵。从这个定义来看,奇异值分解是非常难的。但是前人已经总结出了一套算法了。奇异值分解为什么这么重要?因为这个分解提供了太多信息了。
- V V V的前 r r r个向量组成了矩阵行空间的一组正交基;
- V V V的后几个向量组成了矩阵零空间的一组正交基。
- U U U的前 r r r( r r r是矩阵的秩)个列向量组成了矩阵列空间的一组正交基;
- U U U的后几个向量组成了矩阵左零空间( N u l l ( A H ) Null(A^H) Null(AH))的一组正交基。
- V V V的前 r r r列由 A H A A^HA AHA的单位正交特征向量组成;
- U U U的前 r r r列由 A A H AA^H AAH的单位正交特征向量组成;
这么难吗?哈哈。其实,步骤主要分以下几步:
- 求 A A H AA^H AAH矩阵和 A H A A^HA AHA矩阵;
- 求 A A H AA^H AAH的所有非零特征值,开根号得到奇异值,再排序得到 Σ \Sigma Σ;
- 求 A A H AA^H AAH的所有非零特征值的单位正交特征向量组成 U U U的前 r r r列;
- 求 A H A^H AH的零空间所有单位正交向量组成 U U U的后 m − r m-r m−r列;
- 求 A A H AA^H AAH的所有单位正交特征向量组成 V V V的前 r r r列;
- 求 A A A的零空间所有单位正交向量组成 V V V的后 n − r n-r n−r列;
- 返回 U , V , Σ U,V,\Sigma U,V,Σ
举例
求这个矩阵的奇异值分解:
(
0
1
0
0
0
0
2
0
0
0
0
3
0
0
0
0
)
\begin{pmatrix} 0 & 1 & 0 & 0\\ 0 & 0 & 2 & 0\\ 0 & 0 & 0 & 3\\ 0 & 0 & 0 & 0 \end{pmatrix}
0000100002000030
一步一步来,首先求
A
A
H
AA^H
AAH矩阵和
A
H
A
A^HA
AHA矩阵:
A
A
H
=
(
0
0
0
0
0
1
0
0
0
0
4
0
0
0
0
9
)
A
H
A
=
(
0
0
0
0
0
1
0
0
0
0
4
0
0
0
0
9
)
AA^H=\begin{pmatrix}0 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 4 & 0\\ 0 & 0 & 0 & 9\\ \end{pmatrix}\\ A^HA=\begin{pmatrix}0 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 4 & 0\\ 0 & 0 & 0 & 9\\ \end{pmatrix}
AAH=
0000010000400009
AHA=
0000010000400009
再求 求
A
A
H
AA^H
AAH的所有非零特征值,得到三个奇异值:
3
,
2
,
1
3,2,1
3,2,1
再求
A
A
H
AA^H
AAH非零特征值的的特征空间:
s
p
a
n
{
(
0
0
1
0
)
,
(
0
1
0
0
)
,
(
1
0
0
0
)
}
span\{ \begin{pmatrix}0\\ 0\\ 1\\ 0\\ \end{pmatrix},\begin{pmatrix}0\\ 1\\ 0\\ 0\\ \end{pmatrix}, \begin{pmatrix}1\\ 0\\ 0\\ 0\\ \end{pmatrix} \}
span{
0010
,
0100
,
1000
}
求
A
H
A^H
AH的零空间为:
s
p
a
n
{
(
0
0
0
1
)
}
span\{\begin{pmatrix}0\\ 0\\ 0\\ 1\\ \end{pmatrix}\}
span{
0001
}
所以
U
U
U为:
(
0
0
1
0
0
1
0
0
1
0
0
0
0
0
0
1
)
\begin{pmatrix}0 & 0 & 1 & 0\\ 0 & 1 & 0 & 0\\ 1 & 0 & 0 & 0\\ 0 & 0 & 0 & 1\\ \end{pmatrix}
0010010010000001
为了节省篇幅,求
V
V
V的顺序我就不细说了,最后求得
V
V
V为:
(
0
0
0
0
0
0
1
0
0
1
0
0
1
0
0
1
)
\begin{pmatrix}0 & 0 & 0 & 0\\ 0 & 0 & 1 & 0\\ 0 & 1 & 0 & 0\\ 1 & 0 & 0 & 1\\ \end{pmatrix}
0001001001000001
所以最后的奇异值分解为:
(
0
1
0
0
0
0
2
0
0
0
0
3
0
0
0
0
)
=
(
0
0
1
0
0
1
0
0
1
0
0
0
0
0
0
1
)
(
3
0
0
0
0
2
0
0
0
0
1
0
0
0
0
0
)
(
0
0
0
1
0
0
1
0
0
1
0
0
1
0
0
0
)
\begin{pmatrix}0 & 1 & 0 & 0\\ 0 & 0 & 2 & 0\\ 0 & 0 & 0 & 3\\ 0 & 0 & 0 & 0\\ \end{pmatrix}=\begin{pmatrix}0 & 0 & 1 & 0\\ 0 & 1 & 0 & 0\\ 1 & 0 & 0 & 0\\ 0 & 0 & 0 & 1\\ \end{pmatrix} \begin{pmatrix}3 & 0 & 0 & 0\\ 0 & 2 & 0 & 0\\ 0 & 0 & 1 & 0\\ 0 & 0 & 0 & 0\\ \end{pmatrix} \begin{pmatrix}0 & 0 & 0 & 1\\ 0 & 0 & 1 & 0\\ 0 & 1 & 0 & 0\\ 1 & 0 & 0 & 0\\ \end{pmatrix}
0000100002000030
=
0010010010000001
3000020000100000
0001001001001000
Python实现
我没有用numpy等包,直接把以前自己写的求齐次方程组的解、QR分解等代码利用起来,代码如下:
# 奇异值分解
def svd(self):
m = len(self.__vectors[0])
n = len(self.__vectors)
# 先计算两个矩阵
ah = self.hermitian_transpose()
a_ah = self * ah
ah_a = ah * self
# 求奇异值
from com.youngthing.mathalgorithm.linearalgebra.hessenberg import Matrix as M
eigen_values = M(ah_a.__vectors).eigen_values()
eigen_values.sort(reverse=True)
sigma = Matrix([[0 for _ in range(m)] for _ in range(n)])
for i, e in enumerate(eigen_values):
sigma.__vectors[i][i] = math.sqrt(e)
# 求aah的所有单位正交特征向量
u = []
for i, e in enumerate(eigen_values):
if matrix_utils.is_zero(e):
continue
eigen_vectors = a_ah.eigen_vector(e)
q, _ = Matrix(eigen_vectors).qr_equations()
u += q.__vectors
# 求ah的零空间
vectors = ah.homogeneous_solution()
q, _ = Matrix(vectors).qr_equations()
u += q.__vectors
# 求aha的所有单位正交特征向量
v = []
for i, e in enumerate(eigen_values):
if matrix_utils.is_zero(e):
continue
eigen_vectors = ah_a.eigen_vector(e)
q, _ = Matrix(eigen_vectors).qr_equations()
v += q.__vectors
# 求a的零空间
vectors = self.homogeneous_solution()
q, _ = Matrix(vectors).qr_equations()
v += q.__vectors
return Matrix(u),sigma,Matrix(v)