Python学习第20天:奇异值分解SVD详解
目录
奇异值分解(SVD)学习笔记
一、核心概念速览
二、应用领域详解
1. 特征降维
2. 数据重构与压缩
3. 降噪处理
4. 推荐系统应用
三、实践注意事项
四、经典论文延伸
作业:尝试利用svd来处理心脏病预测,看下精度变化
奇异值分解(SVD)学习笔记
一、核心概念速览

二、应用领域详解
1. 特征降维
工作原理:
# sklearn实现示例
from sklearn.decomposition import TruncatedSVD
svd = TruncatedSVD(n_components=2)
X_reduced = svd.fit_transform(X)
优势:
计算复杂度从O(n³)降至O(k·n²)
可视化高维数据(降至2/3维)
2. 数据重构与压缩
压缩比公式:
压缩率 = (m×k + k + k×n) / (m×n) 其中k为保留的奇异值数量
图像压缩示例:

3. 降噪处理
噪声识别原理:
信号通常对应较大奇异值
噪声通常分散在小奇异值中
实现步骤:
-
计算SVD分解
-
设置阈值保留前r个奇异值
-
重构矩阵:A_clean = U[:,:r] @ Σ[:r,:r] @ Vᵀ[:r,:]
4. 推荐系统应用
协同过滤流程:
# 典型Surprise库实现
from surprise import SVD
algo = SVD(n_factors=20)
algo.fit(trainset)
predictions = algo.test(testset)
潜在因子解释:
用户因子矩阵:用户偏好特征
物品因子矩阵:物品属性特征
三、实践注意事项
-
数据预处理:
-
必须中心化(减去均值)
-
分类变量需要独热编码
-
奇异值截断:
-
肘部法则选择k值
-
保留能量>90%的奇异值:
explained_variance = np.cumsum(singular_values)/np.sum(singular_values) -
计算优化:
-
大数据集使用随机SVD(RandomizedSVD)
-
稀疏矩阵用ARPACK算法
四、经典论文延伸
-
Netflix Prize获奖方案:
-
Koren Y, et al. "Matrix factorization techniques for recommender systems"
-
图像处理应用:
-
Andrew Ng的CS229课程案例:医学图像压缩
附:SVD与PCA关系对比表
| 特性 | SVD | PCA |
|---|---|---|
| 输入要求 | 任意矩阵 | 协方差矩阵 |
| 计算方式 | 直接分解 | 特征分解 |
| 缺失值处理 | 需要填充 | 需要填充 |
| 推荐系统适用性 | 更常用 | 较少使用 |
该笔记已通过Jupyter Notebook实战验证,建议配合NumPy的np.linalg.svd()实践操作加深理解。对于理论推导部分,Gilbert Strang的《Linear Algebra and Its Applications》第6章有详细阐述。
作业:尝试利用svd来处理心脏病预测,看下精度变化
import pandas as pd #用于数据处理和分析,可处理表格数据。
import numpy as np #用于数值计算,提供了高效的数组操作。
import matplotlib.pyplot as plt #用于绘制各种类型的图表
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
import warnings
warnings.filterwarnings("ignore")
# 设置中文字体(解决中文显示问题)
plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统常用黑体字体
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号
data = pd.read_csv('heart.csv') #读取数据
# 最开始也说了 很多调参函数自带交叉验证,甚至是必选的参数,你如果想要不交叉反而实现起来会麻烦很多
# 所以这里我们还是只划分一次数据集
from sklearn.model_selection import train_test_split
X = data.drop(['fbs'], axis=1) # 特征,axis=1表示按列删除
y = data['fbs'] # 标签
# # 按照8:2划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 80%训练集,20%测试集
#选择合适的 K 值
explained_variance_ratio = np.cumsum(sigma_train**2) / np.sum(sigma_train**2)
print(f"前 {k} 个奇异值的累计方差贡献率: {explained_variance_ratio[k-1]}")
# 对训练集进行 SVD 分解
U_train, sigma_train, Vt_train = np.linalg.svd(X_train, full_matrices=False)
print(f"Vt_train 矩阵形状: {Vt_train.shape}")
# 选择保留的奇异值数量 k
# k = 5 # 或者根据累积方差贡献率选择合适的 k 值,上方已经选出,无需再对K进行赋值
Vt_k = Vt_train[:k, :] # 保留前 k 行,形状为 (k, 13)
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}")
# #或者使用 sklearn 的 TruncatedSVD:`sklearn` 提供了 `TruncatedSVD`类,
# #专门用于高效降维,尤其适合大规模数据。它直接计算前 k个奇异值和向量,避免完整 SVD 的计算开销。
# from sklearn.decomposition import TruncatedSVD
# svd = TruncatedSVD(n_components=k, random_state=42)
# X_train_reduced = svd.fit_transform(X_train)
# X_test_reduced = svd.transform(X_test)
# print(f"累计方差贡献率: {sum(svd.explained_variance_ratio_)}")
# 训练模型(以逻辑回归为例)
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}")
# 计算训练集的近似误差(可选,仅用于评估降维效果)
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}")

@浙大疏锦行
作者:沐兮兮兮