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. 降噪处理

  • 噪声识别原理

  • 信号通常对应较大奇异值

  • 噪声通常分散在小奇异值中

  • 实现步骤

    1. 计算SVD分解

    2. 设置阈值保留前r个奇异值

    3. 重构矩阵: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)
    
    
  • 潜在因子解释

  • 用户因子矩阵:用户偏好特征

  • 物品因子矩阵:物品属性特征

  • 三、实践注意事项

    1. 数据预处理

    2. 必须中心化(减去均值)

    3. 分类变量需要独热编码

    4. 奇异值截断

    5. 肘部法则选择k值

    6. 保留能量>90%的奇异值:

      explained_variance = np.cumsum(singular_values)/np.sum(singular_values)
      
      
    7. 计算优化

    8. 大数据集使用随机SVD(RandomizedSVD)

    9. 稀疏矩阵用ARPACK算法

    四、经典论文延伸

    1. Netflix Prize获奖方案:

    2. Koren Y, et al. "Matrix factorization techniques for recommender systems"

    3. 图像处理应用:

    4. 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}")

    @浙大疏锦行

    作者:沐兮兮兮

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python学习第20天:奇异值分解SVD详解

    发表回复