Day20 常见降维算法
包括无监督、有监督降维,定义见vs
PCA (无监督):有一堆人脸图片,PCA会尝试找到那些能最好地概括所有人脸变化的“主脸”(特征向量),比如脸型、鼻子大小等,不关心这些人脸属于谁。看总方差最大
LDA (有监督):有一堆人脸图片,并且知道每张图片属于哪个人(标签)。LDA会尝试找到那些能最好地区分不同人的人脸特征组合。比如,如果A和B的脸型很像,但眼睛差别很大,LDA可能会更强调眼睛的特征,即使脸型总方差更大。LDA加入了类别信息,其优化目标就变成了类间差异最大化和类内差异最小化。 LDA 核心不是 “找波动大的特征”,而是 “找能分清‘甲和乙’的特征”
PCA等无监督降维方法的目标是保留数据的最大方差,这些方差大的方向不一定是对分类最有用的方向。因此,在分类任务中,LDA通常比PCA更直接有效。
一 PCA
PCA定义、步骤
主成分分析 (PCA) 的核心思想是识别数据中方差最大的方向(即主成分)。然后,它将数据投影到由这些最重要的主成分构成的新的、维度更低子空间上。这样做的目的是在降低数据维度的同时,尽可能多地保留原始数据中的“信息”(通过方差来衡量)。新的特征(主成分)是原始特征的线性组合,并且它们之间是正交的(不相关)。
用最直观的方式告诉你:什么是主成分分析PCA_哔哩哔哩_bilibili
去中心化:找到数据的中心点,把坐标原点放在数据中心
实际中一般用SVD实现PCA:通过 SVD 分解直接获取主成分方向(右奇异向量),避免了计算协方差矩阵的步骤
步骤 1:数据预处理(中心化)
步骤 2:对中心化矩阵进行 SVD 分解
步骤 3:确定降维维度 k:根据奇异值S的大小选择保留的主成分数量 k(解释的方差)
步骤 4:构建投影矩阵并降维
- 从右奇异向量矩阵 V 中选取前 k 列,组成投影矩阵,这些列向量就是 PCA 的前 k 个主成分
- 将中心化数据投影到新的低维空间,得到降维后的数据 X降维=X_centered * V
PCA适用
PCA主要适用于那些你认为最重要的信息可以通过数据方差来捕获,并且数据结构主要是线性的情况。
PCA代码
import time
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler # 特征缩放
from sklearn.decomposition import PCA # 主成分分析
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA # 线性判别分析
import umap # 如果安装了 umap-learn,可以这样导入from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix
import numpy as np
1.中心化
# 假设 X_train, X_test, y_train, y_test 已经准备好了
print(f"\n--- 2. PCA 降维 + 随机森林 (不使用 Pipeline) ---")# 步骤 1: 特征缩放
scaler_pca = StandardScaler()
X_train_scaled_pca = scaler_pca.fit_transform(X_train)
X_test_scaled_pca = scaler_pca.transform(X_test) # 使用在训练集上fit的scaler
理论中 PCA 需要 “中心化”,而这里的标准化是更严格的预处理,目的是消除特征尺度差异的影响(例如,若一个特征单位是 “米”,另一个是 “厘米”,不标准化会导致后者方差被放大,主导主成分)。标准化后的数据仍满足 “中心化”(均值为 0),符合 SVD 分解对输入数据的要求。
2.确定降维维度k
# 步骤 2: PCA降维
# 找k,选择降到10维,或者你可以根据解释方差来选择,例如:
pca_expl = PCA(random_state=42) # expl是explained(解释)的缩写
pca_expl.fit(X_train_scaled_pca) # 标准化后的训练数据
cumsum_variance = np.cumsum(pca_expl.explained_variance_ratio_)# cumulative sum累计和的缩写
#内部返回一个数组每个元素表示对应主成分的 “方差贡献率”,外层累计求和,得前i个主成分的累计方差贡献率
n_components_to_keep_95_var=np.argmax(cumsum_variance>=0.95)+1#保留 95% 方差需要的主成分数量
# 内前 i 个主成分的累计方差贡献率是否≥95%,argmax返回数组中第一个最大值的索引(布尔数组中,T为1 F为 0,因此返回第一个True的位置)+ 1 得到实际数量 5
print(f"为了保留95%的方差,需要的主成分数量: {n_components_to_keep_95_var}")
前2行:对中心化矩阵进行 SVD 分解
pca_expl.fit()
内部会对标准化后的训练数据(已中心化)执行 SVD 分解:
- 标准化数据矩阵
(V 为右奇异向量矩阵,即主成分方向)。
- 计算奇异值的平方与总方差的比值(即每个主成分的方差贡献)
后2行:通过计算累计方差贡献率,确定保留 95% 信息所需的最少主成分数量
cumsum_variance=np.cumsum(pca_expl.explained_variance_ratio_)
:累加每个主成分的方差贡献(例如,第 1 个主成分贡献 30%,第 2 个 20%,累计就是 50%)。explained_variance_ratio_
就是每个主成分能解释的 “原始数据方差占比”np.argmax(cumsum_variance >= 0.95) + 1
:找到累计贡献首次达到 95% 时的主成分索引(+1 是因为索引从 0 开始)。
3.PCA 降维部分(实际降维)
# 我们测试下降低到10维的效果
n_components_pca = 10
pca_manual = PCA(n_components=n_components_pca, random_state=42)
X_train_pca = pca_manual.fit_transform(X_train_scaled_pca)
X_test_pca = pca_manual.transform(X_test_scaled_pca) # 使用在训练集上fit的pcaprint(f"PCA降维后,训练集形状: {X_train_pca.shape}, 测试集形状: {X_test_pca.shape}")
pca_manual = PCA(n_components=10)
:手动指定降维维度” 的 PCA 降维pca_manual.fit_transform(X_train_scaled_pca)
:在训练集上拟合模型并直接得到降维后的数据。pca_manual.transform(X_test_scaled_pca)
:用训练集拟合的主成分对测试集降维(保证投影规则一致)。fit
过程:通过 SVD 分解得到前 10 个右奇异向量(主成分),组成投影矩阵transform
过程:将标准化数据投影到这 10 个主成分上,与理论公式完全一致。
4. 模型训练与评估
start_time_pca_manual = time.time()
# 步骤 3: 训练随机森林分类器
rf_model_pca = RandomForestClassifier(random_state=42)
rf_model_pca.fit(X_train_pca, y_train)# 步骤 4: 在测试集上预测
rf_pred_pca_manual = rf_model_pca.predict(X_test_pca)
end_time_pca_manual = time.time()print(f"手动PCA降维后,训练与预测耗时: {end_time_pca_manual - start_time_pca_manual:.4f} 秒")print("\n手动 PCA + 随机森林 在测试集上的分类报告:")
print(classification_report(y_test, rf_pred_pca_manual))
print("手动 PCA + 随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, rf_pred_pca_manual))