定理陈述
对于任意 \(m \times n\) 的矩阵 \(A\),存在一个分解:
\[ A = U \Sigma V^T \]
其中:
- r=rank(A)是矩阵A的秩
- \(U\) 是一个 \(m \times m\) 的正交矩阵(即 \(U^T U = I\)),前r列是矩阵\(A A^\top\)的非零特征值的特征向量。
- \(V\) 是一个 \(n \times n\) 的正交矩阵(即 \(V^T V = I\)),前r列是矩阵$ A^A$ 的非零特征值的特征向量。
- \(\Sigma\) 是一个 \(m \times n\) 的对角矩阵,其对角线元素是非负实数,前r个非负实数称为A的奇异值。
分解结果不是唯一的,不同分解的区别主要在于特征向量和奇异值的顺序。
证明
参考自:奇异值分解(SVD)推导证明与应用_简述奇异值分解定理,并进行推导与证明(公式以及矩阵可以写在纸上照下来)-CSDN博客
因为\(AA^\top\)是半正定矩阵,所以存在正交矩阵\(V_{n\times n}\),
\[ V^T (A^T A) V = \operatorname{diag}(\lambda_1, \lambda_2, \dots, \lambda_n) \]
其中\(\lambda_1 > \lambda_2 > \cdots > \lambda_r > 0 = \lambda_{r+1} = \cdots = \lambda_n\)为\(AA^\top\)的n个非负特征根。
令\(\Sigma_1 = \operatorname{diag}(\sigma_1, \sigma_2, \dots, \sigma_r) = \operatorname{diag}(\sqrt{\lambda_1}, \sqrt{\lambda_2}, \dots, \sqrt{\lambda_r}), \quad V_1 = [\mathbf{v}_1, \mathbf{v}_2, \dots, \mathbf{v}_r], \quad V_2 = [\mathbf{v}_{r+1}, \mathbf{v}_{r+2}, \dots, \mathbf{v}_n],V=[V_1,V_2]\),所以根据\(V\)定义,两个式子左边乘以\(V\),得到
\[ A^\top A V=V\Sigma_1 \]
取其中的r个列向量,有
\[ A^\top A V_1=V_1\Sigma_1 \]
进一步,我们可以得到
\[ \Sigma_1^{-1} V_1^\top A^\top A V_1 \Sigma_1^{-1} = I \]
令 \(U_1 = A V_1 \Sigma_1^{-1}\),则有 \(U_1^\top U_1 = I\)。此时,我们可以选择 \(m - r\) 组标准正交向量与 \(U_1\) 的列向量组成一组标准正交基,也即 \([U_1, U_2]\) 是一个 \(m \times m\) 阶正交矩阵,且 \(U_1^\top U_2 = 0\)。
另一方面,容易得到:
\[ A^\top A V_2 = V_2 0 \Rightarrow V_2^\top A^\top A V_2 = 0 \]
根据矩阵性质\(A = 0 \Leftrightarrow A^\top A = 0\),我们可以得到\(AV_2=0\)。
\[ U^\top A V = \begin{bmatrix} U_1^\top A V_1 & U_1^\top A V_2 \\ U_2^\top A V_1 & U_2^\top A V_2 \end{bmatrix} = \begin{bmatrix} \Sigma_1 & 0 \\ U_2^T U_1 \Sigma_1 & 0 \end{bmatrix} = \begin{bmatrix} \Sigma_1 & 0 \\ 0 & 0 \end{bmatrix} = \Sigma \]
即,
\[ U A V^\top=\Sigma \]
几何理解
如果几何变换的方法为\(XA\),那么SVD将矩阵的线性变换拆解为三步:旋转(或方向调整)\(U\)- 缩放 \(\Sigma\) - 再旋转 \(V\),其中的缩放操作可以理解为,首先奇异值会对向量进行缩放:
- 如果m<n,会额外增加一些为0的维度
- 如果m>n,会删去一些维度
应用
在机器学习的PCA中使用较多,作为特征工程降低数据维度的一个重要方法。
在一些信号领域也可以用于去噪或者图像领域的数据压缩。
代码
Pytorch:
import torch
# 示例矩阵
A = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]])
# 计算 SVD
U, S, V = torch.svd(A)
print("U:", U)
print("S:", S) # 奇异值向量
print("V:", V)
numpy:
import numpy as np
# 示例矩阵
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 计算 SVD
U, sigma, VT = np.linalg.svd(A)
print("U:", U)
print("Sigma:", sigma)
print("V^T:", VT)
scikit-learn:
from sklearn.decomposition import TruncatedSVD
import numpy as np
# 示例矩阵
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 实例化 TruncatedSVD,指定保留的奇异值数量
svd = TruncatedSVD(n_components=2)
A_reduced = svd.fit_transform(A)
print("Reduced Matrix (A_reduced):")
print(A_reduced)
print("Explained Variance Ratio:", svd.explained_variance_ratio_)