Day 20 奇异值SVD分解

@浙大疏锦行

特征降维的非特征筛选方法。

先回顾一下昨天的特征筛选方法:方差筛选,皮尔逊相关系数筛选,基于L1正则化的lasso筛选,树模型重要性,shap重要性特征筛选,递归特征消除RFE

今日知识点(SVD奇异值分解):

一、线代概念回顾:

考研数学中与特征值分解相关的题目主要集中在以下几类:

1. 计算特征值和特征向量:通过特征方程求解。

2. 矩阵对角化:判断矩阵是否可对角化,并求对角化矩阵。

3. 利用特征值分解求矩阵幂或函数:通过分解简化高次幂计算。

4. 证明题:如证明某些矩阵性质与特征值的关系。

正交矩阵:列向量正交且单位化,在 SVD 中用于旋转或反射(U 和 V)。

特征值与特征向量:描述矩阵在某些方向上的缩放特性,是计算奇异值的基础。

对称矩阵:具有实特征值和正交特征向量,SVD 通过构造 利用其性质。

矩阵分解:将复杂矩阵分解为简单矩阵乘积,是降维和数据分析的核心工具。

奇异值分解(SVD)的输入和输出:

  • 输入:一个任意的矩阵 A,尺寸为 m×n(其中 m 是行数,n 是列数,可以是矩形矩阵,不必是方阵)。

奇异值分解(SVD)得到的三个矩阵 U、Σ 和 V^T 各有其特定的意义和用途,下面我简要说明它们的作用:

  1. U(左奇异向量矩阵)

    • 是一个 m×m 的正交矩阵,列向量是矩阵 A A^T 的特征向量。
    • 作用:表示原始矩阵 A 在行空间(样本空间)中的主方向或基向量。简单来说,U 的列向量描述了数据在行维度上的 “模式” 或 “结构”。
    • 应用:在降维中,U 的前几列可以用来投影数据到低维空间,保留主要信息(如在图像处理中提取主要特征)。
  2. Σ(奇异值矩阵)

    • 是一个 m×n 的对角矩阵,对角线上的值是奇异值(singular values),按降序排列,非负。
    • 作用:奇异值表示原始矩阵 A 在每个主方向上的 “重要性” 或 “能量”。较大的奇异值对应更重要的特征,较小的奇异值对应噪声或次要信息。
    • 应用:通过选择前 k 个较大的奇异值,可以实现降维,丢弃不重要的信息(如数据压缩、去噪)。
  3. V^T(右奇异向量矩阵的转置)

    • 是 V 的转置,V 是一个 n×n 的正交矩阵,列向量是矩阵 A^T A 的特征向量。
    • 作用:表示原始矩阵 A 在列空间(特征空间)中的主方向或基向量。简单来说,V 的列向量描述了数据在列维度上的 “模式” 或 “结构”。
    • 应用:类似 U,V 的前几列可以用来投影数据到低维空间,提取主要特征。

整体作用

  • 结合起来,A = U Σ V^T 意味着原始矩阵 A 可以被分解为一系列主方向(U 和 V)和对应的权重(Σ)的组合。这种分解揭示了数据的内在结构。
  • 主要应用
    • 降维:通过保留前 k 个奇异值及其对应的 U 和 V 的列向量,可以近似重建 A,减少数据维度(如 PCA 的基础)。
    • 数据压缩:如图像压缩,丢弃小的奇异值以减少存储空间。
    • 去噪:小的奇异值往往对应噪声,丢弃它们可以提高数据质量。
    • 推荐系统:如矩阵分解,用于预测用户评分矩阵中的缺失值。

简单来说,U、Σ 和 V^T 提供了数据的核心结构信息,帮助我们在保留主要信息的同时简化数据处理。

  • 输出:SVD 将矩阵 A 分解为三个矩阵的乘积形式,即 A = U Σ V^T,其中:
    • U:一个 m×m 的正交矩阵,列向量是 A A^T 的特征向量,称为左奇异向量矩阵。
    • Σ:一个 m×n 的对角矩阵,对角线上的元素是非负的奇异值(singular values),通常按降序排列,表示 A 的 “重要性” 或 “能量”。
    • V^T:一个 n×n 的正交矩阵的转置,V 的列向量是 A^T A 的特征向量,称为右奇异向量矩阵。

奇异值的应用

奇异值分解(SVD)将原始矩阵 A 分解为 A = UΣV^T,这种分解是等价的,用这三个矩阵相乘可完全重构 A,没有信息损失。

但实际应用中,通常不用保留所有奇异值和对应向量,而是通过筛选规则选排序靠前的,实现降维或数据压缩。核心思路如下:

  1. 奇异值的排序
    Σ 矩阵中,奇异值按降序排列。靠前的通常较大,代表数据中最重要的信息或主要变化方向;靠后的较小,代表次要信息或噪声。
    奇异值大小反映对应向量对原始矩阵 A 的贡献程度。

  2. 筛选规则
    可根据需求保留前 k 个奇异值(k 小于原始矩阵秩),丢弃剩余较小的。
    常见规则:

    • 固定数量:直接选前 k 个(如前 10 个)。
    • 累计方差贡献率:算奇异值的平方(代表方差),选累计贡献率达阈值(如 95%)的前 k 个。
    • 奇异值下降幅度:观察下降 “拐点”,在下降明显变缓处截断。
  3. 降维与近似
    保留前 k 个奇异值后,取 U 的前 k 列(U_k,m×k)、Σ 的前 k 个奇异值(Σ_k,k×k)、V^T 的前 k 行(V_k^T,k×n)。
    近似矩阵为 A_k = U_kΣ_kV_k^T,这是 A 的低秩近似,保留主要信息,丢弃次要信息或噪声。
    该方法常用于降维(如 PCA)、图像压缩、推荐系统等领域。

  4. 对应的向量
    U 和 V 的列向量分别是左右奇异向量。保留前 k 个奇异值时,U_k 的列向量代表数据在行空间的主要方向,V_k 的列向量代表在列空间的主要方向。
    这些向量与奇异值一起,构成数据的主要 “模式” 或 “结构”。

总结:SVD 分解后原始矩阵等价,通过筛选靠前的奇异值和对应向量,可实现降维,保留主要信息,减少计算量和噪声影响。这是许多降维算法(如 PCA)和数据处理技术的基础。

# 数据集的划分
from sklearn.model_selection import train_test_split
# 准备标签和特征
X = data_encoded.drop(TARGET_COLUMN, axis=1)
y = data_encoded[TARGET_COLUMN]
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) 

# 新增:在SVD分解前对数据集进行标准化处理
from sklearn.preprocessing import StandardScaler
scaler_svd = StandardScaler()
X_train_scaled = scaler_svd.fit_transform(X_train)
X_test_scaled = scaler_svd.transform(X_test)
print(f"标准化后训练集形状: {X_train_scaled.shape}")
print(f"标准化后测试集形状: {X_test_scaled.shape}")


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


# 选择保留的奇异值数量 k
k = 10
Vt_k = Vt_train[:k, :]  # 保留前 k 行
print(f"保留 k={k} 后的 Vt_k 矩阵形状: {Vt_k.shape}")


# 降维训练集:X_train_reduced = X_train_scaled @ Vt_k.T
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
X_test_reduced = X_test_scaled @ Vt_k.T
print(f"降维后测试集形状: {X_test_reduced.shape}")

# 训练模型(以逻辑回归为例)
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(random_state=42)
model.fit(X_train_reduced, y_train)


# 预测并评估
from sklearn.metrics import accuracy_score
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}")


# 可选:尝试不同的k值,观察准确率和误差变化
print("\n尝试不同的k值:")
for k in [5, 10, 15, 20, X_train.shape[1]]:
    Vt_k = Vt_train[:k, :]
    X_train_reduced = X_train @ Vt_k.T
    X_test_reduced = X_test @ Vt_k.T
    
    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)
    
    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"k={k}: 准确率={accuracy:.4f}, 近似误差={error:.6f}")
26
标准化后训练集形状: (242, 25)
标准化后测试集形状: (61, 25)
Vt_train 矩阵形状: (25, 25)
保留 k=10 后的 Vt_k 矩阵形状: (10, 25)
降维后训练集形状: (242, 10)
降维后测试集形状: (61, 10)
测试集准确率: 0.8688524590163934
训练集近似误差 (Frobenius 范数相对误差): 0.9371979703408998

尝试不同的k值:
k=5: 准确率=0.8525, 近似误差=0.966833
k=10: 准确率=0.8689, 近似误差=0.937198
k=15: 准确率=0.8689, 近似误差=0.905244
k=20: 准确率=0.8689, 近似误差=0.884977

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值