DAY 20 奇异值SVD分解-2025.9.1
奇异值SVD分解
知识点回顾:
- 线性代数概念回顾
- 奇异值推导
- 奇异值的应用
a. 特征降维:对高维数据减小计算量、可视化
b. 数据重构:比如重构信号、重构图像(可以实现有损压缩,k 越小压缩率越高,但图像质量损失越大)
c. 降噪:通常噪声对应较小的奇异值。通过丢弃这些小奇异值并重构矩阵,可以达到一定程度的降噪效果。
d. 推荐系统:在协同过滤算法中,用户-物品评分矩阵通常是稀疏且高维的。SVD (或其变种如 FunkSVD, SVD++) 可以用来分解这个矩阵,发现潜在因子 (latent factors),从而预测未评分的项。这里其实属于特征降维的部分。
知识点回顾:
对于任何矩阵(如结构化数据可以变为:样本*特征的矩阵,图像数据天然就是矩阵),均可做等价的奇异值SVD分解,对于分解后的矩阵,可以选取保留前K个奇异值及其对应的奇异向量,重构原始矩阵,可以通过计算Frobenius 范数相对误差来衡量原始矩阵和重构矩阵的差异。
应用:结构化数据中,将原来的m个特征降维成k个新的特征,新特征是原始特征的线性组合,捕捉了数据的主要方差信息,降维后的数据可以直接用于机器学习模型(如分类、回归),通常能提高计算效率并减少过拟合风险。
ps:在进行 SVD 之前,通常需要对数据进行标准化(均值为 0,方差为 1),以避免某些特征的量纲差异对降维结果的影响。
作业:尝试利用svd来处理心脏病预测,看下精度变化
笔记:
奇异值分解(Singular Value Decomposition, SVD)是线性代数中极具影响力的工具,其核心价值在于能处理任意形状的矩阵,同时在高维数据处理场景中发挥关键作用。以下将从线性代数基础回顾切入,逐步推导奇异值的数学逻辑,最终结合实际场景解析应用,形成完整的知识闭环。
一、线性代数概念回顾(SVD 的数学基础)
SVD 的推导依赖线性代数中 “矩阵变换”“特征值与特征向量” 等核心概念,需先明确以下基础:
1. 矩阵的几何意义:线性变换
任意一个 m×n 矩阵 A,本质是一种从 n 维空间到 m 维空间的线性变换,其作用包括:
- 拉伸 / 压缩:沿某个方向放大或缩小向量长度;
- 旋转:改变向量的方向(仅当矩阵为方阵且行列式非负时可能发生);
- 投影:将高维向量映射到低维子空间(如 3 维向量投影到 2 维平面)。
例如,2×2
矩阵A = [[2,0],[0,1]]
表示:将 x 轴方向的向量拉伸 2 倍,y 轴方向的向量保持不变。
2. 特征值与特征向量(仅针对方阵)
对于 n×n
方阵A
,若存在非零向量 v
和 scalar(标量)λ
,满足 Av = λv
,则:
v
称为 A 的特征向量:表示矩阵 A 对该向量仅产生 “拉伸 / 压缩”,不改变方向(或反向);λ
称为 A 的特征值:表示拉伸 / 压缩的比例(λ>1
拉伸,0<λ<1
压缩,λ<0
反向拉伸)。
关键性质:
若方阵 A
是实对称矩阵(满足 A^T = A
,A^T
为 A 的转置),则其特征向量两两正交,且可构成 n 维空间的标准正交基(向量长度为 1,两两内积为 0)。这一性质是 SVD 推导的核心前提。
3. 正交矩阵与标准正交基
若矩阵 U
满足 U^T U = I
(I
为单位矩阵),则 U
为正交矩阵,其列向量构成标准正交基。
正交矩阵的核心作用:对向量做 “旋转 / 反射” 变换时,不改变向量的长度和夹角(例如,将直角坐标系旋转后,坐标轴仍垂直,向量长度不变)。
二、奇异值的推导(从数学逻辑到公式)
SVD 的目标是:将任意m×n
矩阵 A 分解为 3 个具有明确几何意义的矩阵乘积,即 A = UΣV^T
,其中:
U
:m×m
正交矩阵(列向量为 A 的 “左奇异向量”);
Σ
:m×n
对角矩阵(对角线上的非负元素为 A 的 “奇异值”,且从大到小排列);
V^T
:n×n
正交矩阵的转置(行向量为 A 的 “右奇异向量”)。
以下分 3 步推导,避开复杂证明,聚焦逻辑链:
步骤 1:构造实对称矩阵,利用特征值性质
由于 A
是 m×n
矩阵,其转置 A^T
是 n×m
矩阵,因此:
A^T A
是n×n
实对称矩阵(满足(A^T A)^T = A^T (A^T)^T = A^T A
);A A^T
是m×m
实对称矩阵(同理满足(A A^T)^T = A A^T
)。
根据实对称矩阵的性质:A^T A
和 A A^T
的特征值均为非负数,且两者有相同的非零特征值(设为 λ₁ ≥ λ₂ ≥... ≥ λ_k > 0,k ≤ min(m,n)
)。
步骤 2:定义奇异值与奇异向量
- 奇异值:将
A^T A
(或A A^T
)的非零特征值开平方,得到 A 的奇异值,即σ_i = √λ_i
(i=1,2,...,k
),且满足σ₁ ≥ σ₂ ≥... ≥ σ_k > 0
;
对角矩阵Σ
中,前 k 个对角元素为σ₁, σ₂,..., σ_k
,其余元素为 0。 - 右奇异向量(V 的列向量):
取A^T A
的特征向量,按特征值从大到小排列,构成n×n
正交矩阵V
,其列向量即为A
的右奇异向量。 - 左奇异向量(U 的列向量):
对每个非零奇异值σ_i
,定义u_i = (A v_i) / σ_i
(v_i
是A^T A
的第i
个特征向量),则u_i
是A A^T
的第i
个特征向量;
将u₁, u₂,..., u_k
补充正交向量(若m > k
),构成m×m
正交矩阵U
,其列向量即为A
的左奇异向量。
步骤 3:验证分解式 A = UΣV^T
将 V
的列向量 v₁,..., vₙ
视为 n
维空间的标准正交基,对任意 n
维向量 x
,可表示为 x = c₁v₁ +... + cₙvₙ
(c_i
为系数)。
矩阵 A
对 x
的变换为:
A x = c₁A v₁ +... + cₙA vₙ
由左奇异向量定义 A v_i = σ_i u_i
(i≤k
),且 i>k
时 σ_i=0
,因此:
A x = c₁σ₁ u₁ +... + c_kσ_k u_k
这意味着:A
将 n
维空间的基 v₁,..., vₙ
,通过 “拉伸(σ_i
倍)+ 映射到 m
维空间的基 u₁,..., u_k
” 实现线性变换,与 A = UΣV^T
的矩阵乘法逻辑完全一致。
三、奇异值的应用(从理论到实际场景)
SVD 的所有应用均基于一个核心规律:前 k 个最大的奇异值(σ₁,..., σ_k
)包含了矩阵 A 的绝大部分信息,后面的小奇异值往往对应冗余、噪声或次要细节。通过保留前 k 个奇异值,可在 “效果” 与 “成本”(计算量、存储量)间找到最优平衡。
a. 特征降维:解决 “维度灾难”
核心问题
高维数据(如 1000 维的用户行为数据、10000 维的图像像素数据)会带来两大挑战:
- 计算成本高:例如计算两个 10000 维向量的距离,需遍历 10000 个元素;
- 可视化困难:人类仅能感知 2/3 维空间,高维数据无法直接观察规律。
SVD 降维逻辑
对 m×n
数据矩阵 A(m 个样本,n 个特征)做 SVD 分解 A = UΣV^T
,取前 k 个奇异值对应的:
V
的前 k 列(V_k
,n×k
矩阵);- 降维后的数据矩阵为
A_k = A V_k = U_k Σ_k
(m×k
矩阵,k 远小于 n)。
典型场景
- 高维数据可视化:将 1000 维的商品特征数据降到 2 维,用散点图聚类(如 “高端家电”“平价日用品” 两类商品明显分离);
- 加速机器学习:对文本的 TF-IDF 矩阵(
m×n
,m
为文档数,n
为词汇数)降维后,再输入 SVM、KNN 等算法,计算时间可减少 90% 以上。
b. 数据重构:实现 “有损压缩”
核心逻辑
数据重构是降维的逆过程:用降维时保留的 U_k
(m×k
)、Σ_k
(k×k
)、V_k^T
(k×n
),重构近似原矩阵 A_hat = U_k Σ_k V_k^T
。
重构的关键权衡:
- k越小:保留的奇异值越少 → 压缩率越高(如图片文件体积缩小)→ 质量损失越大(如图片模糊);
- k越大:越接近原矩阵 → 质量越好 → 压缩率越低。
典型场景
- 图像压缩:一张
1024×1024
的灰度图(矩阵1024×1024
),取前 50 个奇异值重构,文件体积仅为原大小的(1024×50 + 50 + 1024×50)/(1024×1024) ≈ 10%
,但肉眼几乎看不出模糊;若取前 10 个奇异值,压缩率达 98%,但图像细节明显丢失; - 信号压缩:语音信号、传感器时序信号(如温度监测数据),通过 SVD 丢弃小奇异值后,可在保证可辨识度的前提下,减少数据传输量。
c. 降噪:过滤 “无规律噪声”
核心观察
数据中的噪声(如图片的斑点、信号的杂波)通常是 “无规律的小波动”,对应的奇异值极小;而数据的核心信息(如图片主体、信号趋势)对应大奇异值。
降噪步骤
- 对含噪声的矩阵
A_noise
做 SVD 分解,得到所有奇异值σ₁ ≥ σ₂ ≥... ≥ σ_k
; - 设定阈值
t
(如取t = 0.1σ₁
),丢弃所有σ_i < t
的奇异值; - 用保留的大奇异值重构矩阵
A_clean = U_k Σ_k V_k^T
,即得到降噪后的数据。
典型场景
- 图像降噪:老照片的划痕、低光照拍摄的噪点,通过 SVD 降噪后,画面清晰度显著提升;
- 传感器数据降噪:温度传感器采集的数据含随机波动(噪声),丢弃小奇异值后,可清晰看到 “白天升温、夜间降温” 的趋势。
d. 推荐系统:挖掘 “潜在因子”
核心问题
用户 - 物品评分矩阵 A
(m×n
,m 为用户数,n 为物品数)是 “稀疏高维” 的 ——90% 以上的元素为空白(用户未评分),无法直接用传统方法预测空白评分。
SVD 推荐逻辑
通过 SVD(或适用于稀疏矩阵的变种,如 FunkSVD、SVD++)分解评分矩阵,发现潜在因子(Latent Factors):
U
的行向量:用户的偏好因子(如 “喜欢科幻电影、讨厌言情电影”);V
的列向量:物品的属性因子(如 “科幻电影、言情电影”);- 空白评分预测:用户 i 对物品 j 的评分 ≈
U_i Σ V_j^T
(即用户偏好与物品属性的匹配度)。
本质关联
该应用本质是 “特征降维” 的延伸:将高维的 “用户 - 物品” 维度,降到低维的 “潜在因子” 维度(如 50 个因子),从而解决稀疏性问题。
四、总结:SVD 的核心价值
SVD 的所有应用均围绕 “抓住主要矛盾” 展开 —— 用少数大奇异值(核心信息)替代大量小奇异值(冗余 / 噪声),在 “效果” 与 “成本” 间找到最优解。其之所以成为数据科学、机器学习的核心工具,正是因为它能以简洁的数学形式,解决高维数据处理的共性问题(降维、压缩、降噪、稀疏性),且兼具理论严谨性与工程实用性。
五、矩阵降维案例
import numpy as np# 创建一个矩阵 A (5x3)
A = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12],[13, 14, 15]])
print("原始矩阵 A:")
print(A)# 进行 SVD 分解
U, sigma, Vt = np.linalg.svd(A, full_matrices=False)
print("\n奇异值 sigma:")
print(sigma)# 保留前 k=1 个奇异值进行降维
k = 1
U_k = U[:, :k] # 取 U 的前 k 列,因为要保持行数不变
sigma_k = sigma[:k] # 取前 k 个奇异值
Vt_k = Vt[:k, :] # 取 Vt 的前 k 行,因为要保持列数不变# 近似重构矩阵 A,常用于信号or图像筛除噪声
A_approx = U_k @ np.diag(sigma_k) @ Vt_k
print("\n保留前", k, "个奇异值后的近似矩阵 A_approx:")
print(A_approx)# 计算近似误差
error = np.linalg.norm(A - A_approx, 'fro') / np.linalg.norm(A, 'fro')
print("\n近似误差 (Frobenius 范数相对误差):", error)
原始矩阵 A:
[[ 1 2 3][ 4 5 6][ 7 8 9][10 11 12][13 14 15]]奇异值 sigma:
[3.51826483e+01 1.47690770e+00 9.86023090e-16]保留前 1 个奇异值后的近似矩阵 A_approx:
[[ 1.85152908 2.05208851 2.25264793][ 4.5411984 5.03310541 5.52501242][ 7.23086771 8.01412231 8.7973769 ][ 9.92053702 10.99513921 12.06974139][12.61020633 13.9761561 15.34210588]]近似误差 (Frobenius 范数相对误差): 0.04194136031471535
作业
import numpy as np #计算
import pandas as pd # 数据处理
from sklearn.model_selection import train_test_split #划分训练集&测试集
from sklearn.linear_model import LogisticRegression # 模型
from sklearn.metrics import accuracy_score # 准确度data = pd.read_csv('heart.csv')# 设置随机种子以便结果可重复
np.random.seed(42)# 区分标签和特征
X = data.drop('target',axis=1)
y = data['target']# 做标准化处理
from sklearn.preprocessing import StandardScalerscaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X_scaled = scaler.transform(X)# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)
print(f"训练集形状: {X_train.shape}")
print(f"测试集形状: {X_test.shape}")# 对训练集进行 SVD 分解
U_train, sigma_train, Vt_train = np.linalg.svd(X_train, full_matrices=False)
print(f"Vt_train 矩阵形状: {Vt_train.shape}")# 选择保留的奇异值数量 k
k = 6
Vt_k = Vt_train[:k, :] # 保留前 k 行
print(f"保留 k={k} 后的 Vt_k 矩阵形状: {Vt_k.shape}")# 降维训练集:X_train_reduced = X_train @ Vt_k.T
X_train_reduced = X_train @ Vt_k.T
print(f"降维后训练集形状: {X_train_reduced.shape}")# 使用相同的 Vt_k 对测试集进行降维:X_test_reduced = X_test @ Vt_k.T
X_test_reduced = X_test @ Vt_k.T
print(f"降维后测试集形状: {X_test_reduced.shape}")# 训练模型(以逻辑回归为例)
model = LogisticRegression(random_state=42)
model.fit(X_train_reduced, y_train)# 预测并评估
y_pred = model.predict(X_test_reduced)
accuracy = accuracy_score(y_test, y_pred)
print(f"测试集准确率: {accuracy:.4f}")# 计算训练集的近似误差(可选,仅用于评估降维效果)
X_train_approx = U_train[:, :k] @ np.diag(sigma_train[:k]) @ Vt_k
error = np.linalg.norm(X_train - X_train_approx, 'fro') / np.linalg.norm(X_train, 'fro')
print(f"训练集近似误差 (Frobenius 范数相对误差): {error:.4f}")
训练集形状: (242, 13)
测试集形状: (61, 13)
Vt_train 矩阵形状: (13, 13)
保留 k=6 后的 Vt_k 矩阵形状: (6, 13)
降维后训练集形状: (242, 6)
降维后测试集形状: (61, 6)
测试集准确率: 0.8852
训练集近似误差 (Frobenius 范数相对误差): 0.5709
@浙大疏锦行