奇异值分解 SVD

奇异值分解 SVD

学习目标

完成本节后,你将能够: - 理解 SVD 的几何和代数意义 - 计算 SVD 分解 - 应用 SVD 进行数据压缩和降维 - 理解 SVD 与 PCA 的关系

1. SVD 的几何意义

定理:任意 \(m \times n\) 矩阵 \(A\) 可以分解为:

\[A = U \Sigma V^T\]

其中 \(U\) 和 \(V\) 是正交矩阵,\(\Sigma\) 是对角矩阵(奇异值 \(\sigma_1 \geq \sigma_2 \geq \cdots \geq \sigma_r > 0\))。

几何分解: 1. \(V^T\):在输入空间旋转 2. \(\Sigma\):沿坐标轴缩放(\(\sigma_i\) 倍) 3. \(U\):在输出空间旋转

> **直觉 (3Blue1Brown)**:任何线性变换都可以分解为三个简单步骤:先旋转,再缩放,再旋转。SVD 就是这种分解的精确数学表达。与特征值分解不同,SVD 适用于**任意**形状的矩阵。

2. SVD 与特征值分解的关系

  • \(U\) 的列是 \(AA^T\) 的特征向量
  • \(V\) 的列是 \(A^T A\) 的特征向量
  • \(\sigma_i^2\) 是 \(A^T A\)(或 \(AA^T\))的特征值
def svd_manual(A):
    """手工计算 SVD"""
    # 计算 V 和 Σ:A^T A 的特征分解
    AT_A = A.T @ A
    eigvals_V, V = np.linalg.eigh(AT_A)
    idx = np.argsort(eigvals_V)[::-1]
    V = V[:, idx]

# 计算 U U = A @ V / s # 使 U 正交 U, _ = np.linalg.qr(U) return U, s, V.T

A = np.array([[3, 1], [1, 3], [0, 0]]) U_manual, s_manual, Vt_manual = svd_manual(A) U_scipy, s_scipy, Vt_scipy = np.linalg.svd(A) print("手工奇异值:", s_manual) print("scipy奇异值:", s_scipy) ```

3. SVD 与四个基本子空间

SVD 完整揭示四个基本子空间:

  • \(U\) 的前 \(r\) 列张成**列空间** \(C(A)\)
  • \(U\) 的后 \(m-r\) 列张成**左零空间** \(N(A^T)\)
  • \(V\) 的前 \(r\) 列张成**行空间** \(C(A^T)\)
  • \(V\) 的后 \(n-r\) 列张成**零空间** \(N(A)\)

这可能是理解 SVD 最重要的角度——它一次给出所有四个子空间的正交基。

4. 最佳低秩近似

Eckart-Young 定理:截断 SVD 给出矩阵的最佳秩 \(k\) 近似:

\[A_k = \sum_{i=1}^k \sigma_i u_i v_i^T\]

这是最小化 \(\|A - B\|_F\) 的秩 \(k\) 矩阵。

### 4.1 图像压缩

def svd_compress(A, k):
    """SVD 压缩"""
    U, s, Vt = np.linalg.svd(A, full_matrices=False)

# 模拟一个 100×100 的矩阵 np.random.seed(42) A = np.random.randn(100, 100)

# 不同压缩比 orig_size = 100 * 100 # 10000

for k in [5, 10, 20, 50]: A_k = svd_compress(A, k) error = np.linalg.norm(A - A_k) / np.linalg.norm(A) comp_size = k * (100 + 100 + 1) # U_k + s_k + V_k ratio = comp_size / orig_size print(f"k={k:2d}: 相对误差={error:.3f}, 压缩率={ratio:.1%}")

# 结论:k=20 时压缩率42%,误差已很小 ```

5. SVD 与 PCA

SVD 是主成分分析 (PCA) 的数学基础:

  1. 数据中心化:\(X \leftarrow X - \bar{X}\)
  2. 做 SVD:\(X = U\Sigma V^T\)
  3. 主成分方向 = \(V\) 的列
  4. 主成分得分 = \(U\Sigma\)
  5. 解释方差比 = \(\sigma_i^2 / \sum \sigma_j^2\)

6. 条件数

\[\kappa(A) = \frac{\sigma_{\max}}{\sigma_{\min}}\]

  • \(\kappa \approx 1\):良态(数值稳定)
  • \(\kappa\) 很大:病态(对误差敏感)
def condition_number(A):
    _, s, _ = np.linalg.svd(A)

# 对比良态和病态矩阵 well_conditioned = np.array([[1, 0], [0, 1]]) ill_conditioned = np.array([[1, 1], [1, 1.001]])

print("良态条件数:", condition_number(well_conditioned)) print("病态条件数:", condition_number(ill_conditioned)) ```

7. 本节习题

  1. 对 \(A = \begin{bmatrix} 2 & 0 \\ 0 & 3 \end{bmatrix}\) 做 SVD,与特征值分解对比
  2. 证明:\(\|A\|_2 = \sigma_{\max}(A)\)
  3. 用 SVD 计算 \(A\) 的伪逆 \(A^{+}\)
  4. 用 SVD 对一张简单的"图像"(16×16 矩阵)做压缩
  5. 解释为什么 \(\sigma_i^2\) 是 \(A^T A\) 的特征值

总结

- SVD 分解任意矩阵为旋转 × 缩放 × 旋转 - 完整揭示四个基本子空间 - 截断 SVD 给出矩阵的最佳低秩近似 - SVD 是 PCA、数据压缩、推荐系统的基础 - 条件数衡量数值稳定性