第3章 PCA原理:从协方差矩阵到降维

各位同学,欢迎来到第三章。上一章我们聊了聊为什么要做PCA,说白了就是想在成千上万个基因里,找到最能解释差异的那几个方向。这一章,我们来点硬核的——PCA到底是怎么把高维数据「压扁」的?

你可能会问:降维听起来很玄乎,数学原理到底难不难?我个人觉得,理解了协方差矩阵,PCA就搞懂了一半。剩下的就是特征值分解,这个你大学线性代数肯定学过,咱们回忆一下就好。

3.1 为什么要从「协方差」说起?

先想想看,我们手头的数据是什么样子的?一个基因表达矩阵,行为基因,列为样本。每个样本就是一个点在N维空间里(N是基因数)。我们想找的是:哪些方向的数据波动最大?

波动,在统计上就是方差。但光看每个基因自己的方差还不够——基因之间还有相关性。A基因表达高了,B基因是不是也跟着高?这种协同变化的量,就是协方差。

我个人习惯这样记:

  • 方差:一个变量自己跟自己「闹腾」的程度
  • 协方差:两个变量一起「闹腾」的程度

如果所有基因都是独立的,那PCA就很简单了——我们只需要把方差大的基因挑出来就行。但现实中的基因表达数据,相关性很复杂。所以才需要协方差矩阵这个工具,把所有的成对关系打包在一起。

核心理解:协方差矩阵是一个对称矩阵,对角线上是每个基因的方差,非对角线上是基因两两之间的协方差。它在PCA中扮演了「信息地图」的角色。

3.2 协方差矩阵的数学形式

假设我们有m个样本,n个基因。数据矩阵X是m×n的,每一列是中心化后的一个基因(减去均值)。那么协方差矩阵C就是:

C = (1/(m-1)) * X^T * X

C是一个n×n的对称矩阵
第i行第j列 = cov(gene_i, gene_j)
对角线元素 = var(gene_i)

为什么是n×n?因为我们要考察所有基因两两之间的关系。如果你有2万个基因,这个矩阵就是2万×2万的——非常大,但对计算机来说不是问题。

我记得有次项目里,有人直接拿原始表达矩阵算协方差,忘记做中心化了。结果跑出来的PCA前几个主成分全是均值偏移,根本没法用。嗯,这里要注意——中心化是必要前提。

避坑指南:计算协方差矩阵前,一定先对每个基因(或变量)做中心化处理,即减去均值。不做中心化,第一主成分会被平均数「带偏」。

3.3 特征值和特征向量:PCA的灵魂

现在我们有了协方差矩阵C。下一步是什么?特征值分解。

你可能会问:为什么偏偏是特征值和特征向量?

这其实很直观。特征向量代表了数据变化的方向,特征值代表了在这个方向上变化的「强度」。PCA做的事情,就是从协方差矩阵中提取出这些方向和强度,然后按强度排序。

概念 在PCA中的含义
特征向量 主成分的方向(即新坐标轴)
特征值 该方向上的方差(即信息量)
特征值越大 该方向越重要,数据差异越明显

具体数学上:

C * v = λ * v

其中:
C  — 协方差矩阵
v  — 特征向量(列向量)
λ  — 对应的特征值

小技巧:在Python中用numpy做特征值分解很容易。我习惯用 np.linalg.eigh 而不是 eig,因为协方差矩阵是对称的,用 eigh 更稳定、更快。

3.4 从特征值到降维:保留多少成分?

好,特征值分解做完了。我们得到了n个特征向量(方向)和n个特征值(方差大小)。那么问题来了——我们要保留几个主成分?

做法很简单:把所有特征值从大到小排序,然后计算累积解释方差比例。

解释方差比例 = λ_i / sum(λ)

累积解释方差比例 = (λ_1 + λ_2 + ... + λ_k) / sum(λ)

通常,我们会选前k个主成分,使得累积解释方差比例超过一个阈值,比如80%或90%。

我曾经遇到一个情况:某个实验数据的前两个主成分就解释了95%以上的方差。这说明什么?说明这个数据其实「低维结构」很明显,基因表达差异被少数几个关键因子主导。反过来,有些数据前十主成分才勉强达到70%,说明噪声很大,或者群体结构不清晰。

所以我说,PCA不仅是一种降维方法,更是一种诊断工具。通过看解释方差的变化曲线(Scree Plot),你能判断数据的内在复杂性。

实用经验:在差异表达分析中,如果前两个主成分解释的方差不到30%,你得小心了——数据可能没有明显的分组结构,或者批次效应太强。这是我踩过的坑,分享给大家。

3.5 降维的几何意义:投影

现在我们已经选好了前k个特征向量(主成分方向)。下一步就是把原始数据「投影」到这些新轴上。

投影的数学就是矩阵乘法:

Y = X * W

其中:
X  — 中心化后的原始数据矩阵 (m×n)
W  — 前k个特征向量组成的矩阵 (n×k)
Y  — 降维后的数据矩阵 (m×k)

这么一乘,每个样本就从n维空间,降到了k维空间。而且,这k维空间里,样本的分布保留了原始数据中最大的方差结构。

换句话说,我们做了一件很聪明的事情:扔掉的信息,都是「不重要」的信息。

注意:投影后,各主成分之间是正交的(不相关),这也是为什么PCA能消除多重共线性的原因。但这个正交性只保证在全局方差上最优,不代表每个主成分都有生物学含义——它们只是数学构造。

3.6 PCA的核心知识结构

这张SVG图我花了不少心思整理,把PCA从数据准备到降维输出的全过程串了起来。你看一眼就能理解整个流程。

PCA从数据到降维:核心流程 原始表达矩阵 m样本 × n基因 中心化处理 每列减去均值 协方差矩阵 C:n×n 对称矩阵 特征值分解 λ₁ ≥ λ₂ ≥ ... ≥ λₙ 选择前k个 累积解释方差 ≥ 阈值 投影到主成分空间 Y = X · W 降维后数据 m样本 × k主成分 关键参数:k值 一般取累积解释方差≥80% 计算协方差 提取方向和强度 降维完成

3.7 实际操作中的几个关键抉择

PCA的原理说完了,但很多人在实际操作中会犹豫。我列几个最常见的问题和我的建议:

  1. 要不要做标准化(scaling)?——如果基因的表达量范围差异太大(比如有的基因几万,有的几百),建议先标准化到均值为0、标准差为1。否则,PCA会被高表达量的基因「绑架」。
  2. 特征值分解 vs SVD?——其实是一回事。PCA可以用SVD(奇异值分解)实现,数值稳定性更好。我个人在Python里常用 sklearn.decomposition.PCA,它底层用的就是SVD。
  3. 怎么判断k值?——看Scree Plot的「拐点」是一个经典方法。但我更建议结合任务来看:如果目的是去除批次效应,可能前10-20个主成分就够了;如果是为了可视化,直接取前2个或3个。

实用建议:在做差异表达分析前,我总会先从PCA图看一遍数据。如果对照和实验组在PC1上有明显分离,说明差异信号足够强,后续差异基因筛选会轻松很多。如果两组混在一起,那你得想想——是不是样品出了问题?或者差异本来就微弱?