主成分分析(PCA)基础:数学原理、协方差矩阵、特征值与特征向量
说到数据降维,PCA绝对是最经典的那一个。我刚开始接触机器学习时,第一个认真啃的算法就是它。你想想看,几百维的数据一眼看过去全是数字,根本不知道哪些特征重要。PCA能把这些信息浓缩到几个主成分里,还不丢失太多结构。今天咱们就把它最核心的数学骨架拆开,看看协方差矩阵、特征值、特征向量到底在干嘛。
核心思想:最大化方差
PCA的本质其实就是找个新坐标系。这个坐标系的原点在数据中心,轴的方向要保证数据投影到轴上后方差最大。说白了,就是把数据铺得最开的方向找出来。第一个方向是第一主成分,第二个方向跟第一个垂直,再找次大方差……以此类推。
我当年刚学的时候总觉得“最大化方差”太抽象。后来做了个实验:拿二维点云在某个方向投影,投影点越分散,保留的信息就越多。如果投影后所有点挤成一团,那这个方向基本没用。嗯,这么一想就通了。
协方差矩阵:衡量变量间的关系
要找“数据铺得最开的方向”,你得先知道各个维度之间是怎么联动的。协方差矩阵就是干这个的。它是个对称方阵,第 i 行第 j 列的元素表示第 i 个特征和第 j 个特征之间的协方差。
我自己的经验:如果你拿到的数据量纲差距太大(比如一个特征范围0~1,另一个是0~10000),一定要先做标准化,否则协方差矩阵会被那个大数值的特征主导,PCA结果直接跑偏。
假设我们有 n 个样本,d 个特征,中心化后的数据矩阵是 X(n×d)。那么协方差矩阵 C 的计算公式是:
C = (1/(n-1)) * Xᵀ X
如果你用 Python 的 NumPy,一行代码就能算出来:
import numpy as np
# X 是已经中心化后的数据,shape = (n, d)
C = np.cov(X.T) # 注意要转置,因为np.cov默认每行是一个变量
协方差矩阵的对角线是各个特征的方差,非对角线是协方差。方差越大,特征本身的信息量越大;协方差的绝对值越大,两个特征相关性越强——PCA会通过旋转坐标系把这种相关性解掉。
特征值与特征向量:PCA的引擎
协方差矩阵算完之后,真正的关键步骤来了:对它做特征分解。得到一组特征值 λ 和对应的特征向量 v。它们满足:
C v = λ v
我刚开始看这个公式时也觉得玄乎。其实几何意义很简单:特征向量 v 代表一个方向,矩阵 C 作用在这个方向上只会拉伸(或压缩),而不会旋转。拉伸的倍数就是特征值 λ。
在PCA里,特征向量就是主成分的方向,特征值的大小决定了这个方向的重要性。你把特征值从大到小排个序,最大的那个特征值对应的特征向量就是第一主成分。为什么?因为它的拉伸倍数最大,意味着在这个方向上数据的方差最大。
这里有个小坑:特征向量的符号是任意的。也就是说同一个方向,v 和 -v 都是合法的特征向量。我曾经在项目中遇到过两次PCA结果图里主成分方向完全相反的情况,吓得我以为代码写错了。后来才发现只是符号翻转,对降维结果没影响。
用 NumPy 做特征分解也很直接:
eigen_values, eigen_vectors = np.linalg.eig(C)
# 按特征值从大到小排序
idx = np.argsort(eigen_values)[::-1]
eigen_values = eigen_values[idx]
eigen_vectors = eigen_vectors[:, idx]
注意,eigen_vectors 的每一列是一个特征向量,不是每一行。
PCA 的完整步骤
你看,数学原理就这么几块。实际操作时流程很清晰:
- 数据中心化:每个特征减去自己的均值,得到零均值数据。
- 计算协方差矩阵:根据中心化后的数据算。
- 特征分解:得到特征值和特征向量。
- 选主成分:按特征值从大到小排序,取前 k 个特征向量构成投影矩阵。
- 降维投影:原始数据乘上投影矩阵,得到 k 维的降维结果。
整个流程可以用下面这张图串起来:
我建议你在实际操作中,先把上面这个流程用 NumPy 手写一遍——别急着调 sklearn。自己算一遍协方差矩阵,自己跑一遍 np.linalg.eig,对特征值排序,然后投影。只有亲手敲过,你才会发现什么叫“特征向量就是主成分方向”。
| 概念 | 定义 | 在 PCA 中的角色 |
|---|---|---|
| 方差 | 数据在某个方向上的离散程度 | 衡量该方向保留的信息量 |
| 协方差 | 两个特征一起变化的趋势 | 协方差矩阵的构造元素 |
| 特征值 | 特征向量方向上数据投影的方差 | 决定主成分的重要性顺序 |
| 特征向量 | 协方差矩阵拉伸不旋转的方向 | 作为新坐标系的轴方向 |
注意:协方差矩阵是对称半正定矩阵,它的特征值一定是非负实数。如果你算出来负的特征值(在数值误差下可能为非常小的负数),说明数据可能没有完全中心化,或者数值精度出了问题。我建议检查一下中心化的均值是不是真的接近零。
至于怎么选保留多少个主成分,常用方法是看累计方差解释比例。把特征值归一化(除以总和),然后从大到小累加,直到达到某个阈值(比如 95%)。这个我后面还会细讲,但数学原理就是这一套。
嗯,PCA 的数学基础说透了其实不复杂:协方差矩阵描述特征关系,特征分解找到最重要的方向。剩下的就是线性代数里那些基础操作。你在项目里如果用顺手了,会发现它是个非常扎实的“硬”工具——至少在那些特征线性相关较强的场景下特别好使。我曾经处理过基因表达数据,几千个特征,PCA 一跑前两个成分就把样本聚类了,省了不知道多少功夫。