线性代数(九)奇异值分解 SVD
Chen Kai BOSS

SVD(奇异值分解)被誉为线性代数的"皇冠明珠"——它能分解任何矩阵,不仅仅是方阵或对称矩阵。从图像压缩到 Netflix 推荐算法,从人脸识别到基因分析, SVD 无处不在。理解 SVD,就是掌握了数据科学最强大的数学工具之一。

引言:为什么 SVD 如此重要?

在前一章我们学习了对称矩阵的谱分解:。但这有一个限制——矩阵必须是对称的

现实世界中,大多数矩阵都不对称:

  • 图像矩阵(,通常
  • 用户-物品评分矩阵(推荐系统)
  • 文档-词项矩阵(自然语言处理)
  • 基因表达数据矩阵(生物信息学)

奇异值分解( SVD) 可以分解任意 矩阵:

这是线性代数中最强大、最有用的分解之一。

一个生活类比:理解 SVD 的本质

想象你是一位摄影师,想要理解一张照片的"本质"。照片可以看作一个矩阵——每个像素是一个数字。 SVD 告诉你:

  1. 任何照片都可以分解为若干"基础图层"的叠加
  2. 这些图层按重要性排序——第一层捕获最主要的结构,第二层捕获次要细节...
  3. 只保留前几层就能还原大部分信息

这就像乐队的录音可以分解为不同乐器的轨道:主唱、吉他、贝斯、鼓...有些轨道(如主唱)更"重要",去掉背景和声影响不大,但去掉主唱整首歌就变味了。

本章学习目标

  1. SVD 的定义与几何意义:理解 的含义
  2. 计算方法:如何求奇异值和奇异向量
  3. 与特征分解的关系: SVD 如何推广谱定理
  4. 低秩逼近:最佳秩- 逼近定理
  5. 伪逆:处理不可逆矩阵的通用方法
  6. 应用:图像压缩、主成分分析、推荐系统、潜在语义分析

SVD 的定义

基本定理

奇异值分解定理:任何 矩阵 都可以分解为:

其中:

- 正交矩阵(左奇异向量) - 对角矩阵(奇异值),对角元 - 正交矩阵(右奇异向量) -

标准形式

关键性质

  • 奇异值 永远是非负实数(与特征值可能为负或复数不同)
  • 奇异值按降序排列:
  • SVD 对任意矩阵都存在(这是它比特征分解更强大的原因)

几何意义:变换的"解剖"

SVD 告诉我们:任何线性变换都可以分解为三步

  1. 旋转/反射):在输入空间中旋转坐标系
  2. 拉伸):沿新坐标轴方向拉伸(或压缩)
  3. 旋转/反射):在输出空间中旋转坐标系

生活类比:想象你在揉面团。

  • 第一步(:把面团转到一个"方便操作"的角度
  • 第二步(:用擀面杖把面团压扁、拉长——这是真正改变形状的步骤
  • 第三步(:把压好的面团转到最终需要的方向

可视化理解

- 的列:输入空间的一组正交基,是变换作用的"最自然方向" - 的列:输出空间的一组正交基,是变换结果的"最自然方向" -:在第 个方向上的拉伸因子

单位圆经过矩阵 变换后变成椭圆。 SVD 告诉我们:

  • 椭圆的主轴方向由 的列决定
  • 椭圆的半轴长度就是奇异值
  • 输入空间中的"特殊方向"由 的列给出

外积形式

SVD 还有一个重要的等价表达——外积展开

每个 是一个秩 1 矩阵。所以:

任何矩阵都是若干秩 1 矩阵的加权和,权重就是奇异值。

这个视角在低秩逼近中至关重要。

例子

考虑 矩阵:

SVD 分解(计算过程后面详述):

奇异值: 几何意义:单位圆 → 旋转 45 ° → 沿 x 轴拉伸 5 倍、沿 y 轴拉伸 1 倍 → 旋转到最终位置

SVD 的计算

的关系

SVD 与对称矩阵的谱分解紧密相关。

关键观察

-都是对称半正定矩阵 - 它们的非零特征值相同 - 它们的特征向量分别是 的列

详细推导

因为。注意 是对角矩阵,对角元为

这正是 的谱分解!

结论

- 的列是 的特征向量(右奇异向量) - 的特征值 -奇异值

类似地:

- 的列是 的特征向量(左奇异向量

直觉理解:为什么要用 可以理解为" 作用两次"的效果:先用 变换,再用 变换回来。这个往返过程放大了 的"主要作用方向"——奇异值大的方向被放大得更厉害( 倍),奇异值小的方向被压制。

计算步骤

给定 矩阵(假设):

步骤 1:计算 的特征值和特征向量

  • 特征值:
  • 特征向量:(正交归一化)
  • 这些 组成矩阵 步骤 2:计算奇异值 - 步骤 3:计算左奇异向量 -(对
  • 如果,需要扩展为完整的正交基

步骤 4:构造 为什么

可以推出。取第 列:

所以(假设)。

例子:手工计算 SVD

计算 的 SVD 。

步骤 1:计算

特征方程:

特征值: 特征向量(归一化):

-: -: 步骤 2:奇异值

步骤 3:左奇异向量

计算得: 类似: 结果

SVD 与四个基本子空间

SVD 优雅地揭示了矩阵的四个基本子空间。

四个子空间的关系

对于,秩):

行空间

  • 维度:
  • 基: 的前

零空间

  • 维度:
  • 基: 的后

列空间

  • 维度:
  • 基: 的前

左零空间

  • 维度:
  • 基: 的后

关键洞察

- 的列给出定义域的正交分解:行空间零空间 - 的列给出值域的正交分解:列空间 左零空间

SVD 的几何图像

SVD 给出了 作用的完整图像:

意义

  • 行空间的正交基被映射到列空间的正交基
  • 每个被拉伸
  • 零空间被映射到零

低秩逼近

SVD 最重要的应用之一是最佳低秩逼近。这是数据压缩、降噪、推荐系统的理论基础。

Eckart-Young 定理

定理:设 是秩 矩阵的 SVD 。定义秩- 截断:

其中 的前 列, 是前 个奇异值的对角矩阵。

是所有秩 矩阵中最接近 的矩阵(在 Frobenius 范数意义下):

意义

  • 保留前 个奇异值/向量,丢弃其余
  • 这是最优的秩逼近——没有任何其他秩 矩阵能更接近
  • 误差由被丢弃的奇异值决定

生活类比:这就像音乐压缩。 MP3 格式丢弃人耳不敏感的高频成分,保留最重要的频率。 SVD 同理——保留"能量"最大的几个分量。

能量观点

奇异值的平方和等于矩阵的 Frobenius 范数平方:

个奇异值捕获的"能量"比例:

实际观察:大部分矩阵的奇异值快速衰减。例如,一张 1000 × 1000 的自然图像,前 50 个奇异值可能捕获 95%的能量。

应用:图像压缩

图像可以看作矩阵(灰度值)。用低秩逼近压缩:

原始图像 矩阵,存储 个数

压缩图像(秩):

  • 存储:)+ 个数)+
  • 总计: 个数
  • 压缩率: 例子 图像,用秩 近似:
  • 原始: 个数
  • 压缩: 个数
  • 压缩率:约 10%

Python 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt

# 读取图像并转为灰度
img = np.array(Image.open('photo.jpg').convert('L'), dtype=float)

# SVD 分解
U, s, Vt = np.linalg.svd(img, full_matrices=False)

# 保留前 k 个奇异值
def compress(U, s, Vt, k):
return U[:, :k] @ np.diag(s[:k]) @ Vt[:k, :]

# 不同压缩级别
for k in [5, 20, 50, 100]:
compressed = compress(U, s, Vt, k)
energy = sum(s[:k]**2) / sum(s**2) * 100
print(f"k={k}: 能量保留 {energy:.1f}%")

伪逆

动机:当逆矩阵不存在时

对于方程

  • 如果 可逆,解是
  • 如果 不可逆或非方阵呢?

伪逆(又称 Moore-Penrose 逆)提供了一个"最佳替代方案"。

定义

对于矩阵伪逆 定义为:

其中 的伪逆:

即:非零对角元取倒数,零元素保持为零,然后转置(调整维度)。

性质

伪逆满足四个 Moore-Penrose 条件:

1.$AA^+A = AA+AA+ = A+(AA+)^T = AA+AA+$ 是对称的) 2. 是对称的)

特殊情况:如果 可逆,

最小二乘解

对于方程

最小二乘解(最小化):

如果有多个最小二乘解, 是其中范数最小的解。

几何解释 做了两件事:

  1. 投影到列空间(找最接近的可达点)
  2. 在所有能到达投影点的 中,选范数最小的

应用:过定和欠定系统

过定系统,方程多于未知数):

  • 通常无精确解 - 给出最小二乘解

欠定系统,未知数多于方程):

  • 通常有无穷多解 - 给出最小范数解

实际应用:机器学习中的线性回归、数据拟合、系统辨识都大量使用伪逆。

主成分分析( PCA)

PCA 与 SVD 的关系

主成分分析是数据降维的经典方法,其核心就是 SVD 。

给定数据矩阵 个样本, 个特征):

步骤 1:中心化数据

(每列减去其均值)

步骤 2:对 进行 SVD

则:

  • 主成分方向 的列(右奇异向量)
  • 主成分得分
  • 方差解释 是第 主成分的方差

降维:保留前 个主成分:

为什么 PCA 有效?

PCA 寻找数据变化最大的方向:

第一主成分:方差最大的方向

第二主成分:与 正交,方差次大的方向

结论:这正是 SVD 给出的右奇异向量。

生活类比:想象你有一团数据点的"云"。 PCA 找到云最"扁"的方向和最"长"的方向。最长的方向(方差最大)是第一主成分——它捕获数据最多的变化。

应用:数据可视化

高维数据(如 100 维)→ 投影到前 2 或 3 个主成分 → 可视化

例子:手写数字识别。每张 的图片是 784 维向量。用 PCA 投影到 2 维,不同数字形成不同的聚类。

推荐系统中的 SVD

问题背景

Netflix 、 Amazon 、淘宝等平台面临一个核心问题:如何预测用户对未评价商品的喜好?

用户-物品评分矩阵 用户 × 物品):

  • 已知部分:用户已评价的物品
  • 目标:预测缺失的评分

矩阵分解思想

核心假设:评分由少数"潜在因子"决定。

例如电影评分可能由以下潜在因子决定:

  • 动作程度
  • 浪漫程度
  • 幽默程度
  • 深度/艺术性
  • ...

每个用户对这些因子有不同偏好,每部电影在这些因子上有不同得分。

SVD 方法

- 的行:每个用户的"潜在因子向量" - 的行:每个物品的"潜在因子向量" - 预测评分 ≈ 用户因子 · 物品因子

Netflix Prize

Netflix 在 2006-2009 年举办百万美元大奖赛:

  • 任务:预测用户电影评分
  • 数据: 1 亿条评分记录
  • 目标:比 Netflix 算法准确 10%

获胜方法的核心:矩阵分解( SVD 的变种),处理稀疏数据和隐式反馈。

其他应用

潜在语义分析( LSA)

在自然语言处理中,文档-词项矩阵

  • 行:文档
  • 列:词汇
  • 元素:词频( TF-IDF)

LSA:对 进行 SVD,保留前 个奇异向量:

  • 捕获"潜在语义"(主题)
  • 降维:从数万维到几百维
  • 应用:文档相似度、信息检索、同义词发现

信号去噪

模型:观测信号 = 真实信号 + 噪声

如果真实信号是"低秩"的(有结构),而噪声是"满秩"的(随机):

  • SVD 分解观测信号
  • 保留大奇异值(信号)
  • 丢弃小奇异值(噪声)

人脸识别( Eigenfaces)

将人脸图像集合进行 PCA:

  • 主成分 = "特征脸"( eigenfaces)
  • 每张人脸 ≈ 特征脸的线性组合
  • 识别:比较系数向量的距离

总结与展望

本章关键要点

  1. SVD 定义 -:左奇异向量(输出空间正交基)

    -:奇异值(拉伸因子,永远非负) -:右奇异向量(输入空间正交基)

  2. 几何意义:任何线性变换 = 旋转 + 拉伸 + 旋转

  3. 计算方法

    - 的特征向量 - 的特征向量 -

  4. 低秩逼近

    • Eckart-Young 定理: 是最佳秩-逼近
    • 应用:数据压缩、降噪
  5. 伪逆 - 处理不可逆和非方阵矩阵

    • 给出最小二乘解和最小范数解
  6. PCA: SVD 在数据分析中的核心应用

SVD vs 特征分解

特性 特征分解 SVD
适用矩阵 方阵(通常对称) 任意矩阵
分解形式
向量 特征向量 奇异向量
特征值(可负/复数) 奇异值(非负实数)
几何意义 不变方向+缩放 旋转+拉伸+旋转

为什么 SVD 是"皇冠明珠"?

  1. 普适性:适用于任何矩阵
  2. 稳定性:数值计算非常稳定
  3. 最优性:低秩逼近的最优性保证
  4. 洞察力:揭示矩阵的完整结构
  5. 应用广泛:从图像压缩到推荐系统

下一章预告

《矩阵范数与条件数》

  • 什么是"矩阵的大小"?
  • 不同范数的意义和应用
  • 条件数:矩阵有多"病态"?
  • 数值稳定性分析
  • 应用:误差分析、算法设计

理解范数和条件数对数值线性代数至关重要!

练习题

基础概念题

  1. 解释为什么奇异值永远是非负实数,而特征值可能是负数或复数。
  2. 计算 的 SVD(手工)。
  3. 证明:( Frobenius 范数)。
  4. 为什么 有相同的奇异值?给出证明。
  5. 如果 矩阵, 的形状是什么? 分别是什么形状?

计算与证明题

  1. 证明:非零奇异值的个数。
  2. ,求其 SVD 和伪逆
  3. 证明 Eckart-Young 定理: 是最佳秩-逼近。(提示:利用不等式
  4. 证明伪逆满足: 是到列空间的投影矩阵, 是到行空间的投影矩阵。
  5. 是正交矩阵,它的奇异值是什么?为什么?

应用题

  1. 图像压缩实验:选择一张灰度图像,实现 SVD 压缩。

    • 画出奇异值衰减曲线
    • 比较 时的压缩图像
    • 计算每种情况的 PSNR(峰值信噪比)
  2. PCA 降维:使用 Iris 数据集:

    • 对数据进行 PCA
    • 画出前两个主成分的散点图,用颜色区分三种花
    • 计算前两个主成分解释的方差比例
  3. 简单推荐系统:创建一个 5 用户× 10 电影的评分矩阵(部分缺失):

    • 用 SVD 进行低秩近似(
    • 预测缺失评分
    • 讨论结果的合理性
  4. 文本分析:构造一个小型文档-词项矩阵( 5 个文档, 10 个词):

    • 计算 SVD
    • 解释前两个奇异向量的"语义"
    • 计算文档之间的相似度

挑战题

  1. SVD 与 2-范数:证明矩阵的 2-范数(算子范数)等于最大奇异值:
  2. 随机矩阵的奇异值:生成 的随机矩阵(元素独立同分布于),画出奇异值分布。与理论预测( Marchenko-Pastur 分布)比较。
  3. 截断 SVD 的误差界:证明( 2-范数意义下的误差)。
  4. 条件数与 SVD:矩阵的条件数定义为。解释为什么条件数大意味着矩阵"病态",求解 对误差敏感。

练习题详细答案

基础概念题答案

题 1:为什么奇异值永远非负,而特征值可能是负数或复数?

答案

奇异值的定义:奇异值是通过 的特征值得到的:

关键观察: 1.对称正半定矩阵 2. 对称正半定矩阵的所有特征值 3. 因此(平方根保证非负)

证明 正半定

对任意向量

特征值可能为负或复数的原因

特征值来自一般矩阵 的特征方程

  1. 非对称矩阵:可能有复数特征值
    • 例:(旋转矩阵)
    • 特征值:
  2. 负定矩阵:所有特征值为负
    • 例:
    • 特征值:

总结: - 奇异值(来自正半定矩阵) - 特征值(来自一般矩阵)


题 2:计算 的 SVD

答案

步骤 1:计算

步骤 2:求 的特征值

因此: - -

奇异值

步骤 3:求右奇异向量

:类似求得

步骤 4:求左奇异向量

最终 SVD


题 3:证明

证明

Frobenius 范数定义

利用 SVD

计算迹

利用迹的循环性质

结论


题 4:为什么 有相同的奇异值?

证明

的 SVD 为

观察: - 的奇异值矩阵是 - 对于对角矩阵, 的对角元素相同

严格证明 的奇异值来自 的特征值:

的奇异值来自 的特征值(注意):

关键 有相同的非零特征值!

证明:若 的特征值,特征向量为

两边左乘

因此 也是 的特征值,特征向量为

结论 有相同的奇异值


题 5 的形状、 的形状

答案

矩阵

的形状(与 相同)

的形状

这是 对角矩阵,前 个对角元为,其余为 0。

的形状

这是 对角矩阵,前 个对角元为,其余为 0。

总结: - -(与 同形) -(与 同形)


计算与证明题答案

题 6:证明 非零奇异值的个数

证明

方法 1:通过秩的定义,其中 是正交矩阵

由于正交矩阵是可逆的(满秩): 是对角矩阵:

对角矩阵的秩 = 非零对角元个数 =

方法 2:通过列空间 的列空间由 的线性独立列张成。

在 SVD 中: 的列是 的线性组合。

由于 正交(线性独立), 的列空间由 个独立向量张成。

因此 = 非零奇异值个数


题 7:计算 的 SVD 和伪逆

答案

使用 Python 计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import numpy as np

A = np.array([[1, 2, 3],
[4, 5, 6]])

# SVD
U, s, Vt = np.linalg.svd(A)

print("U =")
print(U)
print("\nSingular values:", s)
print("\nV^T =")
print(Vt)

# 伪逆
A_pinv = np.linalg.pinv(A)
print("\nPseudoinverse A+ =")
print(A_pinv)

# 验证
print("\nVerification: A @ A+ @ A =")
print(A @ A_pinv @ A)

输出结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
U =
[[-0.386 0.922]
[-0.922 -0.386]]

Singular values: [9.508 0.773]

V^T =
[[-0.429 -0.566 -0.704]
[ 0.806 0.112 -0.582]
[-0.408 0.816 -0.408]]

Pseudoinverse A+ =
[[-0.944 0.444]
[-0.111 0.111]
[ 0.722 -0.222]]

手工验证伪逆性质

其中


题 8:证明 Eckart-Young 定理(概要)

定理:秩- 近似 是最佳低秩逼近,即:

证明思路

  1. 计算

由题 3:

  1. 证明最优性

对任意秩不超过 的矩阵 的零空间维度至少为

存在单位向量

则:

因此 是最优的


题 9:证明 是投影矩阵

证明

,则

证明 是投影到列空间

其中:

因此:

这是到 的正交投影!

验证投影性质

1. ✓(对称) 2. ✓(幂等)

类似地 是到行空间 的投影


题 10:正交矩阵的奇异值

答案所有奇异值都等于 1

证明

是正交矩阵,即

则:Extra close brace or missing open braceQ^TQ = I \Rightarrow \text{eigenvalues of } Q^TQ = \{1, 1, \ldots, 1\\}

奇异值

几何解释

正交矩阵保持向量长度不变(等距变换),因此"拉伸因子"都是 1。

例子

  • 旋转矩阵:
  • 反射矩阵:

应用题答案

题 11:图像压缩实验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

# 读取灰度图像
img = Image.open('image.jpg').convert('L')
A = np.array(img, dtype=float)

# SVD分解
U, s, Vt = np.linalg.svd(A, full_matrices=False)

# 不同秩的近似
fig, axes = plt.subplots(2, 3, figsize=(15, 10))

ranks = [10, 50, 100, 200, 'full']
positions = [(0,0), (0,1), (0,2), (1,0), (1,1)]

for rank, pos in zip(ranks, positions):
ax = axes[pos]

if rank == 'full':
compressed = A
title = f'原始图像'
else:
# 低秩逼近
compressed = U[:, :rank] @ np.diag(s[:rank]) @ Vt[:rank, :]

# 计算PSNR
mse = np.mean((A - compressed)**2)
if mse == 0:
psnr = 100
else:
max_pixel = 255.0
psnr = 20 * np.log10(max_pixel / np.sqrt(mse))

title = f'秩-{rank}\nPSNR: {psnr:.2f} dB'

ax.imshow(compressed, cmap='gray')
ax.set_title(title, fontsize=11)
ax.axis('off')

# 奇异值衰减曲线
ax = axes[1, 2]
ax.plot(range(1, min(100, len(s))+1), s[:100], 'b-', linewidth=2)
ax.set_xlabel('奇异值索引', fontsize=10)
ax.set_ylabel('奇异值大小', fontsize=10)
ax.set_title('奇异值衰减曲线', fontsize=11)
ax.grid(True, alpha=0.3)
ax.set_yscale('log')

plt.tight_layout()
plt.savefig('svd_image_compression.png', dpi=150)
plt.show()

# 计算累积能量
energy = s**2
cumulative_energy = np.cumsum(energy) / np.sum(energy)

# 找到90%能量对应的秩
k_90 = np.where(cumulative_energy >= 0.9)[0][0] + 1
print(f"90%能量需要的秩: {k_90}")
print(f"压缩率: {(1 - k_90/len(s))*100:.1f}%")

分析: - 秩-10:PSNR ~20dB(轮廓可见) - 秩-50:PSNR ~30dB(细节清晰) - 秩-100:PSNR ~35dB(接近原始)


题 12:PCA降维(Iris数据集)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.preprocessing import StandardScaler

# 加载Iris数据
iris = datasets.load_iris()
X = iris.data # 4维特征
y = iris.target # 3类标签

# 标准化
scaler = StandardScaler()
X_std = scaler.fit_transform(X)

# 方法1:使用SVD进行PCA
U, s, Vt = np.linalg.svd(X_std, full_matrices=False)

# 前两个主成分
X_pca = U[:, :2] @ np.diag(s[:2])

# 或者直接:X_pca = X_std @ Vt.T[:, :2]

# 可视化
plt.figure(figsize=(10, 7))
colors = ['red', 'green', 'blue']
labels = ['Setosa', 'Versicolor', 'Virginica']

for i, (color, label) in enumerate(zip(colors, labels)):
plt.scatter(X_pca[y==i, 0], X_pca[y==i, 1],
c=color, label=label, s=50, alpha=0.7)

plt.xlabel('第一主成分', fontsize=12)
plt.ylabel('第二主成分', fontsize=12)
plt.title('Iris数据集PCA降维(4D→2D)', fontsize=14, fontweight='bold')
plt.legend(fontsize=11)
plt.grid(True, alpha=0.3)
plt.show()

# 方差解释率
explained_variance = (s**2) / (len(X) - 1)
explained_variance_ratio = explained_variance / explained_variance.sum()

print(f"第一主成分解释方差: {explained_variance_ratio[0]:.2%}")
print(f"第二主成分解释方差: {explained_variance_ratio[1]:.2%}")
print(f"前两个主成分总计: {explained_variance_ratio[:2].sum():.2%}")

输出

1
2
3
第一主成分解释方差: 72.96%
第二主成分解释方差: 22.85%
前两个主成分总计: 95.81%

结论:前两个主成分保留了95.8%的信息!


题 13:简单推荐系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import numpy as np

# 创建评分矩阵(5用户×10电影)
# 0表示未评分
ratings = np.array([
[5, 3, 0, 1, 0, 0, 4, 0, 0, 2],
[4, 0, 0, 2, 0, 5, 0, 0, 3, 0],
[0, 0, 5, 4, 5, 0, 0, 3, 0, 0],
[0, 3, 4, 0, 3, 0, 0, 0, 0, 5],
[1, 0, 0, 0, 0, 4, 0, 5, 4, 0]
], dtype=float)

# 用平均值填充缺失(预处理)
mask = ratings > 0
mean_ratings = np.sum(ratings, axis=1, keepdims=True) / np.sum(mask, axis=1, keepdims=True)

# SVD(秩-2近似)
U, s, Vt = np.linalg.svd(ratings, full_matrices=False)

# 低秩重构
k = 2
ratings_pred = U[:, :k] @ np.diag(s[:k]) @ Vt[:k, :]

print("原始评分矩阵:")
print(ratings)
print("\n预测评分矩阵(秩-2):")
print(np.round(ratings_pred, 2))

# 预测缺失评分
print("\n缺失评分预测:")
for i in range(5):
for j in range(10):
if ratings[i, j] == 0:
print(f"用户{i+1}对电影{j+1}: {ratings_pred[i,j]:.2f}")

分析: - 用户1和用户2评分模式相似 → 可以互相推荐 - 电影1-4可能是同一类型(奇异向量相似) - 秩-2捕获了"用户偏好"和"电影类型"两个潜在因子


题 14:文本分析(LSA)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import numpy as np

# 文档-词项矩阵(5文档×10词)
# 行:文档,列:词
documents = {
'doc1': '机器学习 算法 数据',
'doc2': '深度学习 神经网络',
'doc3': '算法 数据结构',
'doc4': '数据科学 分析',
'doc5': '神经网络 深度学习'
}

# 简化矩阵(词频)
doc_term = np.array([
[2, 1, 2, 0, 0, 0, 0, 0, 1, 0], # doc1
[0, 0, 0, 2, 2, 0, 0, 0, 0, 0], # doc2
[0, 2, 0, 0, 0, 2, 0, 0, 1, 0], # doc3
[0, 0, 3, 0, 0, 0, 1, 1, 0, 0], # doc4
[0, 0, 0, 2, 2, 0, 0, 0, 0, 0] # doc5
], dtype=float)

# SVD
U, s, Vt = np.linalg.svd(doc_term, full_matrices=False)

print("前两个奇异值:", s[:2])
print("\n前两个右奇异向量(词的语义):")
print(Vt[:2, :])

# 文档在潜在语义空间中的坐标
doc_coords = U[:, :2] @ np.diag(s[:2])

print("\n文档坐标(2D语义空间):")
for i, coord in enumerate(doc_coords):
print(f"doc{i+1}: ({coord[0]:.2f}, {coord[1]:.2f})")

# 计算文档相似度(余弦相似度)
def cosine_similarity(v1, v2):
return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))

print("\n文档相似度矩阵:")
for i in range(5):
for j in range(i+1, 5):
sim = cosine_similarity(doc_coords[i], doc_coords[j])
print(f"doc{i+1} vs doc{j+1}: {sim:.3f}")

分析: - 第一奇异向量:捕获"技术"vs"应用"维度 - 第二奇异向量:捕获"学习"vs"结构"维度 - doc2和doc5最相似(都关于深度学习)


挑战题答案

题 15:证明

证明

2-范数(算子范数)定义

,则:

(因为 是正交矩阵,保持范数)

,则 正交)

等号成立当且仅当

结论


题 16:随机矩阵奇异值分布

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import numpy as np
import matplotlib.pyplot as plt

# 生成随机矩阵
n = 100
A = np.random.randn(n, n) / np.sqrt(n)

# SVD
U, s, Vt = np.linalg.svd(A)

# 绘制奇异值分布
plt.figure(figsize=(12, 5))

# 子图1:直方图
plt.subplot(121)
plt.hist(s, bins=30, density=True, alpha=0.7, edgecolor='black')
plt.xlabel('奇异值', fontsize=11)
plt.ylabel('密度', fontsize=11)
plt.title('随机矩阵奇异值分布\n(100×100,标准正态)', fontsize=12, fontweight='bold')
plt.grid(True, alpha=0.3)

# 理论预测(Marchenko-Pastur分布,当m=n时退化为半圆律)
# 半圆律: rho(x) = sqrt(4-x^2) / (2*pi) for |x| <= 2
x = np.linspace(0, 2.5, 1000)
theoretical = np.sqrt(np.maximum(4 - x**2, 0)) / np.pi
plt.plot(x, theoretical, 'r-', linewidth=2, label='半圆律(理论)')
plt.legend(fontsize=10)

# 子图2:累积分布
plt.subplot(122)
plt.plot(sorted(s, reverse=True), 'b-', linewidth=2)
plt.xlabel('奇异值索引', fontsize=11)
plt.ylabel('奇异值大小', fontsize=11)
plt.title('奇异值衰减', fontsize=12, fontweight='bold')
plt.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

print(f"最大奇异值: {s[0]:.3f}")
print(f"最小奇异值: {s[-1]:.3f}")
print(f"条件数: {s[0]/s[-1]:.1f}")

观察: - 奇异值分布接近半圆律(时) - 最大奇异值 - 大部分奇异值集中在 区间


题 17:证明

证明

由题 15,矩阵的 2-范数等于最大奇异值。 的奇异值是

因此:

(因为奇异值降序排列)


题 18:条件数与病态矩阵

答案

条件数定义

为什么大条件数意味着"病态"

考虑线性方程组

有小扰动,解的变化满足:

解释: - 大 → 输出误差被放大很多倍 - → 良态(well-conditioned) - → 病态(ill-conditioned)

几何直觉 大意味着: - 某个方向被强烈拉伸() - 某个方向几乎被压扁() - 沿压扁方向的微小误差在逆变换时被巨大放大

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np

# 病态矩阵
A_bad = np.array([[1, 1],
[1, 1.0001]])

s_bad = np.linalg.svd(A_bad, compute_uv=False)
kappa_bad = s_bad[0] / s_bad[1]

print(f"病态矩阵条件数: {kappa_bad:.0f}")

# 良态矩阵
A_good = np.eye(2)
s_good = np.linalg.svd(A_good, compute_uv=False)
kappa_good = s_good[0] / s_good[1]

print(f"良态矩阵条件数: {kappa_good:.1f}")

输出

1
2
病态矩阵条件数: 20001
良态矩阵条件数: 1.0


参考资料

  1. Strang, G. (2019). Introduction to Linear Algebra. 5th ed. Chapter 7.
  2. Trefethen, L. N., & Bau, D. (1997). Numerical Linear Algebra. SIAM.
  3. Golub, G. H., & Van Loan, C. F. (2013). Matrix Computations. 4th ed. Johns Hopkins.
  4. Hastie, T., Tibshirani, R., & Friedman, J. (2009). The Elements of Statistical Learning. Springer.
  5. Koren, Y., Bell, R., & Volinsky, C. (2009). "Matrix Factorization Techniques for Recommender Systems". Computer, 42(8).
  6. 3Blue1Brown. Essence of Linear Algebra series. YouTube.

本文是《线性代数的本质与应用》系列的第 9 章,共 18 章。

  • 本文标题:线性代数(九)奇异值分解 SVD
  • 本文作者:Chen Kai
  • 创建时间:2019-02-17 14:45:00
  • 本文链接:https://www.chenk.top/%E7%BA%BF%E6%80%A7%E4%BB%A3%E6%95%B0%EF%BC%88%E4%B9%9D%EF%BC%89%E5%A5%87%E5%BC%82%E5%80%BC%E5%88%86%E8%A7%A3SVD/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论