知识点回顾:
- 线性代数概念回顾(可不掌握)
- 奇异值推导(可不掌握)
- 奇异值的应用
- 特征降维:对高维数据减小计算量、可视化
- 数据重构:比如重构信号、重构图像(可以实现有损压缩,k 越小压缩率越高,但图像质量损失越大)
- 降噪:通常噪声对应较小的奇异值。通过丢弃这些小奇异值并重构矩阵,可以达到一定程度的降噪效果。
- 推荐系统:在协同过滤算法中,用户-物品评分矩阵通常是稀疏且高维的。SVD (或其变种如 FunkSVD, SVD++) 可以用来分解这个矩阵,发现潜在因子 (latent factors),从而预测未评分的项。这里其实属于特征降维的部分。
- 奇异矩阵SVD分解
对于任何矩阵(如结构化数据可以变为:样本*特征的矩阵,图像数据天然就是矩阵),均可做等价的奇异值SVD分解,对于分解后的矩阵,可以选取保留前K个奇异值及其对应的奇异向量,重构原始矩阵,可以通过计算Frobenius 范数相对误差来衡量原始矩阵和重构矩阵的差异。
ps:在进行 SVD 之前,通常需要对数据进行标准化(均值为 0,方差为 1),以避免某些特征的量纲差异对降维结果的影响。
作业:尝试利用svd来处理心脏病预测,看下精度变化
(一)SVD介绍
#SVD 的奇异值是通过对 A^T A 或 A A^T的特征值取平方根得到的,特征向量则与奇异向量相关
#在 SVD 中,我们构造 A^T A 和 A A^T,这两个矩阵都是对称矩阵,因此可以进行特征值分解,进而求解奇异值和奇异向量
#SVD 是一种更广义的矩阵分解方法,适用于非方阵,而特征值分解是 SVD 计算的基础步骤。
- 总结:
- 正交矩阵:列向量正交且单位化,在 SVD 中用于旋转或反射(U 和 V)。
- 特征值与特征向量:描述矩阵在某些方向上的缩放特性,是计算奇异值的基础。
- 对称矩阵:具有实特征值和正交特征向量,SVD 通过构造 A^T A 和 A A^T 利用其性质。
- 矩阵分解:将复杂矩阵分解为简单矩阵乘积,是降维和数据分析的核心工具。
SVD通过将矩阵分解为奇异值和正交基,揭示了数据的本质结构。其输入为任意矩阵,输出为三个具有明确意义的子矩阵,广泛应用于降维、推荐、NLP等领域
(二)SVD的输入和输出
- 输入:一个任意的矩阵 AA,尺寸为 m×n(其中 m 是行数,n是列数,可以是矩形矩阵,不必是方阵)。
奇异值分解(SVD)得到的三个矩阵 U、Σ 和 VT 各有其特定的意义和用途:
-
U(左奇异向量矩阵):
- 是一个 m×m 的正交矩阵,列向量是矩阵 AAT 的特征向量。
- 作用:表示原始矩阵 A在行空间(样本空间)中的主方向或基向量。简单来说,U 的列向量描述了数据在行维度上的“模式”或“结构”。
- 应用:在降维中,U的前几列可以用来投影数据到低维空间,保留主要信息(如在图像处理中提取主要特征)。
-
Σ(奇异值矩阵):
- 是一个 m×n的对角矩阵,对角线上的值是奇异值(singular values),按降序排列,非负。
- 作用:奇异值表示原始矩阵 A 在每个主方向上的“重要性”或“能量”。较大的奇异值对应更重要的特征,较小的奇异值对应噪声或次要信息。
- 应用:通过选择前 k 个较大的奇异值,可以实现降维,丢弃不重要的信息(如数据压缩、去噪)。
-
VT(右奇异向量矩阵的转置):
- 是 V 的转置,V 是一个 n×n的正交矩阵,列向量是矩阵 ATA 的特征向量。
- 作用:表示原始矩阵 A在列空间(特征空间)中的主方向或基向量。简单来说,V 的列向量描述了数据在列维度上的“模式”或“结构”。
- 应用:类似 U,V的前几列可以用来投影数据到低维空间,提取主要特征。
整体作用:
结合起来,A=UΣVT 意味着原始矩阵 A可以被分解为一系列主方向(U和 V)和对应的权重(Σ)的组合。这种分解揭示了数据的内在结构。
主要应用:
- 降维:通过保留前 k 个奇异值及其对应的 U 和 V 的列向量,可以近似重建A,减少数据维度(如 PCA 的基础)。
- 数据压缩:如图像压缩,丢弃小的奇异值以减少存储空间。
- 去噪:小的奇异值往往对应噪声,丢弃它们可以提高数据质量。
- 推荐系统:如矩阵分解,用于预测用户评分矩阵中的缺失值。
简单来说,U、Σ 和 VT 提供了数据的核心结构信息,帮助我们在保留主要信息的同时简化数据处理
- 输出:
SVD 将矩阵 A 分解为三个矩阵的乘积形式,即 A=UΣVT
(三)奇异值应用——降维/数据压缩
奇异值排序——筛选——降维和近似——对应向量
筛选靠前的k个对角线上值(奇异值),取U阵前k列和Σ前k奇异值和VT前k行可实现降维
总结:SVD 分解后原始矩阵是等价的,但通过筛选排序靠前的奇异值和对应的向量,我们可以实现降维,保留数据的主要信息,同时减少计算量和噪声影响。这种方法是许多降维算法(如 PCA)和数据处理技术的基础。
- 问题:在机器学习中,如果对训练集进行 SVD 降维后训练模型,而测试集的特征数量与降维后的训练集不一致(测试集仍保持原始特征数量),该如何处理?
答:同样地对测试集进行等效降维(进行相同变换) ,若对测试集单独进行 SVD,会得到不同的 V^T 矩阵,导致测试集和训练集的低维空间不一致,模型无法正确处理测试数据
(四)作业
import warnings
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
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.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
np.random.seed(42)
print(f"训练集形状: {X_train.shape}")
print(f"测试集形状: {X_test.shape}")
U_train, sigma_train, Vt_train = np.linalg.svd(X_train, full_matrices=False) ##full_matrices=False 表示只计算 U 和 Vt 的前 k 列,其中 k 是矩阵 A 的秩。进行经济SVD分解
print(f"Vt_train 矩阵形状: {Vt_train.shape}")
# 选择保留的奇异值数量 k
k = 8
Vt_k = Vt_train[:k, :] # 保留前 k 行,形状为 (k, 50)
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}")
# 计算训练集的近似误差(可选,仅用于评估降维效果)
#近似重构矩阵 A,常用于信号or图像筛除噪声
X_train_approx = U_train[:, :k] @ np.diag(sigma_train[:k]) @ Vt_k # 取 U 的前 k 列,因为要保持行数不变;# 取前 k 个奇异值#取Vt_k所有行#np.diag(sigma_k) :将降维后的奇异值数组 sigma_k 转换为对角矩阵,对角线上的元素为 sigma_k 中的值,其他位置为 0。
error = np.linalg.norm(X_train - X_train_approx, 'fro') / np.linalg.norm(X_train, 'fro')
print(f"训练集近似误差 (Frobenius 范数相对误差): {error}")
结果如下:
训练集形状: (242, 13)
测试集形状: (61, 13)
Vt_train 矩阵形状: (13, 13)
保留 k=8 后的 Vt_k 矩阵形状: (8, 13)
降维后训练集形状: (242, 8)
降维后测试集形状: (61, 8)
测试集准确率: 0.8688524590163934
训练集近似误差 (Frobenius 范数相对误差): 0.002934026637631935
- 评价报告
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 #用于生成分类报告和混淆矩阵rf_model_var = RandomForestClassifier(random_state=42) #实例化
rf_model_var.fit(X_train_reduced, y_train) # 训练
rf_pred_var = rf_model_var.predict(X_test_reduced) #预测# 打印模型在测试集上的分类报告,展示模型的性能
# 分类报告包括精确率、召回率、F1分数等指标,帮助评估模型好坏
print("\nSVD降维后随机森林在测试集上的分类报告:")
print(classification_report(y_test, rf_pred_var))# 打印混淆矩阵,展示模型预测的详细结果
# 混淆矩阵显示了真实标签和预测标签的对应情况,比如多少样本被正确分类,多少被错分
print("SVD降维后随机森林在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, rf_pred_var))
结果:
SVD降维后随机森林在测试集上的分类报告:precision recall f1-score support0 0.81 0.90 0.85 291 0.90 0.81 0.85 32accuracy 0.85 61macro avg 0.85 0.85 0.85 61
weighted avg 0.86 0.85 0.85 61SVD降维后随机森林在测试集上的混淆矩阵:
[[26 3][ 6 26]]
@浙大疏锦行