降维:从正确的角度看见高维数据的结构


文档摘要

降维:从正确的角度看见高维数据的结构 本节摘要:高维数据有结构,只是你得从正确的角度看。一个样本有 784 个特征(手写数字的像素、基因表达、用户行为),你无法可视化、无法画图、甚至无法想象——但其中大部分是冗余。一个手写的「7」不需要 784 个独立数字,几个就够(笔画角度、横线长度、倾斜度),其余是噪声。降维就是找出那个更小的曲面:把 784 维压到 2、10 或 50 维,同时保住关键结构。

降维:从正确的角度看见高维数据的结构

本节摘要:高维数据有结构,只是你得从正确的角度看。一个样本有 784 个特征(手写数字的像素、基因表达、用户行为),你无法可视化、无法画图、甚至无法想象——但其中大部分是冗余。一个手写的「7」不需要 784 个独立数字,几个就够(笔画角度、横线长度、倾斜度),其余是噪声。降维就是找出那个更小的曲面:把 784 维压到 2、10 或 50 维,同时保住关键结构。本节先讲维度灾难(高维下距离失效、体积集中到角点、数据需求指数增长);然后从零实现 PCA——中心化、协方差矩阵、特征分解、按特征值排序、投影;用解释方差比肘部法选主成分数;对比 t-SNE(保局部邻居、出版物级 2D 图)与 UMAP(更快、保全局结构);引入核 PCA(RBF 核分离同心圆这种非线性流形);最后用重建误差量化「压成了什么、丢了什么」,并把它接上异常检测。

对应原课程:Phase 01 · Lesson 10 · dimensionality-reduction(原英文 phases/01-math-foundations/10-dimensionality-reduction/docs/en.md)。前置:第 1、2、3 节(线性代数)与第 6 节(概率)。

学习目标

阅读完本节,你应当能够:

  1. 从零实现 PCA:中心化数据、算协方差矩阵、特征分解、投影。
  2. 解释方差比肘部法选择主成分数。
  3. 对比 PCA、t-SNE、UMAP 在 MNIST 2D 可视化上的表现,解释各自权衡。
  4. RBF 核的核 PCA 分离标准 PCA 处理不了的非线性结构。

一、问题与直觉

你有一个 784 特征的数据集,无法可视化、无法画图、甚至无法想象。但 784 个特征大多冗余,真正信息活在远更小的曲面上。降维找到这个曲面,把 784 维压到 2/10/50 维而保留关键结构。

1.1 维度灾难

高维空间违反直觉,三件事随维数增长而崩坏。

距离失效:高维下任意两随机点的距离都趋于同一值,最近邻搜索失效。

维数 平均距离比(随机点 max/min)
2 ~5.0
10 ~1.8
100 ~1.2
1000 ~1.02

体积集中到角点:d 维单位超立方体有 2^d 个角。100 维下几乎所有体积都在角点,数据点散到边缘,模型在内部饿死。

数据需求指数增长:从 2D 升到 20D 要 10¹⁸ 倍数据才能保持同样密度——你永远没有足够数据。降维把数据密度拉回可用范围。

1.2 PCA:找到重要的方向

主成分分析(PCA)找数据变化最大的轴,旋转坐标系,使第一轴捕获最大方差、第二轴次之、依此类推。

1. 中心化数据 (每个特征减均值) 2. 算协方差 (特征如何协同变化) 3. 特征分解 (找主方向) 4. 按特征值排序 (最大方差优先) 5. 投影 (保留前 k 个特征向量,丢弃其余)

为什么特征分解? 协方差矩阵对称半正定,其特征向量是特征空间里正交方向,特征值告诉你每个方向捕获多少方差。最大特征值的特征向量指向最大方差方向。

1.3 解释方差比

每个主成分捕获总方差的一小部分:

成分 特征值 解释比 累计
PC1 4.73 0.473 0.473
PC2 2.51 0.251 0.724
PC3 1.12 0.112 0.836
PC4 0.89 0.089 0.925

累计解释方差达 0.95 时,这些成分就捕获了 95% 信息,其余多是噪声。

1.4 选主成分数

三种策略:

  1. 阈值法:保留够解释 90~95% 方差的成分。
  2. 肘部法:画每成分的解释方差,找急剧跌落的拐点。
  3. 下游性能:把 PCA 当预处理,扫描 k 测模型精度,精度平台处即最佳 k。

1.5 t-SNE:保邻居

t-分布随机邻接嵌入(t-SNE)专为可视化设计,把高维数据映射到 2D/3D,同时保留「谁离谁近」。直觉:原空间按距离算点对的概率分布(近点概率高、远点概率低),再找一个 2D 排列使同一分布成立——784 维里的邻居在 2D 里仍是邻居。

性质:非线性(能展开 PCA 不能的复杂流形);随机性(不同运行布局不同);perplexity 控制考虑几个邻居(典型 5~50);输出里簇间距离无意义,只有簇本身有意义;大数据上慢(O(n²))。

1.6 UMAP:更快、全局结构更好

UMAP 与 t-SNE 类似,但两点更优:更快(用近似最近邻图而非全 pairwise 距离);全局结构更好(簇的相对位置比 t-SNE 更有意义)。它在高维建加权图(「模糊拓扑表示」),再找尽量保住该图的低维布局。参数:n_neighbors(像 perplexity,大值保更多全局结构)、min_dist(输出里点挤得多紧,小值成更密簇)。

1.7 何时用哪个

方法 用例 保留 速度
PCA 训练前预处理 全局方差 快(精确),百万样本可用
PCA 快速探索可视化 线性结构
t-SNE 出版级 2D 图 局部邻居 慢(<1 万样本理想)
UMAP 大规模 2D 可视化 局部 + 部分全局 中(百万可处理)

拇指法则:PCA 用于预处理与压缩;t-SNE 或 UMAP 用于 2D 结构可视化。

1.8 核 PCA

标准 PCA 找线性子空间(旋转坐标系、丢轴)。但若数据活在非线性流形上(2D 里的圆无法被任何直线分开),标准 PCA 无能为力。核 PCA 在核函数诱导的高维特征空间里做 PCA,而不显式算该空间坐标——这就是 SVM 背后的核技巧

1. 算核矩阵 K,K_ij = k(xᵢ, xⱼ) 2. 在特征空间中心化核矩阵 3. 对中心化核矩阵特征分解 4. 前几个特征向量(乘 1/√特征值)即投影
公式 适用
RBF(高斯) exp(−γ·‖x−y‖²) 多数非线性数据、光滑流形
多项式 (x·y + c)^d 多项式关系
Sigmoid tanh(α·x·y + c) 类神经网络映射

经典例子:2D 同心圆(两环嵌套),标准 PCA 把两环投到同一直线(分类无用);RBF 核 PCA 把内外圈映到不同区域,线性可分。

1.9 重建误差

降维好不好?压缩 784 到 50,丢了什么?量重建误差:

  1. 投影到 k 维:X_reduced = X @ W_k;
  2. 重建:X_hat = X_reduced @ W_kᵀ;
  3. 算 MSE:mean((X − X_hat)²)

对 PCA,重建误差与解释方差有干净关系:

重建误差 = 未保留的特征值之和 总方差 = 全部特征值之和 丢失比例 = 丢弃特征值之和 / 全部特征值之和

画累计解释方差对成分数的曲线得「肘部」,拐点处即合适成分数。重建误差还可用于异常检测:重建误差高的样本是不拟合学得子空间的离群点——这是生产系统里 PCA 异常检测的基础。

二、从零实现

完整源码见 phases/01-math-foundations/10-dimensionality-reduction/code/

2.1 PCA 类

class PCA: def __init__(self, n_components): self.n_components = n_components def fit(self, X): self.mean = np.mean(X, axis=0) X_centered = X - self.mean cov_matrix = np.cov(X_centered, rowvar=False) eigenvalues, eigenvectors = np.linalg.eigh(cov_matrix) # 协方差对称 → eigh sorted_idx = np.argsort(eigenvalues)[::-1] # 大到小 eigenvalues = eigenvalues[sorted_idx] eigenvectors = eigenvectors[:, sorted_idx] self.components = eigenvectors[:, :self.n_components].T self.eigenvalues = eigenvalues[:self.n_components] self.explained_variance_ratio_ = self.eigenvalues / np.sum(eigenvalues) return self def transform(self, X): return (X - self.mean) @ self.components.T def fit_transform(self, X): self.fit(X); return self.transform(X)

设计要点:协方差矩阵对称半正定,用 np.linalg.eigh(而非 eig)更稳更快且保证实特征值;特征向量按 [:, sorted_idx] 重排列(列对应特征值)。

2.2 在 MNIST 上对比

pca_50 = PCA(n_components=50); X_pca50 = pca_50.fit_transform(X_mnist) # 50 成分通常捕获 >80% 方差 from sklearn.manifold import TSNE from umap import UMAP X_tsne = TSNE(n_components=2, perplexity=30, random_state=42).fit_transform(X_mnist) X_umap = UMAP(n_components=2, n_neighbors=15, min_dist=0.1, random_state=42).fit_transform(X_mnist)

三、框架对比

实战中直接用 scikit-learn:

from sklearn.decomposition import PCA pca = PCA(n_components=2) X_reduced = pca.fit_transform(X_mnist) print(pca.explained_variance_ratio_)

sklearn 的 PCA 用 SVD(而非协方差特征分解)实现,数值更稳、更快;但数学等价。你的从零版本与之最大差异应在 1e-10 量级。

四、可复用产物

  • outputs/skill-dimensionality-reduction.md:一份帮你为给定任务选对降维技术的技能说明。
  • 本节的 PCA 类是后续章节(第 3 章机器学习、第 5 章计算机视觉的特征压缩)的复用件。

五、练习

  1. (Easy)PCAinverse_transform,用 10、50、200 成分重建 MNIST 数字,打印各自的重建误差(MSE)。
  2. (Medium) 对同一 MNIST 子集用 perplexity = 5、30、100 跑 t-SNE,描述输出如何变,为何 perplexity 影响簇紧密度?
  3. (Hard)make_classification 造 50 特征但只有 5 个有信息的数据集,套 PCA,看解释方差曲线是否正确识别「数据实质 5 维」。

本节要点回顾

  1. 维度灾难:高维下距离失效、体积集中角点、数据需求指数增长——降维把密度拉回可用。
  2. PCA 五步:中心化、协方差、特征分解、按特征值排序、投影到前 k 个特征向量。
  3. 解释方差比告诉你每个主成分捕获多少信息,累计达 0.90~0.95 即足够。
  4. 选 k 三法:阈值法、肘部法、下游性能平台法。
  5. t-SNE非线性、保局部邻居、适合出版级 2D 图但慢且簇间距离无意义。
  6. UMAP更快、保局部 + 部分全局结构,可处理百万样本。
  7. 核 PCA用核技巧在高维特征空间做 PCA,能分离同心圆这类非线性流形。
  8. 重建误差与解释方差互补:丢的特征值之和即误差,还可做异常检测。

下一节,我们进入线性代数的「瑞士军刀」——奇异值分解(SVD):它统一了 PCA、矩阵求逆、推荐系统、潜在语义分析,是把任意矩阵拆成「旋转—缩放—旋转」三步的万能工具。


发布者: 作者: Rohit Gupta 转发
评论区 (0)
U