SVD奇异值分解

知识点回顾:

  1. 线性代数概念回顾(可不掌握)
  2. 奇异值推导(可不掌握)
  3. 奇异值的应用
    1. 特征降维:对高维数据减小计算量、可视化
    2. 数据重构:比如重构信号、重构图像(可以实现有损压缩,k 越小压缩率越高,但图像质量损失越大)
    3. 降噪:通常噪声对应较小的奇异值。通过丢弃这些小奇异值并重构矩阵,可以达到一定程度的降噪效果。
    4. 推荐系统:在协同过滤算法中,用户-物品评分矩阵通常是稀疏且高维的。SVD (或其变种如 FunkSVD, SVD++) 可以用来分解这个矩阵,发现潜在因子 (latent factors),从而预测未评分的项。这里其实属于特征降维的部分。

对于任何矩阵(如结构化数据可以变为:样本*特征的矩阵,图像数据天然就是矩阵),均可做等价的奇异值SVD分解,对于分解后的矩阵,可以选取保留前K个奇异值及其对应的奇异向量,重构原始矩阵,可以通过计算Frobenius 范数相对误差来衡量原始矩阵和重构矩阵的差异。

SVD奇异值分解_第1张图片

应用:结构化数据中,将原来的m个特征降维成k个新的特征,新特征是原始特征的线性组合,捕捉了数据的主要方差信息,降维后的数据可以直接用于机器学习模型(如分类、回归),通常能提高计算效率并减少过拟合风险。

ps:在进行 SVD 之前,通常需要对数据进行标准化(均值为 0,方差为 1),以避免某些特征的量纲差异对降维结果的影响。

作业:尝试利用svd来处理心脏病预测,看下精度变化

import pandas as pd
import pandas as pd    #用于数据处理和分析,可处理表格数据。
import numpy as np     #用于数值计算,提供了高效的数组操作。
import matplotlib.pyplot as plt    #用于绘制各种类型的图表
import seaborn as sns   #基于matplotlib的高级绘图库,能绘制更美观的统计图形。
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(['target'], axis=1)  # 特征,axis=1表示按列删除
y = data['target']  # 标签
# # 按照8:2划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)  # 80%训练集,20%测试集

from sklearn.ensemble import RandomForestClassifier #随机森林分类器
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score # 用于评估分类器性能的指标
from sklearn.metrics import classification_report, confusion_matrix #用于生成分类报告和混淆矩阵
import warnings #用于忽略警告信息
warnings.filterwarnings("ignore") # 忽略所有警告信息
# --- 1. 默认参数的随机森林 ---
# 评估基准模型,这里确实不需要验证集
print("--- 1. 默认参数随机森林 (训练集 -> 测试集) ---")
import time # 这里介绍一个新的库,time库,主要用于时间相关的操作,因为调参需要很长时间,记录下会帮助后人知道大概的时长
start_time = time.time() # 记录开始时间
rf_model = RandomForestClassifier(random_state=42)
rf_model.fit(X_train, y_train) # 在训练集上训练
rf_pred = rf_model.predict(X_test) # 在测试集上预测
end_time = time.time() # 记录结束时间

print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")
print("\n默认随机森林 在测试集上的分类报告:")
print(classification_report(y_test, rf_pred))
print("默认随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, rf_pred))
# 标准化数据
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 对训练集进行 SVD 分解
U_train, sigma_train, Vt_train = np.linalg.svd(X_train_scaled, full_matrices=False)
print(f"Vt_train 矩阵形状: {Vt_train.shape}")

可以通过累计方差贡献率(explained variance ratio)选择 k,通常选择解释 90%-95% 方差的 k值。

for k in range(1,14):
    explained_variance_ratio=np.cumsum(sigma_train**2)/np.sum(sigma_train**2)
    print(f"前 {k} 奇异值累计方差贡献率: {explained_variance_ratio[k-1]}")
前 1 奇异值累计方差贡献率: 0.20725750322157369
前 2 奇异值累计方差贡献率: 0.33159835641408386
前 3 奇异值累计方差贡献率: 0.4261041158536957
前 4 奇异值累计方差贡献率: 0.5145682644552819
前 5 奇异值累计方差贡献率: 0.594836157809091
前 6 奇异值累计方差贡献率: 0.6704558466663653
前 7 奇异值累计方差贡献率: 0.7383440506650232
前 8 奇异值累计方差贡献率: 0.7983963651348129
前 9 奇异值累计方差贡献率: 0.8516239171229452
前 10 奇异值累计方差贡献率: 0.8987659293980156
前 11 奇异值累计方差贡献率: 0.9394914234782588
前 12 奇异值累计方差贡献率: 0.9728991519151071
前 13 奇异值累计方差贡献率: 1.0000000000000002

import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
k=11
Vt_k = Vt_train[:k, :]  # 保留前 k 行
print(f"保留 k={k} 后的 Vt_k 矩阵形状: {Vt_k.shape}")

# 降维训练集
X_train_reduced = X_train_scaled @ Vt_k.T
print(f"降维后训练集形状: {X_train_reduced.shape}")

# 使用相同的 Vt_k 对测试集进行降维
X_test_reduced = X_test_scaled @ 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}")

# 计算训练集的近似误差(可选,仅用于评估降维效果)
X_train_approx = U_train[:, :k] @ np.diag(sigma_train[:k]) @ Vt_k
error = np.linalg.norm(X_train_scaled - X_train_approx, 'fro') / np.linalg.norm(X_train_scaled, 'fro')
print(f"训练集近似误差 (Frobenius 范数相对误差): {error}")
保留 k=11 后的 Vt_k 矩阵形状: (11, 13)
降维后训练集形状: (242, 11)
降维后测试集形状: (61, 11)
测试集准确率: 0.8524590163934426
训练集近似误差 (Frobenius 范数相对误差): 0.24598491116680557

 @浙大疏锦行

你可能感兴趣的:(python训练营打卡内容,机器学习,人工智能,python,笔记)