2. sctransform算法原理:参数化负二项回归
好了,咱们正式开始啃这块硬骨头。
很多做单细胞的朋友,上来就直接跑SCTransform()。但你要问我,不懂原理就去调参,迟早要翻车。我之前帮一个团队排查批次效应,他们跑了SCTransform,结果聚类还是按样本分群。一看日志,参数没调对,正则化强度设得太高,生物信号被当噪声抹掉了。
所以,花半小时搞懂它背后的数学直觉,绝对值。
为什么是负二项?
单细胞数据最让人头疼的特征是什么?过离散。
你想想看,同一个基因在不同细胞里的UMI计数,方差往往远大于均值。这在泊松分布下是解释不了的——泊松要求方差等于均值。现实数据呢?方差经常是均值的几倍甚至几十倍。
我记得第一次处理10X数据时,画了个基因表达量的分布图,拖了个长长的尾巴。当时就知道,泊松肯定没戏。
负二项分布 (NB) 自带一个色散参数,可以同时建模均值和方差。公式长这样:
Var(Y) = μ + μ² / θ
其中 θ 是色散参数。θ 越小,过离散越严重。当 θ 趋近无穷大时,负二项就退化为泊松。
参数化模型怎么建模?
sctransform并没有用传统的广义线性模型那套框架。它的建模思路很直接,说白了就是三步:
- 学习全局参数:根据所有基因在所有细胞里的表达,估计出一套通用参数。
- 逐基因建模:对每个基因,拟合一个负二项回归模型,以UMI测序深度作为协变量。
- 提取残差:用模型预测值减去观测值,得到"标准化"后的残差。
但问题来了:如果对两万个基因逐个跑负二项回归,计算量太大了。我当年在集群上跑过一次,等了两个小时还没出结果。
sctransform的聪明之处在于,它用了一个参数化技巧,把拟合过程大大简化了。
参数化负二项回归的细节
sctransform模型假设:对于基因 g 在细胞 c 中的UMI计数 Y_{gc},其分布为:
Y_{gc} ~ NB(μ_{gc}, θ_g)
其中: log(μ_{gc}) = β_{0g} + β_{1g} * log(UMI_total_c)
这里的 log(UMI_total_c) 就是每个细胞的总UMI测序深度取对数。为什么要用对数?因为测序深度和表达量之间,基本上是幂律关系,取对数之后变成线性,好拟合。
然后重点来了:sctransform假设这些回归系数(β₀和β₁)与基因的均值之间,存在一个平滑的非线性关系。
换句话说,sctransform先用一小部分基因(默认2000个)拟合出完整的回归模型,然后通过核回归,预测出所有基因的回归系数。
模型拟合的完整流程
我整理了一张流程图,把整个参数化建模过程串起来:
残差的计算方式
模型拟合完成后,每个基因都有了完整的参数。接下来计算Pearson残差:
z_{gc} = (y_{gc} - μ̂_{gc}) / √(μ̂_{gc} + μ̂_{gc}² / θ̂_g)
这个残差z_{gc},就是你最终拿去做降维、聚类的输入值。
为什么不用原始的logCPM、TPM?因为那些方法没能把测序深度的影响完全剥离。sctransform的残差,去除的是"由测序深度带来的表达量变化",保留的是"超出预期的那部分信号"。
参数对比表
我把sctransform与传统标准化方法的核心差异,整理成了一张表:
| 对比维度 | LogNormalize | sctransform |
|---|---|---|
| 基础分布假设 | 泊松(隐含) | 负二项(显式建模过离散) |
| 协变量处理 | 离差缩放因子 | 直接回归建模测序深度 |
| 方差处理 | 全局缩放 | 基于正则化的基因特异方差 |
| 残差性质 | log(CPM), 方差不稳定 | Pearson残差, 方差稳定 |
| 计算效率 | 极快 | 较快(因参数化加速) |
| 批次校正集成 | 需要额外步骤 | 内置 (SCTransform v2) |
回归系数的生物学解释
说到这里,有朋友可能会问:「你花了这么大力气去拟合β₀和β₁,这两个系数到底代表什么?」
我个人习惯这么理解:
- β₀:截距项。反映的是这个基因的基础表达水平。直白点说,就是在测序深度取平均对数的情况下,这个基因预期会有多高表达。
- β₁:斜率项。反映的是基因对测序深度的敏感程度。如果β₁接近1,说明该基因的表达量和测序深度完全成正比——这种基因往往是非特异性的背景基因(比如线粒体基因)。
- θ:色散参数。决定这个基因在不同细胞间的波动程度。θ越小,基因的噪音越大。
我记得在分析肾脏单细胞数据时,β₁特别大的基因大多是核糖体蛋白基因。这说明这些基因的表达量高度依赖于细胞总体转录活性,而不是细胞类型特异的信号。在做降维之前,把这类基因的残差压低,反而让真实的细胞类型标记基因的信号更突出。
嗯,原理部分就讲这么多。下一层,我们会把这点理论拆成代码,一行一行跑通。