edgeR、limma-voom、DESeq2 怎么选
跟完这篇,您能根据自己的样本量、数据类型和设计复杂度,在 edgeR、limma-voom、DESeq2 三者中选定一个(或干脆三个都跑),并在三者结果对不上时,按一张清单逐条排查,判断分歧是正常现象还是哪里出了错。
做 bulk RNA-seq 差异分析,绕不开这三个包。它们都久经检验、都靠得住,网上却常把「哪个更好」吵成玄学。其实选择没那么玄:它们的差别是统计模型和适用场景的差别,对上您的数据就有答案。这篇不比高下,只给您一套可照着走的判断流程,外加一份把三个都跑通的最小代码。
一句话先分清三个工具
先建立整体印象,细节留到后面。
| 工具 | 统计模型 | 归一化 | 一句话定位 |
|---|---|---|---|
| DESeq2 | 负二项 GLM,Wald 检验 | median-of-ratios | 上手最省心,小样本稳,结果表和收缩倍数都给全 |
| edgeR | 负二项 GLM,准似然 F 检验 | TMM | 与 DESeq2 同源,小样本同样稳,QL 检验对假阳性控制好 |
| limma-voom | 线性模型 + 精度权重,moderated t 检验 | TMM | 最快、对复杂设计最灵活,样本量大时尤其稳 |
三者都要原始 counts(非负整数),都不能喂 TPM、FPKM、RPKM。这一点没有例外——limma-voom 看似处理的是连续值,但它也是从原始 counts 出发、自己在内部完成归一化和转换的。为什么必须用原始 counts,见 counts、TPM、FPKM 怎么分。
原理差异:它们在建什么模型
选工具之前,先弄清它们「算法上到底不一样在哪」,后面的取舍才不是背口诀。
DESeq2 和 edgeR 是一家人。 两者都把每个基因的 counts 看作服从负二项分布,用广义线性模型(GLM)拟合分组效应。counts 数据有个特点:均值越大、方差越大,负二项分布正是为这种「计数」量身定制的。它们最关键的共同点,是都用经验贝叶斯在成千上万个基因之间借信息来估计离散度(每个基因的变异程度)——这让它们在重复数很少时依然能给出稳健的方差估计。
两者的差别主要在细节:
- 归一化不同:DESeq2 用 median-of-ratios,edgeR 用 TMM。思路相近,多数数据上结论接近。
- 默认检验不同:DESeq2 默认 Wald 检验;edgeR 推荐
glmQLFit+glmQLFTest的准似然(quasi-likelihood)F 检验,它把离散度估计的不确定性也算进去,对假阳性的控制通常更保守。
limma-voom 是另一条路。 它不直接对 counts 建负二项模型,而是分两步:先用 voom 把 counts 变成 log-CPM,并根据均值—方差关系给每个观测值算一个精度权重(表达越低、越不可信的点权重越小);再把这些带权重的值喂给 limma 成熟的线性模型 + 经验贝叶斯 moderated t 检验框架。这套框架原本是为芯片数据打磨了多年的,好处是极快,且面对复杂设计(多因素、配对/区组、连续协变量、交互项)时写起来最灵活。
一句话记忆:DESeq2 / edgeR 直接对计数建模,小样本稳;limma-voom 转成连续值加权后建模,快且擅长复杂设计。
按样本量选
样本量是最实在的分岔点。下面的倾向是常见比较研究的大致共识,按数据调、不是硬阈值。
- 每组重复很少(约 2~3 个):优先 DESeq2 或 edgeR。它们的经验贝叶斯离散度收缩在样本少时「借力」最明显,用极少的重复也能压住方差估计的噪声。这是它们最擅长的场景。
- 每组重复中等(约 5 个以上)到大队列:limma-voom 越来越有优势。它快得多(几十上百个样本时差距明显),FDR 控制稳;相反,样本量很大时 DESeq2/edgeR 有时会偏激进(假阳性略多)。临床队列这类几十上百样本的场景,limma-voom 往往是稳妥之选。
几点提醒,避免把上面的话当铁律:
- 这些倾向是统计性质上的平均表现,不是保证。在多数真实数据上,三者的 top 强信号基因高度重叠,分歧集中在临界区。
- 无论哪个工具,每组只有 1 个样本都做不了差异分析(没有组内变异可估)。重复数太少时,增加重复永远比纠结换哪个工具更管用。
- 需要复杂设计(多个协变量、交互、区组)时,无论样本量大小,limma-voom 的写法通常最省心,edgeR 的 GLM 通路次之。
按数据类型选
样本量之外,还要看数据本身是不是「计数」。选错这一步,模型的前提假设直接不成立。
| 您的数据 | 该用什么 | 别用什么 |
|---|---|---|
| 原始 counts(bulk RNA-seq、CRISPR 筛选、部分 counts 型测序) | DESeq2 / edgeR / limma-voom 都行 | 别喂 TPM、FPKM |
| 已经是连续/对数强度(表达芯片、已 log 的定量蛋白/代谢组等) | limma(普通 limma,可配 limma-trend) | 别用 DESeq2/edgeR(负二项不适用),也别用 voom |
要点就一句:负二项模型(DESeq2、edgeR)和 voom 都是为原始 counts 设计的;数据一旦本就是连续值或对数强度,改用普通 limma 直接建线性模型。 把 TPM 硬塞进 DESeq2,或把芯片强度当 counts 跑 edgeR,得到的 p 值都不可信。
三个都跑一遍(推荐做法)
拿不准哪个更适合时,最省心的办法是三个都跑,看结果重不重合。下面用同一份 counts(行基因、列样本)和同一个分组向量 group,给出三段最小可跑的骨架。为方便对齐,先统一把对照组设为参照水平。
group <- relevel(factor(group), ref = "control") # 统一对照方向,treated 比 control
DESeq2
library(DESeq2)
colData <- data.frame(group = group, row.names = colnames(counts))
dds <- DESeqDataSetFromMatrix(counts, colData, design = ~ group)
dds <- DESeq(dds)
res_deseq <- results(dds, contrast = c("group", "treated", "control"))
edgeR(准似然,推荐)
library(edgeR)
y <- DGEList(counts = counts, group = group)
keep <- filterByExpr(y, group = group) # 按惯例过滤低表达基因
y <- y[keep, , keep.lib.sizes = FALSE]
y <- calcNormFactors(y) # TMM 归一化
design <- model.matrix(~ group)
y <- estimateDisp(y, design)
fit <- glmQLFit(y, design)
qlf <- glmQLFTest(fit, coef = 2) # 第 2 列 = treated vs control
res_edger <- topTags(qlf, n = Inf)$table
limma-voom
library(limma); library(edgeR)
y <- DGEList(counts = counts)
keep <- filterByExpr(y, group = group)
y <- y[keep, , keep.lib.sizes = FALSE]
y <- calcNormFactors(y)
design <- model.matrix(~ group)
v <- voom(y, design) # 转 log-CPM 并估计精度权重
fit <- lmFit(v, design)
fit <- eBayes(fit)
res_limma <- topTable(fit, coef = 2, number = Inf)
跑完取三者显著基因的交集,作为高置信集,通常比信任任何单个工具都稳:
sig_deseq <- rownames(subset(as.data.frame(res_deseq),
padj < 0.05 & abs(log2FoldChange) > 1))
sig_edger <- rownames(subset(res_edger, FDR < 0.05 & abs(logFC) > 1))
sig_limma <- rownames(subset(res_limma, adj.P.Val < 0.05 & abs(logFC) > 1))
common <- Reduce(intersect, list(sig_deseq, sig_edger, sig_limma))
这里的 padj < 0.05 且 |log2FC| > 1(变化 2 倍)是常用惯例、不是铁律,要按数据和问题调,展开见 DESeq2 怎么做对 里的阈值一节。
三个结果对不上,先查什么
三者跑出来不完全一致,是常态,不是都得吓一跳。按下面顺序排查,能分清「正常分歧」和「真出错」。
-
先接受:它们本就不会逐基因完全相同。 模型和归一化不同,强信号基因通常高度重叠,分歧集中在临界区——padj 卡在 0.05 附近、低表达、低倍数的那些基因,排序会抖。这不是 bug。
-
确认您比的是「同一列」。 三个工具的显著性列和倍数列名字不一样,别把它们当算错了:
工具 校正后 p 值(FDR) log2 倍数变化 DESeq2 padjlog2FoldChangeedgeR FDRlogFClimma-voom adj.P.VallogFC三者的 FDR 默认都用 BH 法校正,口径一致,可以直接横比。
-
输入是否一致。 是同一份原始 counts 吗?分组和对照方向(参照水平)是否一致?对照设反了,倍数变化会整体反号,看着就像两套结果。
-
过滤是否一致。
filterByExpr、手动rowSums门槛、DESeq2 的独立过滤,会让「进入检验的基因集合」不同,从而改变多重检验的分母、连带改变 padj。先统一过滤规则再比。 -
log2FC 是否被收缩。 DESeq2 若跑了
lfcShrink,倍数会被往 0 拉;拿它和 edgeR/limma 的未收缩logFC直接比,会觉得「小了一截」。比较时两边都用未收缩的,或都用收缩后的。 -
归一化差异。 DESeq2 用 median-of-ratios、edgeR/limma 用 TMM,多数时候结论接近;但当个别样本存在极端高表达基因时,可能拉开差别。
-
样本量太小。 每组只有 2 个重复时,任何工具都不稳,三者对不上很正常。这种情况下别纠结换工具,补重复才是解法。
稳妥的收尾方式始终是:三者都跑、取交集当高置信集,单个工具独有的差异基因放到次要位置、留待验证。
在平台上跑一遍
不想在三个包之间反复配环境、对齐参数,可以在百沐一下直接做这一步:上传原始 counts 矩阵和样本分组表,用自然语言说清「哪组比哪组、对照是谁、样本量多大」,平台会零代码替您选定合适的方法跑完差异分析,并给出结果表和火山图;关键处(分组列、对照方向、过滤与阈值)它会先与您确认,选得不合适也能追问着改。
从上传到出结果的完整流程见 组学智能体使用指南,或直接开始:https://app.baimuyixia.com。