3、PCA原理(下):PCA的数学推导步骤、数据标准化的重要性、主成分的选取准则
好,咱们接着聊PCA。上一节我们把PCA的核心思想讲清楚了——就是找一组新的坐标轴,让数据投影上去之后方差最大。说白了,就是帮数据“转个身”,让最重要的信息露出来。
这一节,咱们要动真格的了。我会把PCA的数学推导一步步拆开,再聊聊为什么标准化那么重要,最后告诉你到底选几个主成分才合适。嗯,这些坑我都踩过,咱们一个一个说。
3.1 PCA的数学推导:一步步拆解
先别被“数学推导”四个字吓到。其实PCA的数学逻辑非常优雅,你跟着我走一遍就明白了。
假设我们有一个数据集 X,它是 n×p 的矩阵(n个样本,p个特征)。我们的目标是找到一组新的基向量(主成分),让数据投影后的方差最大。
第一步:数据中心化
这是前提。把每个特征的均值归零:
X_centered = X - mean(X, axis=0)
为什么要这么做?因为如果数据没居中,第一主成分会被均值偏移带偏,而不是真正捕捉方差方向。我刚开始学的时候没注意这个,结果画出来的主成分方向怎么看怎么别扭。
第二步:计算协方差矩阵
协方差矩阵 C 是 p×p 的方阵,它告诉我们特征两两之间的相关性:
C = (1/(n-1)) * X_centered.T @ X_centered
这个矩阵的对角线是每个特征的方差,非对角线是协方差。你想想看,如果两个特征高度相关,那它们其实在说同一件事,PCA就能把它们合并成一个主成分。
第三步:特征值分解
对协方差矩阵做特征值分解:
eigenvalues, eigenvectors = np.linalg.eig(C)
这里的关键是:特征向量就是主成分的方向,特征值就是该方向上的方差大小。
我习惯把特征值从大到小排序,对应的特征向量就是第一主成分、第二主成分……
第四步:选择前k个特征向量
取前k个最大的特征值对应的特征向量,组成投影矩阵 W(p×k)。
第五步:数据投影
X_pca = X_centered @ W
搞定。这就是降维后的数据。
核心要点:PCA的本质就是协方差矩阵的特征值分解。特征值越大,说明这个方向保留的原始信息越多。
3.2 数据标准化:这一步千万别省
这个问题我吃过亏。有一次做客户数据降维,特征里有“年龄”(20-60)和“年收入”(5万-200万)。你猜怎么着?第一主成分几乎完全被“年收入”主导,因为它的数值范围大,方差天然就大。
但这不是我们想要的。我们希望PCA找到的是数据内在的结构,而不是被量纲牵着鼻子走。
标准化的做法:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
标准化之后,每个特征的均值为0,标准差为1。这样所有特征就在同一个尺度上比较了。
注意:如果特征的量纲本身就有意义(比如都是同一类物理测量值),可以不标准化。但绝大多数场景下,我建议你标准化。我曾经因为没标准化,导致主成分解释完全跑偏,排查了半天才发现是量纲问题。
你想想看,如果“年龄”的方差是200,“年收入”的方差是2000万,PCA会优先捕捉年收入的波动,但这对你的业务分析可能毫无意义。标准化之后,每个特征才有公平的“发言权”。
3.3 主成分的选取准则:到底选几个?
这是PCA里最实际的问题。选少了丢信息,选多了没达到降维目的。我一般用下面几种方法来判断。
方法一:累计方差贡献率
这是最常用的方法。计算每个主成分的方差占比,然后看前k个主成分累计解释了多少方差。
explained_variance_ratio = eigenvalues / sum(eigenvalues)
cumulative = np.cumsum(explained_variance_ratio)
通常我们设定一个阈值,比如80%或90%。累计方差达到这个阈值时,就取对应的k值。
我个人习惯设85%。为什么不是90%?因为很多时候,最后10%的方差来自噪声,强行保留反而会引入干扰。
方法二:碎石图(Scree Plot)
把特征值从大到小画成折线图。你会看到一条“陡坡”然后变平缓的曲线。
import matplotlib.pyplot as plt
plt.plot(range(1, len(eigenvalues)+1), eigenvalues, 'o-')
plt.xlabel('主成分序号')
plt.ylabel('特征值')
plt.title('碎石图')
plt.show()
拐点(肘部)之前的主成分就是我们要保留的。这个方法很直观,我经常用它来做快速判断。
小技巧:如果碎石图没有明显的拐点,说明数据本身就没有特别强的结构。这时候我会结合业务需求来定——比如我要降到2维做可视化,那就直接取k=2。
方法三:Kaiser准则
只保留特征值大于1的主成分。这个准则来自因子分析,简单粗暴,但有时候挺好用。
不过要小心——如果特征数量很少(比如只有3个),这个准则可能太保守了。
方法四:交叉验证法
这是比较高级的做法。把数据分成训练集和验证集,在训练集上做PCA,然后在验证集上计算重建误差。选择误差最小的k值。
嗯,这个方法计算量大,但结果最可靠。我在做高维基因数据时用过一次,效果不错。
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 累计方差贡献率 | 通用场景 | 简单直观 | 阈值需要主观设定 |
| 碎石图 | 快速探索 | 可视化,一目了然 | 拐点可能不明显 |
| Kaiser准则 | 特征较多时 | 有明确标准 | 可能过于保守 |
| 交叉验证 | 对精度要求高 | 结果最可靠 | 计算量大 |
我的建议:先用碎石图快速定位大概范围,再用累计方差贡献率精确确定。如果业务上有特殊要求(比如要降到2维做可视化),那就直接按业务需求来。别纠结,PCA是工具,不是目的。
好了,这一节的内容就到这儿。PCA的数学推导其实不复杂,关键是要理解每一步在干什么。标准化是必须的,除非你有充分的理由不这么做。选主成分时,别贪多,也别太少,找到那个“刚刚好”的点就行。
下一节,咱们会用Python手撸一个PCA,到时候你就知道这些理论怎么落地了。