Lesson 14
降维与 PCA:化繁为简
高维数据难以可视化、存储昂贵、且容易过拟合。PCA 是最经典的降维方法,通过找方差最大的方向把数据投影到低维空间,同时保留尽可能多的信息。
本章细分学习地图
| 模块 | 拆细学习单元 | 完成后应产出 | 掌握标准 |
|---|---|---|---|
| 维度灾难 | 高维稀疏性、距离失效、过拟合。 | 维度灾难的直觉解释。 | 能说清为什么高维数据需要降维。 |
| PCA 原理 | 协方差矩阵、特征值/特征向量、投影。 | PCA 流程描述。 | 能说清主成分的方向和方差的关系。 |
| 选择主成分数 | 累计解释方差、肘部图。 | 方差解释图。 | 能用 95% 方差阈值选 n_components。 |
| 实战 | 可视化、Pipeline 分类、人脸降维。 | 完整代码。 | 能在 Pipeline 中正确使用 PCA。 |
学习目标
PCA 流程
本章完成度
已完成 0/4
维度灾难
随着特征数增加,数据变得越来越稀疏——距离失去区分度、模型需要指数级增长的数据量才能泛化。
稀疏性
高维空间中数据点散布在各个角落,样本间距离趋于相等,KNN 等算法失效。
过拟合
特征数 ≫ 样本数时,模型很容易记住噪声而非模式。
计算开销
特征数越多,存储和训练成本越高。
解决思路
降维(PCA)、特征选择、正则化。
PCA 原理
PCA(主成分分析)找到数据方差最大的方向作为第一主成分,然后在与之正交的方向中找方差第二大的方向,依此类推。
PCA 基于方差。如果特征量纲不同,大数值特征会主导方差方向。在 PCA 前用 StandardScaler 是必须的。
| 概念 | 含义 |
|---|---|
| 主成分 | 方差最大的正交方向,是原始特征的线性组合。 |
| 特征值 | 每个主成分捕获的方差大小。 |
| 解释方差比 | 该主成分捕获的方差 / 总方差。 |
互动实验:找到方差最大的投影方向
下面是一份有明显线性相关性的二维数据。拖动滑块旋转虚线(投影方向),金色小点是每个样本投影到该方向后的位置。留意"当前方向解释方差比",试着手动找到让它最大的角度——那正是 PCA 用协方差矩阵特征值分解算出来的第一主成分方向。
- 当前方向解释方差比
- 0%
- PC1 方向解释方差比
- 0%
- 与 PC1 夹角
- 0°
投影方向对准数据"最长轴"时,金色投影点铺得最开、解释方差比最大——这就是第一主成分。垂直于它的方向(第二主成分)解释方差比最小,金色点会挤在中间一小段。PCA 不是凑巧试出这个角度,而是直接对协方差矩阵做特征值分解算出来的精确解。
选择主成分数
用累计解释方差比来决定保留多少个主成分。通常保留累计方差 ≥ 95% 的前 k 个。
from sklearn.datasets import load_digits
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
import numpy as np
X, y = load_digits(return_X_y=True)
X_scaled = StandardScaler().fit_transform(X)
pca = PCA().fit(X_scaled)
cumvar = np.cumsum(pca.explained_variance_ratio_)
for n in [5, 10, 20, 30, 40]:
print(f"前 {n:2d} 个主成分累计方差: {cumvar[n-1]:.3f}")
# 找到 95% 方差对应的主成分数
n_95 = np.argmax(cumvar >= 0.95) + 1
print(f"\n保留 95% 方差需要 {n_95} 个主成分(原始 {X.shape[1]} 维)")
sklearn 实战
1. 高维数据可视化(降到 2D)
from sklearn.datasets import load_digits
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
X, y = load_digits(return_X_y=True)
X_scaled = StandardScaler().fit_transform(X)
pca = PCA(n_components=2)
X_2d = pca.fit_transform(X_scaled)
print(f"降维后形状: {X_2d.shape}") # (1797, 2)
print(f"前 2 个主成分解释方差: {pca.explained_variance_ratio_.sum():.3f}")
2. PCA + 分类 Pipeline
from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.pipeline import Pipeline
from sklearn.model_selection import cross_val_score
X, y = load_digits(return_X_y=True)
# 不用 PCA
pipe_full = Pipeline([
("scaler", StandardScaler()),
("svc", SVC(kernel="rbf", random_state=42)),
])
score_full = cross_val_score(pipe_full, X, y, cv=5).mean()
# 用 PCA 保留 95% 方差
pipe_pca = Pipeline([
("scaler", StandardScaler()),
("pca", PCA(n_components=0.95)),
("svc", SVC(kernel="rbf", random_state=42)),
])
score_pca = cross_val_score(pipe_pca, X, y, cv=5).mean()
pipe_pca.fit(X, y)
n_components = pipe_pca.named_steps["pca"].n_components_
print(f"原始 {X.shape[1]} 维 → PCA {n_components} 维")
print(f"无 PCA 准确率: {score_full:.3f}")
print(f"有 PCA 准确率: {score_pca:.3f}")
3. 人脸降维(Eigenfaces)
from sklearn.datasets import fetch_lfw_people
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.pipeline import Pipeline
from sklearn.model_selection import train_test_split
# 加载人脸数据(至少 70 张照片的人)
lfw = fetch_lfw_people(min_faces_per_person=70, resize=0.4)
X, y = lfw.data, lfw.target
print(f"样本: {X.shape[0]}, 特征: {X.shape[1]}")
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42, stratify=y
)
pipe = Pipeline([
("scaler", StandardScaler()),
("pca", PCA(n_components=100, whiten=True, random_state=42)),
("svc", SVC(kernel="rbf", C=10, gamma=0.001)),
])
pipe.fit(X_train, y_train)
print(f"测试准确率: {pipe.score(X_test, y_test):.3f}")
PCA 只能捕捉线性关系。如果数据的关键结构是非线性的(如流形),应考虑 t-SNE(可视化)或 UMAP。sklearn 也提供 KernelPCA 用于非线性降维。
练习题
第 1 题:PCA 前为什么必须标准化?不标准化会怎样?
参考思路:PCA 基于方差。不标准化时,量纲大的特征方差大,会主导主成分方向,其他特征的信息被忽略。
第 2 题:累计解释方差 = 0.95 意味着什么?
参考思路:保留的主成分捕获了原始数据 95% 的总方差,只丢失了 5% 的信息。这通常是一个合理的保留阈值。
第 3 题:用手写数字数据集,分别保留 10、20、30 个主成分,对比 SVC 的准确率。
参考思路:修改上面 Pipeline 中的 n_components 参数,观察准确率变化。通常 20-30 个主成分就能达到接近全维度的准确率。
检查点
离开本章前,请确认:
- 能解释维度灾难的三个问题(稀疏/过拟合/计算)。
- 能说清 PCA 找方差最大方向并投影的核心思想。
- 能用累计解释方差比选择合适的主成分数。
- 能在 Pipeline 中正确使用 StandardScaler + PCA + 模型。