SVD(奇异值分解)被誉为线性代数的"皇冠明珠"——它能分解任何矩阵,不仅仅是方阵或对称矩阵。从图像压缩到
Netflix 推荐算法,从人脸识别到基因分析, SVD 无处不在。理解
SVD,就是掌握了数据科学最强大的数学工具之一。
引言:为什么 SVD 如此重要?
在前一章我们学习了对称矩阵的谱分解: 。但这有一个限制——矩阵必须是对称的 。
现实世界中,大多数矩阵都不对称:
图像矩阵( ,通常 )
用户-物品评分矩阵(推荐系统)
文档-词项矩阵(自然语言处理)
基因表达数据矩阵(生物信息学)
奇异值分解( SVD)
可以分解任意 矩阵:
这是线性代数中最强大、最有用的分解之一。
一个生活类比:理解 SVD 的本质
想象你是一位摄影师,想要理解一张照片的"本质"。照片可以看作一个矩阵——每个像素是一个数字。
SVD 告诉你:
任何照片都可以分解为若干"基础图层"的叠加
这些图层按重要性排序 ——第一层捕获最主要的结构,第二层捕获次要细节...
只保留前几层就能还原大部分信息
这就像乐队的录音可以分解为不同乐器的轨道:主唱、吉他、贝斯、鼓...有些轨道(如主唱)更"重要",去掉背景和声影响不大,但去掉主唱整首歌就变味了。
本章学习目标
SVD 的定义与几何意义 :理解 的含义
计算方法 :如何求奇异值和奇异向量
与特征分解的关系 : SVD 如何推广谱定理
低秩逼近 :最佳秩- 逼近定理
伪逆 :处理不可逆矩阵的通用方法
应用 :图像压缩、主成分分析、推荐系统、潜在语义分析
SVD 的定义
基本定理
奇异值分解定理 :任何 矩阵
都可以分解为:
其中:
- :
正交矩阵(左奇异向量 ) - : 对角矩阵(奇异值 ),对角元 - :
正交矩阵(右奇异向量 ) -
标准形式 :
关键性质 :
奇异值
永远是非负实数 (与特征值可能为负或复数不同)
奇异值按降序排列:
SVD 对任意矩阵都存在(这是它比特征分解更强大的原因)
几何意义:变换的"解剖"
SVD 告诉我们:任何线性变换都可以分解为三步 :
旋转/反射 ( ):在输入空间中旋转坐标系
拉伸 ( ):沿新坐标轴方向拉伸(或压缩)
旋转/反射 ( ):在输出空间中旋转坐标系
生活类比 :想象你在揉面团。
第一步( ) :把面团转到一个"方便操作"的角度
第二步( ) :用擀面杖把面团压扁、拉长——这是真正改变形状的步骤
第三步( ) :把压好的面团转到最终需要的方向
可视化理解 :
-
的列:输入空间的一组正交基,是变换作用的"最自然方向" -
的列:输出空间的一组正交基,是变换结果的"最自然方向" - :在第 个方向上的拉伸因子
单位圆经过矩阵 变换后变成椭圆。
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 npfrom PIL import Imageimport matplotlib.pyplot as pltimg = np.array(Image.open ('photo.jpg' ).convert('L' ), dtype=float ) U, s, Vt = np.linalg.svd(img, full_matrices=False ) 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:.1 f} %" )
伪逆
动机:当逆矩阵不存在时
对于方程 :
伪逆 (又称 Moore-Penrose
逆)提供了一个"最佳替代方案"。
定义
对于矩阵 ,伪逆 定义为:
其中 是 的伪逆:
即:非零对角元取倒数,零元素保持为零,然后转置(调整维度)。
性质
伪逆满足四个 Moore-Penrose 条件:
1.$AA^+A = A A+AA + =
A+ (AA +)^T =
AA+( AA +$ 是对称的)
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)
在自然语言处理中,文档-词项矩阵 :
LSA :对 进行
SVD,保留前 个奇异向量:
捕获"潜在语义"(主题)
降维:从数万维到几百维
应用:文档相似度、信息检索、同义词发现
信号去噪
模型 :观测信号 = 真实信号 + 噪声
如果真实信号是"低秩"的(有结构),而噪声是"满秩"的(随机):
SVD 分解观测信号
保留大奇异值(信号)
丢弃小奇异值(噪声)
人脸识别( Eigenfaces)
将人脸图像集合进行 PCA:
主成分 = "特征脸"( eigenfaces)
每张人脸 ≈ 特征脸的线性组合
识别:比较系数向量的距离
总结与展望
本章关键要点
SVD 定义 : - :左奇异向量(输出空间正交基)
- :奇异值(拉伸因子,永远非负)
- :右奇异向量(输入空间正交基)
几何意义 :任何线性变换 = 旋转 + 拉伸 +
旋转
计算方法 :
- : 的特征向量 - : 的特征向量 -
低秩逼近 :
Eckart-Young 定理:
是最佳秩- 逼近
应用:数据压缩、降噪
伪逆 : - 处理不可逆和非方阵矩阵
PCA : SVD 在数据分析中的核心应用
SVD vs 特征分解
特性
特征分解
SVD
适用矩阵
方阵(通常对称)
任意矩阵
分解形式
向量
特征向量
奇异向量
值
特征值(可负/复数)
奇异值(非负实数)
几何意义
不变方向+缩放
旋转+拉伸+旋转
为什么 SVD 是"皇冠明珠"?
普适性 :适用于任何矩阵
稳定性 :数值计算非常稳定
最优性 :低秩逼近的最优性保证
洞察力 :揭示矩阵的完整结构
应用广泛 :从图像压缩到推荐系统
下一章预告
《矩阵范数与条件数》
什么是"矩阵的大小"?
不同范数的意义和应用
条件数:矩阵有多"病态"?
数值稳定性分析
应用:误差分析、算法设计
理解范数和条件数对数值线性代数至关重要!
练习题
基础概念题
解释为什么奇异值永远是非负实数,而特征值可能是负数或复数。
计算 的 SVD(手工)。
证明: ( Frobenius 范数)。
为什么 和 有相同的奇异值?给出证明。
如果 是 矩阵, 的形状是什么? 和 分别是什么形状?
计算与证明题
证明: 非零奇异值的个数。
设 ,求其 SVD 和伪逆 。
证明 Eckart-Young 定理:
是最佳秩- 逼近。(提示:利用不等式 )
证明伪逆满足:
是到列空间的投影矩阵,
是到行空间的投影矩阵。
若
是正交矩阵,它的奇异值是什么?为什么?
应用题
图像压缩实验 :选择一张灰度图像,实现 SVD
压缩。
画出奇异值衰减曲线
比较
时的压缩图像
计算每种情况的 PSNR(峰值信噪比)
PCA 降维 :使用 Iris 数据集:
对数据进行 PCA
画出前两个主成分的散点图,用颜色区分三种花
计算前两个主成分解释的方差比例
简单推荐系统 :创建一个 5 用户× 10
电影的评分矩阵(部分缺失):
用 SVD 进行低秩近似( )
预测缺失评分
讨论结果的合理性
文本分析 :构造一个小型文档-词项矩阵( 5 个文档,
10 个词):
计算 SVD
解释前两个奇异向量的"语义"
计算文档之间的相似度
挑战题
SVD 与 2-范数 :证明矩阵的
2-范数(算子范数)等于最大奇异值: 。
随机矩阵的奇异值 :生成
的随机矩阵(元素独立同分布于 ),画出奇异值分布。与理论预测(
Marchenko-Pastur 分布)比较。
截断 SVD 的误差界 :证明 (
2-范数意义下的误差)。
条件数与 SVD :矩阵的条件数定义为 。解释为什么条件数大意味着矩阵"病态",求解 对误差敏感。
练习题详细答案
基础概念题答案
题
1 :为什么奇异值永远非负,而特征值可能是负数或复数?
答案 :
奇异值的定义 :奇异值是通过 或 的特征值得到的:
关键观察 : 1. 是对称正半定矩阵 2.
对称正半定矩阵的所有特征值 3.
因此 (平方根保证非负)
证明
正半定 :
对任意向量 :
特征值可能为负或复数的原因 :
特征值来自一般矩阵
的特征方程 :
非对称矩阵 :可能有复数特征值
负定矩阵 :所有特征值为负
总结 : - 奇异值 (来自正半定矩阵) - 特征值 (来自一般矩阵)
题 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 npA = np.array([[1 , 2 , 3 ], [4 , 5 , 6 ]]) 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 定理(概要)
定理 :秩-
近似 是最佳低秩逼近,即:
证明思路 :
计算 :
由题 3:
证明最优性 :
对任意秩不超过 的矩阵 ,
的零空间维度至少为 。
存在单位向量
则:
因此 是最优的
题 9 :证明
和 是投影矩阵
证明 :
设 ,则
证明
是投影到列空间 :
其中:
因此:
这是到 的正交投影!
验证投影性质 :
1. ✓(对称)
2. ✓(幂等)
类似地 ,
是到行空间 的投影
题 10 :正交矩阵的奇异值
答案 :所有奇异值都等于 1
证明 :
设 是正交矩阵,即
则:Extra close brace or missing open brace Q^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 npimport matplotlib.pyplot as pltfrom PIL import Imageimg = Image.open ('image.jpg' ).convert('L' ) A = np.array(img, dtype=float ) 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, :] 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:.2 f} 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) k_90 = np.where(cumulative_energy >= 0.9 )[0 ][0 ] + 1 print (f"90%能量需要的秩: {k_90} " )print (f"压缩率: {(1 - k_90/len (s))*100 :.1 f} %" )
分析 : - 秩-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 npimport matplotlib.pyplot as pltfrom sklearn import datasetsfrom sklearn.preprocessing import StandardScaleriris = datasets.load_iris() X = iris.data y = iris.target scaler = StandardScaler() X_std = scaler.fit_transform(X) U, s, Vt = np.linalg.svd(X_std, full_matrices=False ) X_pca = U[:, :2 ] @ np.diag(s[: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 npratings = 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 ) 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]:.2 f} " )
分析 : - 用户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 npdocuments = { 'doc1' : '机器学习 算法 数据' , 'doc2' : '深度学习 神经网络' , 'doc3' : '算法 数据结构' , 'doc4' : '数据科学 分析' , 'doc5' : '神经网络 深度学习' } doc_term = np.array([ [2 , 1 , 2 , 0 , 0 , 0 , 0 , 0 , 1 , 0 ], [0 , 0 , 0 , 2 , 2 , 0 , 0 , 0 , 0 , 0 ], [0 , 2 , 0 , 0 , 0 , 2 , 0 , 0 , 1 , 0 ], [0 , 0 , 3 , 0 , 0 , 0 , 1 , 1 , 0 , 0 ], [0 , 0 , 0 , 2 , 2 , 0 , 0 , 0 , 0 , 0 ] ], dtype=float ) 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 ]:.2 f} , {coord[1 ]:.2 f} )" ) 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:.3 f} " )
分析 : - 第一奇异向量:捕获"技术"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 npimport matplotlib.pyplot as pltn = 100 A = np.random.randn(n, n) / np.sqrt(n) U, s, Vt = np.linalg.svd(A) plt.figure(figsize=(12 , 5 )) 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 ) 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 ) 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 ]:.3 f} " )print (f"最小奇异值: {s[-1 ]:.3 f} " )print (f"条件数: {s[0 ]/s[-1 ]:.1 f} " )
观察 : - 奇异值分布接近半圆律( 时) - 最大奇异值 - 大部分奇异值集中在 区间
题 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 npA_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:.0 f} " )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:.1 f} " )
输出 : 1 2 病态矩阵条件数: 20001 良态矩阵条件数: 1.0
参考资料
Strang, G. (2019). Introduction to Linear
Algebra . 5th ed. Chapter 7.
Trefethen, L. N., & Bau, D. (1997).
Numerical Linear Algebra . SIAM.
Golub, G. H., & Van Loan, C. F. (2013).
Matrix Computations . 4th ed. Johns Hopkins.
Hastie, T., Tibshirani, R., & Friedman, J.
(2009). The Elements of Statistical Learning . Springer.
Koren, Y., Bell, R., & Volinsky, C. (2009).
"Matrix Factorization Techniques for Recommender Systems".
Computer , 42(8).
3Blue1Brown . Essence of Linear Algebra
series. YouTube.
本文是《线性代数的本质与应用》系列的第 9 章,共 18 章。