PCA 做的事一句话说完: 找出数据里方差最大的那几个方向,把坐标轴换成它们。 Demo 用 4 个特征、 其实只有 2 个潜在因子的数据试了一次——前两个主成分吃掉 99.9% 的方差, 压到 2 维重建误差只剩 0.06%,而特征值明明白白告诉你:后两个方向加起来才 0.06%。
从这一节开始,第 3 章进入无监督学习:手上没有标签 y,只有一堆 x。 没有 y 就没法定义「预测错了多少」, 所以这一章的所有算法都在回答同一个问题——这批数据本身有什么结构? PCA 给的答案是: 它躺在哪几个方向上。第 2 章里被「维度灾难」折磨过的 KNN(见 2.9 节)最需要这一节的东西。
一、没有标签的时候,「结构」指什么
有监督学习的目标很明确:让预测值接近真实值。 无监督没有真实值可比,于是换了个思路——找数据自身的规律性。 规律性有很多种,这一章的八个算法各盯一种:
| 算法 | 它认为的「结构」 |
|---|---|
| PCA、LSA、NMF | 数据躺在一个低维的平面上(线性) |
| LDA | 同一类挤在一起,不同类离得远 |
| k-means、混合高斯 | 数据是几团拼起来的 |
| LLE、t-SNE | 数据躺在一个低维的弯面上 |
这四种「结构」假设互相不兼容,选错了算法,出来的图再漂亮也没有意义。 PCA 假设的是第一种,也是最省事的一种。
二、第一个主成分:方差最大的那个方向
先想一个二维的例子:一团点拉成斜的椭圆。你要用一条直线概括它们,这条线该朝哪? 朝椭圆的长轴。 因为投到长轴上,点散得最开,压成一条线之后损失的信息最少; 投到短轴上,所有点挤成一坨,就什么都看不出来了。 「散得最开」的量化就是方差。所以第一个主成分的定义是:让投影后方差最大的那个方向。 怎么算?不用搜索,有解析解。 把所有特征标准化之后算协方差矩阵 C, C 的最大特征值对应的特征向量就是第一个主成分的方向,这个特征值本身就是投影后的方差。 这件事有个重要推论: 特征值就是「这个方向上有多少信息」。 把所有特征值加起来等于特征个数(标准化之后每个特征的方差是 1), 所以「某个特征值除以总和」就是方差解释率——这个方向吃掉了百分之多少的信息。 Demo 里四个特征值分别是 2.7753、1.2425、0.0014、0.0009:第一主成分 69.0%,第二个 30.9%, 两个加起来 99.9%。后两个特征值小到 0.001 量级,等于在说「这两个方向上几乎没有变化」。
三、第二个主成分为什么必须垂直
第二个主成分的定义不是「方差第二大的方向」, 而是「在与第一个垂直的所有方向里,方差最大的那个」。这个「垂直」是硬要求。 为什么? 因为如果不要求垂直,第二个方向会无限逼近第一个方向——它俩几乎重合,第二个就等于白算, 一点新信息都没带来。 垂直在统计上的意思就是「不相关」:两个主成分之间的协方差为 0。 这样它们各自携带的信息才是互不重复的。 这个约束还有一个漂亮的后果:主成分就是协方差矩阵的特征向量。 对称矩阵的特征向量天生两两正交, 正好满足要求。所以 PCA 的计算归结成一次特征值分解,不需要任何迭代。 Demo 里第一主成分的权重是 (−0.5944, −0.5607, +0.1066, +0.5666):x1 和 x4 符号相反。 回头看生成数据的那一行——x4 是「−0.6 f1 加上一点噪声」,g 和 f1 反向, 所以 x1 与 x4 该反着走。PCA 不知道这件事,它只是从协方差矩阵里读出了符号。 注意权重里的负号不用纠结。 特征向量乘以 −1 还是特征向量,换个库、换个版本, 符号可能整个反过来。看绝对值,看相对大小。
四、降到几维:解释率与重建误差
保留几个主成分,取决于你要干什么,但判断标准是同一个:丢掉的那部分有多少。 两种说法其实是一回事。方差解释率说「前 k 个吃掉了多少信息」; 重建误差说「压到 k 维再乘回去,和原始数据差多少」。 数学上后者等于「被丢掉的奇异值平方和」,和前者互补。 Demo 里量了三个档:留 1 维误差 0.3096、留 2 维 0.0006、留 3 维 0.0002。 从 1 到 2 是断崖式下降,从 2 到 3 几乎没动。 这个「断崖」就是该保留的维数—— 和 k-means 的肘部法是同一个思路。 实际用的时候有几个经验值:做可视化留 2 到 3 维(人能看);做压缩留到累计解释率 95% 左右; 做特征预处理给下游模型,常见的是留到 99%。但这些都只是起点,最终要看下游任务的效果。 有一个坑必须提: PCA 挑的是「方差大」,不是「对预测有用」。 如果某个方向方差很小但恰好和标签高度相关, PCA 会毫不犹豫地把它扔掉。这时该用的是 3.4 节的 LDA——它按「能不能分开类」来挑方向。
五、它成立需要三个前提
第一,结构必须是线性的。 PCA 用协方差矩阵,而协方差只衡量线性相关。 如果数据躺在一张卷起来的曲面上,PCA 会把它压扁、把不同层叠在一起——这是 3.7 节 LLE 要解决的问题。 第二,必须标准化。 一个特征以万元计、一个以百分比计,不标准化的话前者的方差能到后者的几万倍, 第一主成分会被它独吞。 这不只是精度问题,是结论完全错掉。 1.2 节量过同一件事:不标准化时 KNN 准确率 0.3556, 标准化后 0.9333。 第三,主成分方向可正可负。 这一点前面说过,但它在工程里会咬人:把 PCA 结果存下来做增量训练时, 新一批数据算出来的主成分可能整体反号,直接拼上去就把模型搞坏了。 工程上一般会加一步「符号对齐」。
六、动手 Demo:4 个特征,其实是 2 个因子拼出来的
造 200 个样本、4 个特征,但这 4 个特征全由两个看不见的潜在因子 f1、f2 拼出来, 其中 x4 是「−0.6 f1 + 0.5 f2」,故意和 x1 反向。 真实场景里你只知道 4 个测量值,看不到因子——PCA 要做的就是把因子反推回来。 代码只有十几行:标准化、算协方差、特征值分解、排序、投影。没有迭代,没有学习率,一次算完。
import numpy as np
mu, sd = X.mean(axis=0), X.std(axis=0) # 先标准化,不然量纲大的特征独吞
Z = (X - mu) / sd
C = np.cov(Z, rowvar=False) # 协方差矩阵:谁和谁同向变化
ev, evec = np.linalg.eigh(C) # 特征值 = 这个方向的方差
order = np.argsort(ev)[::-1]
ev, evec = ev[order], evec[:, order]
ratio = ev / ev.sum() # 方差解释率
T2 = Z @ evec[:, :2] # 压到 2 维
rec2 = T2 @ evec[:, :2].T # 再乘回去,看丢了多少
实跑输出:
--------------------------------------------------------------------
PCA:找方差最大的那几个方向
--------------------------------------------------------------------
造 200 个样本、4 个特征。这 4 个特征其实都由**两个潜在因子**
拼出来的,只是我们看不到因子,只看到 4 个测量值。PCA 要做的,就是把这两个因子反推出来。
【一】特征值就是「每个方向上有多少方差」
主成分 特征值 方差解释率 累计
--------------------------------------------
第 1 2.7753 0.6904 0.6904
第 2 1.2425 0.3091 0.9994
第 3 0.0014 0.0004 0.9998
第 4 0.0009 0.0002 1.0000
第一主成分解释了 69.0% 的方差,前两个加起来 99.9%。
**这意味着 4 个特征里真正有用的信息,基本集中在两个方向上。**
【二】前两个主成分长什么样
特征 第 1 主成分 第 2 主成分
----------------------------------
x1 -0.5944 -0.1389
x2 -0.5607 -0.3261
x3 +0.1066 -0.8850
x4 +0.5666 -0.3018
第一主成分在 x1、x2、x4 上都有较大权重,
且 x1 与 x4 符号相反——这和造假数据时「x4 = −0.6 f1 + …」正好对上。
**PCA 把「谁和谁同向变化」这件事从协方差矩阵里读了出来。**
【三】降维:从 4 维压到 2 维,丢了多少
保留主成分数 重建误差(均方) 重建误差占原方差
--------------------------------------------------
1 0.3096 0.3096
2 0.0006 0.0006
3 0.0002 0.0002
保留 2 个主成分,重建误差只占原方差的 0.1%——**把维度砍一半,信息只丢了这么点。**
这就是降维能成立的根本原因:真实数据几乎总是躺在一个比原始维度低得多的「薄片」上。
【四】PCA 的三个前提,缺一个就不成立
**第一,它只找线性结构。**
PCA 用协方差矩阵,协方差只衡量线性相关。如果数据躺在一个弯曲的流形上(比如瑞士卷),
PCA 会把它压扁成一团——3.7 节的 LLE 就是为解决这个才出现的。
**第二,它对尺度敏感。**
不标准化的话,量纲大的特征会独吞第一主成分。上面代码里先做了 z 标准化,
就是为了避免这件事。
**第三,主成分方向可正可负。** 特征向量的符号是任意的,换个库、换个版本,符号可能反过来。
**看结果时别纠结正负,看绝对值。**
特征值那张表是这一节的核心。2.7753、1.2425、0.0014、0.0009——前两个占 99.9%, 后两个加起来 0.06%。数据其实只有 2 维,多出来的 2 个特征纯粹是噪声。 权重表要看符号关系。第一主成分在 x1、x2、x4 上都大,且 x1 与 x4 反号; 第二主成分几乎只在 x3 上(−0.8850)。 回头对生成规则:x3 = 0.4 f2 + 噪声,它是唯一主要由 f2 决定的特征,所以第二主成分压在它身上。 重建那张表要看「断崖」。留 1 维误差 0.3096,留 2 维 0.0006——掉了一千倍。留 3 维 0.0002, 和 2 维几乎一样。所以 2 就是这份数据的真实维度,PCA 自己把它量出来了。 这里没有「准确率」可报。无监督学习没有标签,就没有对错,只有「解释了多少方差」。 这是第 3 章所有算法共同的评价困境——后面几节会用「纯度」「邻居保持率」「分离度」这些替代指标, 但它们都只是代理,不是真值。
30 秒实验
- 把 x4 的系数从「−0.6 f1 + 0.5 f2」改成「+0.6 f1 + 0.5 f2」,第一主成分的权重会怎么变?
- 去掉标准化那一步,把 x3 乘以 1000,第一个主成分会变成什么方向?解释率呢?
- 保留 2 个主成分之后,用这两个坐标重建数据,和原始数据算相关系数,会是多少?
常见误区
- 不标准化就做 PCA。这是最常见的错。 量纲大的特征会独吞第一主成分,你以为在降维,其实是在看「哪个特征的单位大」。 除非所有特征本来同量纲。
- 把方差解释率当成「模型好坏」。解释率高只说明数据确实低秩,不说明这些方向对预测有用。 PCA 是无监督的,它不知道你要预测什么。
- 以为 PCA 能处理非线性结构。遇到弯曲流形时 PCA 会把不同层叠在一起,而且它不会报错, 只是出来的图看着「有结构」其实全是错的。先画个图看看再说。
自测三问(点开对答案)
1. 为什么第二个主成分必须和第一个垂直? —— 不垂直的话它会无限逼近第一个方向,两者几乎重合,第二个就等于白算。 垂直在统计上等于不相关,保证两个主成分携带的信息互不重复。 2. 四个特征值 2.0、1.0、0.5、0.5,第一主成分的方差解释率是多少? —— 2.0 ÷ 4 = 0.5,也就是 50%。标准化之后特征值之和等于特征个数,所以分母是 4。 3. PCA 降维之后,原始特征的名字还能用吗? —— 不能直接用。 新坐标是原始特征的线性组合,「第一主成分 = −0.59 x1 − 0.56 x2 + …」,它没有业务名字。 要解释就去看权重绝对值大的那几个原始特征。PCA 处理的是「一张数值表」。 如果这张表是「词 × 文档」,同样的一次奇异值分解就换了个名字——3.2 节的 LSA。
- ☐ (本节完,下一节 3.2 算法 11:LSA)