理解DESeq2统计模型:负二项分布与缩并估计

咱们直接切入正题。DESeq2 的核心,就是用一个数学模型来描述基因表达数据。你想想看,RNA-seq 的计数数据有个很讨厌的特性——方差比均值大得多。这不是普通的泊松分布能搞定的。DESeq2 选用了 负二项分布,又叫 NB 分布,正是因为这个分布多了一个离散参数,能兜住那种“过度离散”的现象。

我刚开始用的时候,也犯过嘀咕:为什么非要用 NB?直接用泊松省事多了。后来在项目里处理一批 replicate 差异很大的样本,才发现泊松根本压不住方差,假阳性满天飞。嗯,从那以后我彻底服了 NB。

负二项分布:均值与方差的亲密关系

NB 分布的数学形式我就不展开了,但你需要记住一个关键公式:

方差 = 均值 + 离散度 × 均值²

这个离散度参数(记作 α,或者用 DESeq2 里的 dispersion)决定了方差超过均值的幅度。α 越大,数据越“散”;α = 0 时,NB 退化为泊松。你想想看,如果所有基因的 α 都设成同一值,那估计起来多简单?但现实是每个基因都有自己的脾气——有些基因表达稳定,α 很小;有些基因受噪声影响大,α 很大。

关键点:DESeq2 不是为每个基因独立估计离散度的。它利用所有基因的信息,对离散度做“缩并估计”(shrinkage estimation)。这就是它威力所在。

缩并估计:借力打力的贝叶斯智慧

怎么理解缩并?我举个例子。你有一个基因,只有 3 个 replicate,数据波动很大。如果你只用这 3 个点估计它的离散度,结果会非常不靠谱。但是,如果你同时看到其他几千个基因的离散度分布——大多数基因的离散度集中在某个区间——那你就可以把这个基因的估计值“拉”向这个集中区间。这就叫缩并。

DESeq2 采用 经验贝叶斯 策略:先用所有基因估计一个离散度的先验分布(通常是 Gamma 分布),然后对每个基因的离散度做后验估计。说白了,就是给每个基因一个“修正因子”,避免极端值带来的误导。

个人经验:我遇到过一组数据,其中某个基因在对照组和实验组都只有 1 个 replicate(剩下是技术重复)。如果不缩并,那个基因的 P 值几乎全是 0.9999——它被判定为非差异。缩并后,它一举成为前 50 的差异基因。后来 qPCR 验证,确实显著。缩并救活了它。

DESeq2 中的两步估计流程

下面这张图概括了 DESeq2 如何从原始计数走到最终差异检验。注意,离散度估计是卡在中间的关键一步。

DESeq2 离散度缩并估计流程 原始基因计数矩阵 每个基因独立估计离散度 拟合先验 Gamma 分布 缩并后验离散度 核心思想 弱基因借强基因的信息 缩并朝向先验均值 保留真实生物学变异

控制缩并效果的几个参数

参数 作用 我常用的设置
fitType 选择拟合先验分布的方式:parametric(默认,假设均值-离散度曲线为平滑曲线)、local(非参数局部回归)、mean(直接对每个表达水平分组计算均值) 样本量大时用 parametric;样本少且基因表达范围广时换 local
minReplicatesForReplace 当某个条件(组)内 replicate 数少于该值时,DESeq2 会用缩并值替代原始离散度估计 默认是 Inf(全部替换),但我习惯设为 3,留一点原始信息
useT 是否用 t 分布计算 P 值;TRUE 时对缩并离散度的不确定性做额外校正 小样本(n ≤ 5)时开启,大样本按默认

我曾经踩过一次坑:在做时间序列分析时,每个时间点只有 2 个生物学重复,却把 fitType 设成了 parametric。结果拟合曲线被少数基因带偏,导致大量假阴性。后来换成 local 才稳住。所以参数没有绝对的好,要看数据集的总体分布特征。

实际操作:如何修改参数

在 DESeqDataSet 建成后,你可以直接用 estimateDispersions 或者通过 DESeq 函数传递参数。下面是我常用的代码块:

dds <- DESeqDataSetFromMatrix(
  countData = counts,
  colData = coldata,
  design = ~ condition
)

# 手动控制缩并参数
dds <- estimateDispersions(dds,
                           fitType = "local",
                           minReplicatesForReplace = 3)

# 或者直接用 DESeq() 一步到位
dds <- DESeq(dds, fitType = "parametric")

如果你想知道每个基因的最终离散度长什么样,可以在 colData 里找到 dispersion 一列。我会习惯画一个散点图看看均值-离散度关系,确认缩并有没有把离群值拉回来。

留个心眼:缩并也有副作用。如果某个基因的真实生物学变异确实非常大(比如组织特异性高表达基因),缩并可能会把它压回背景水平,导致漏检。这时候可以查看 mcols(dds)$dispersion 中的 dispersionPriorVar,看看缩并的程度是否合理。我在一篇关于免疫细胞亚群的项目中就遇到过这种情况,最后手动调高了那个基因的离散度权重。

小结:别让参数变成黑盒

负二项分布 + 缩并估计,这两样东西构成了 DESeq2 的脊梁骨。你不需要搞懂数学推导,但必须理解这背后的逻辑:为什么要缩并?缩并的力度受哪些按钮控制?

我的建议是:跑第一个分析时,全部用默认参数。然后打印出离散度分布图,看看有没有基因的离散度被异常拉高或压低。如果有,再调整 fitType 或 minReplicatesForReplace。千万别一上来就盲目改参数——你想想看,连数据长什么样都不知道,就去拧旋钮,不是瞎搞吗?