说到转录组分析,很多人第一反应就是“哇,好复杂,代码一堆,P值满天飞”。但说实话,这玩意儿其实就像是在侦探破案——你有一堆线索(差异表达基因),需要通过KEGG通路和GO功能注释这些“情报网”把它们串起来,最后还原出细胞里到底发生了什么生物故事。今天我就带你把这个过程掰开了、揉碎了讲清楚,保证你看完不仅能跑通代码,还能真正读懂里面的生物学含义。
为什么我们需要KEGG和GO?先看一个小例子
假设你正在研究一种新药对肝癌细胞的影响。经过RNA-seq实验,你得到了几百个差异表达基因(DEGs)。这时候问题来了:这几百个基因意味着什么?哪个通路被激活了?细胞是在增殖还是凋亡?
这时候KEGG和GO就成了你的救星。
- KEGG(Kyoto Encyclopedia of Genes and Genomes):专注于代谢通路、信号转导通路等,告诉你基因参与哪些“生化反应路线”。
- GO(Gene Ontology):从三个维度描述基因功能——生物学过程(BP)、细胞组分(CC)、分子功能(MF),给你一个更全面的“功能画像”。
举个例子:如果你发现差异基因里“凋亡”相关的基因显著富集,那这个药很可能是在诱导癌细胞死亡——这个结论比看几百个基因名要有意义得多。
整体流程概览:从原始数据到生物学解读
整个分析流程大致可以分为以下几个步骤:
- 数据预处理:质控、比对、定量
- 差异表达分析:找出显著变化的基因
- 功能注释富集分析:KEGG + GO
- 结果可视化与生物学解读
今天我们的重点在第3步和第4步,也就是如何用R语言批量处理并解读结果。但为了上下文完整,我会简单带过前两步,让你知道数据来源是哪里。
第一步:数据预处理(简要回顾)
这部分通常用Snakemake或Nextflow等流程化工具,或者直接用R包处理。核心是用DESeq2或edgeR进行差异分析。假设你已经得到了一个差异基因的表达矩阵,格式大概长这样:
log2FoldChange padj
GeneA 2.35 1.2e-05
GeneB -1.89 3.4e-03
GeneC 0.12 0.85
...
padj是校正后的P值,通常我们取padj < 0.05且|log2FoldChange| > 1的基因作为差异基因。这些基因就是后续富集分析的输入。
第二步:KEGG和GO富集分析的核心代码
这里我会用最流行的clusterProfiler包,它是R语言中转录组功能富集分析的事实标准。安装和加载这些包:
# 安装必要包(如果还没装的话)
if (!require("BiocManager", quietly = TRUE))
install.packages("BiocManager")
BiocManager::install(c("clusterProfiler", "org.Hs.eg.db", "enrichplot", "GSEABase"))
# 加载库
library(clusterProfiler)
library(org.Hs.eg.db) # 人类基因注释,其他物种换对应的包,如org.Mm.eg.db(小鼠)
library(enrichplot)
library(GSEABase)
2.1 准备基因列表
假设你已经有一个差异基因向量,需要把基因名转换成ENTREZ ID(KEGG和GO富集分析通常需要ID格式):
# 假设diff_genes是你的差异基因数据框,Row.names是基因Symbol
# 转换Symbol到ENTREZ ID
gene_list <- bitr(
rownames(diff_genes),
fromType = "SYMBOL",
toType = "ENTREZID",
OrgDb = org.Hs.eg.db
)
# 同时保留log2FoldChange,用于后续基因集富集分析(GSEA)
names(gene_list$ENTREZID) <- gene_list$SYMBOL
gene_list_named <- setNames(diff_genes$log2FoldChange, gene_list$ENTREZID)
# 排序,用于GSEA
gene_list_sorted <- sort(gene_list_named, decreasing = TRUE)
2.2 GO富集分析
# 进行GO富集分析
go_enrich <- enrichGO(
gene = gene_list$ENTREZID, # 差异基因ENTREZ ID列表
OrgDb = org.Hs.eg.db, # 物种注释数据库
ont = "ALL", # 分析所有三个本体:BP, CC, MF;也可选"BP"或"MF"
pAdjustMethod = "BH", # 多重检验校正方法:Benjamini-Hochberg
pvalueCutoff = 0.05, # P值阈值
qvalueCutoff = 0.2, # FDR阈值
readable = TRUE # 将ENTREZ ID转回基因Symbol,方便阅读
)
# 查看结果
head(go_enrich)
输出的结果通常包含这些列:ID(GO term)、Description(描述)、GeneRatio(差异基因中属于该term的比例)、BgRatio(背景中属于该term的比例)、pvalue、pAdjust、geneID(参与该term的差异基因列表)、count(基因数量)。
2.3 KEGG富集分析
# 进行KEGG富集分析
kegg_enrich <- enrichKEGG(
gene = gene_list$ENTREZID,
organism = "hsa", # 人类;小鼠用"mmu",大鼠用"rat"等
pAdjustMethod = "BH",
pvalueCutoff = 0.05,
qvalueCutoff = 0.2,
outDir = NULL
)
# 查看结果
head(kegg_enrich)
2.4 GSEA:全基因组范围的富集分析
有时候你不想只盯着差异基因,而是想把所有基因按表达变化程度排序,看哪些通路在整体上也呈现协同变化。这就是GSEA(Gene Set Enrichment Analysis)的用武之地:
# GSEA分析
go_gsea <- gseGO(
geneList = gene_list_sorted, # 排序后的全基因组基因列表
OrgDb = org.Hs.eg.db,
ont = "BP", # 只看生物学过程
nPerm = 1000,
minGSSize = 10,
maxGSSize = 500,
pvalueCutoff = 0.05
)
kegg_gsea <- gseKEGG(
geneList = gene_list_sorted,
organism = "hsa",
nPerm = 1000,
minGSSize = 10,
maxGSSize = 500,
pvalueCutoff = 0.05
)
GSEA的结果里多了NES(Normalized Enrichment Score)和core_enrichment(核心富集基因),能告诉你哪些基因是该通路富集的主要贡献者。
第三步:可视化——让结果会说话
枯燥的表格没人爱看,好的可视化才能让生物学故事自己讲出来。
3.1 GO富集结果可视化
# 条形图:展示Top 10显著GO term
barplot(go_enrich, showCategory = 10) + ggtitle("GO Biological Process Enrichment")
# 点图:同时展示显著性和基因比例
dotplot(go_enrich, showCategory = 20) + ggtitle("GO Enrichment Dot Plot")
# 气泡图:更直观,大小表示基因数量,颜色表示P值
cnetplot(go_enrich, categorySize = "pvalue", foldChange = diff_genes$log2FoldChange)
# 拓扑图:展示GO term之间的关系
godag(go_enrich, top 10, layout = "kk")
# 热力图:展示基因在多个term中的分布
emapplot(go_enrich, groupSize = "odd")
3.2 KEGG富集结果可视化
# KEGG通路图:直接在通路图上标注差异基因
k = keggPathway(kegg_enrich$ID[1]) # 取第一个显著通路
plot(k, showGeneMap = TRUE,
geneMap = list(group1 = kegg_enrich@geneID[1]))
# 或者用更简单的富集图
plotKEGG(kegg_enrich, top 10)
clusterProfiler还有一个神器叫cnetplot,能画出资讯量极高的网络图:节点是GO term或KEGG通路,连线连接共同的基因,节点大小和颜色反映显著性。
3.3 自定义美化:让图看起来像Nature级别的
有时候默认的图不够好看,我们可以用ggplot2深度定制:
# 提取数据
ego_data <- as.data.frame(go_enrich)
# 自定义气泡图
library(ggplot2)
p <- ggplot(ego_data, aes(x = reorder(Description, pvalue), y = pvalue,
size = Count, color = -log10(pvalue))) +
geom_point() +
scale_y_log10() +
coord_flip() +
labs(title = "Top 15 GO Terms Enriched in Differentially Expressed Genes",
x = "", y = "Adjusted P-value", size = "Gene Count") +
theme_minimal()
print(p)
第四步:批量处理多个条件或样本组
很多时候你不只有一个比较组,比如你有对照组 vs 处理组A,对照组 vs 处理组B,甚至多个时间点。这时候手动跑太累了,用循环和purrr就能优雅地批量处理:
library(purrr)
# 假设你有三个对比组的差异基因数据框列表
diff_gene_lists <- list(
"A_vs_Control" = diff_genes_A,
"B_vs_Control" = diff_genes_B,
"C_vs_Control" = diff_genes_C
)
# 批量GO富集分析
go_results <- map(diff_gene_lists, ~ {
# 转换基因ID
gene_ids <- bitr(rownames(.x), fromType = "SYMBOL", toType = "ENTREZID",
OrgDb = org.Hs.eg.db)
# 富集分析
enrichGO(
gene = gene_ids$ENTREZID,
OrgDb = org.Hs.eg.db,
ont = "BP",
pAdjustMethod = "BH",
pvalueCutoff = 0.05
)
})
# 批量KEGG富集
kegg_results <- map(diff_gene_lists, ~ {
gene_ids <- bitr(rownames(.x), fromType = "SYMBOL", toType = "ENTREZID",
OrgDb = org.Hs.eg.db)
enrichKEGG(
gene = gene_ids$ENTREZID,
organism = "hsa",
pAdjustMethod = "BH",
pvalueCutoff = 0.05
)
})
# 合并结果,方便后续分析
go_combined <- rbindlist(go_results, idcol = "Condition")
kegg_combined <- rbindlist(kegg_results, idcol = "Condition")
这样你就能一次性得到所有条件的富集结果,然后对比不同条件下哪些通路是共享的、哪些是特异的。
第五步:解读结果——从数据到生物学故事
这是最关键、也最容易让人困惑的一步。拿到一堆GO term和KEGG通路,怎么看?
5.1 先看最显著的top term
打开你的富集结果,找到pAdjust最小的那些term。比如:
immune responseinflammatory responseT cell activationinterferon signaling pathway
这些词告诉你,差异基因主要参与免疫相关的生物学过程。如果再结合KEGG结果看到TNF signaling pathway、NF-kappa B signaling pathway显著富集,那基本可以推断:你的处理可能激活了炎症/免疫反应。
5.2 注意基因数量(count)和GeneRatio
有时候某个term的P值很显著,但只有3个基因参与。这种情况可靠性较低。建议同时关注Count >= 5且pAdjust < 0.05的结果,这样更有说服力。
5.3 结合已知文献验证
假设你发现p53 signaling pathway显著富集,你可以去PubMed搜一下:是否已有文献报道你的药物/处理能激活p53通路?如果已有报道,你的结果就得到了独立验证;如果没有,这可能是一个新的发现,值得深入探究。
5.4 避免常见陷阱
- 不要只看P值:多重检验校正后的P值才是可靠的,原始P值容易有假阳性。
- 注意背景基因集:
enrichGO和enrichKEGG默认的背景是人类所有注释基因。如果你的实验只检测了一部分基因(比如聚焦某些基因),需要手动指定背景。 - 物种要匹配:用错了物种数据库(比如把人类基因用小鼠注释)会导致结果完全错误。
一个完整的实战例子
假设你有一批肝癌vs癌旁的差异基因数据(模拟数据):
# 模拟差异基因数据
set.seed(123)
diff_genes <- data.frame(
SYMBOL = rownames(diff_expr),
log2FoldChange = rnorm(nrow(diff_expr), mean = 0, sd = 1),
padj = runif(nrow(diff_expr), 0, 0.1)
)
diff_genes <- diff_genes[diff_genes$padj < 0.05 & abs(diff_genes$log2FoldChange) > 1, ]
# 执行富集分析
gene_ids <- bitr(diff_genes$SYMBOL, fromType = "SYMBOL", toType = "ENTREZID",
OrgDb = org.Hs.eg.db)
go_res <- enrichGO(gene = gene_ids$ENTREZID, OrgDb = org.Hs.eg.db,
ont = "BP", pAdjustMethod = "BH", pvalueCutoff = 0.05)
kegg_res <- enrichKEGG(gene = gene_ids$ENTREZID, organism = "hsa",
pAdjustMethod = "BH", pvalueCutoff = 0.05)
# 可视化
dotplot(go_res, showCategory = 15) + ggtitle("GO Enrichment in Liver Cancer")
barplot(kegg_res, showCategory = 10) + ggtitle("KEGG Pathway Enrichment")
运行后你可能会看到cell cycle、DNA replication、p53 signaling pathway等显著富集——这非常符合肝癌的生物学特征:癌细胞疯狂增殖。这样的结果不仅验证了实验的可靠性,也为后续机制研究提供了方向。
进阶技巧:如何提升分析质量
使用自定义基因集
clusterProfiler支持自定义基因集,比如你有一个实验室自己构建的“免疫相关基因集”:
custom_gene_sets <- list(
immune_genes = c("CD3D", "CD3E", "IL2", "IFNG", "TNF", ...),
apoptosis_genes = c("BCL2", "CASP3", "CASP9", "TP53", ...)
)
# 转换为GSEABase格式
gene_sets <- fromList(custom_gene_sets)
# 进行GSEA
gsea_custom <- gseGeneric(geneList = gene_list_sorted, geneSets = gene_sets)
整合多组学数据
如果你还有蛋白质组或代谢组数据,可以用mixOmics或WGCNA做整合分析,找到转录水平和蛋白水平的共同调控模块。
用fgsea加速GSEA
当基因集很多时,clusterProfiler的GSEA可能比较慢。fgsea包是专门优化的快速GSEA实现:
library(fgsea)
# 准备 pathway 和 scores
pathways <- msigdb::msigdb("Homo sapiens", "C2", "cp")
scores <- gene_list_sorted
# 运行fgsea
fgsea_res <- fgsea(pathways = pathways, stats = scores, nperm = 10000)
总结:把技术变成生物学洞察
说到底,KEGG和GO富集分析不是目的,理解生物学意义才是。工具只是帮你从海量数据中提炼信号,真正的洞察来自于你对领域的熟悉——你知道哪些通路在肝癌中重要,哪些基因是已知的驱动因子,哪些结果符合预期、哪些出乎意料。
建议你在跑完分析后,做一个简单的表格,列出最显著的通路、参与的基因、以及可能的生物学解释。这样无论是写论文还是和导师讨论,都能有理有据。
如果你在分析过程中遇到具体问题——比如某个物种没有合适的注释包、或者结果太少找不到显著通路——别慌,大多数问题都能通过调整参数或换用其他包(如topGO、GAGE)来解决。欢迎随时来问,我们一起把数据背后的故事挖出来。
记住:好的分析不是堆砌代码,而是用代码讲好一个生物学故事。祝你分析顺利!
