我们最近开设了一门课:Galaxy 经典课程:RNA-seq 数据分析实战。其中有一节内容是将差异基因富集到 KEGG 通路。
虽然我们向学员推广基于云平台的无代码数据分析,但是作为生信从业人员,搞清楚每一个工具背后的原理,甚至读一读软件的源代码,对专业能力的精进是大有禆益的。
例如 KEGG 富集分析,当我们深入学习 Y 叔的 clusterProfiler 包,理解了KEGG 富集分析本质上就是超几何检验算法的应用之后,可以试着自己手搓一个富集分析程序。
下面是我的实验:
library(magrittr)
library(dplyr)
library(readr)
library(qvalue)
library(enrichplot)
rm(list= ls())
# 需要富集的基因:207个
data(geneList, package="DOSE")
geneList
gene <-names(geneList)[abs(geneList)>2]
gene
length(gene)
gene_sets <- data.frame(gene_sets=gene)
gene_sets
head(gene_sets)
utils::data(list="kegg_category", package="clusterProfiler")
get("kegg_category", envir = .GlobalEnv)
kegg_category
kegg_category <- select(kegg_category,1:3)
# 下载表格数据
kegg_rest <-function(rest_url){
message('Reading KEGG annotation online: "', rest_url,'"...')
reader = readLines
params =list()
content <- do.call(reader, args =c(rest_url, params))
content %<>% strsplit(.,"\t")%>% do.call('rbind', .)
res <- data.frame(from=content[,1],
to=content[,2])
return(res)
}
# 下载 path - gene 列表
url ='https://rest.kegg.jp/link/hsa/pathway'
keggpathid2extid.df <- kegg_rest(url)
keggpathid2extid.df
keggpathid2extid.df[,1]%<>% gsub("[^:]+:","", .)
keggpathid2extid.df[,2]%<>% gsub("[^:]+:","", .)
# 下载 path - name 列表
url ='https://rest.kegg.jp/list/pathway/hsa'
keggpathid2name.df <- kegg_rest(url)
keggpathid2name.df
keggpathid2name.df[,2]<- sub("\\s-\\s[a-zA-Z ]+\\(\\w+\\)$","", keggpathid2name.df[,2])
# 过滤:无名称的通路不用于后续分析
kegg <- inner_join(keggpathid2extid.df, keggpathid2name.df, by ='from')|>
rename(path=1, gene=2, name=3)|>
select(1,3,2)|>
left_join(gene_sets, by =c("gene"="gene_sets"), keep =TRUE)
kegg_enrich <- filter(kegg,!is.na(gene_sets))
kegg
kegg_enrich
# 统计所有基因数, 各通路中基因的个数, 所有富集上的基因数, 富集上基因的通路
N <-length(unique(kegg$gene))
M <- count(kegg, path, name ='M')
n <-length(unique(kegg_enrich$gene_sets))
k <- count(kegg_enrich, path, name ='k')
N
M
n
k
# 整理信息
enrich_count <- left_join(k, M, by ="path")|>
mutate(O = N-M, n = n)
enrich_count
enrich_stats <- enrich_count |>
mutate(
GeneRatio = sprintf("%s/%s", k, n),
BgRatio = sprintf("%s/%s", M, N),
RichFactor = k / M,
FoldEnrichment = RichFactor * N / k,
mu = M * n / N,
sigma = mu *(N - n)*(N - M)/ N /(N-1),
zScore =(k - mu)/sqrt(sigma),
pvalue = phyper(k-1, M, O, n, lower.tail =FALSE),
p.adjust = p.adjust(pvalue, method="BH"),
Count = k
)|>
arrange(pvalue)|>
select(-k,-M,-O,-n,-mu,-sigma)
enrich_stats
qobj <- tryCatch(qvalue(p=enrich_stats$pvalue, lambda=0.05, pi0.method="bootstrap"), error=function(e)NULL)
if(inherits(qobj,"qvalue")){
qvalues <- qobj$qvalues
}else{
qvalues <-NA
}
enrich_stats$qvalue <- qvalues
enrich_stats
gene_id <- kegg_enrich |>
group_by(path)|>
summarize(geneID = paste(gene_sets, collapse ='/'))
gene_id
rval <- enrich_stats |>
mutate(id=sub("^\\D+","", path))|>
left_join(gene_id, by ="path")|>
left_join(keggpathid2name.df, by =c("path"="from"))|>
left_join(kegg_category, by ="id")|>
select(-id)|>
rename(
ID=path,
Description=to
)|>
select(category, subcategory, ID, Description, everything())|>
relocate(Count, .after = geneID)
rval
write_tsv(rval,'kegg_result.tsv')
这段代码共 120 行,其中有不少是冗余的(注释、空行,变量打印等),去掉冗余之后,一个 KEGG 富集分析程序应该可以控制在 100 行以内,因此标题并非哗众取宠。
感兴趣的朋友可以试着运行一下上述代码,成功后将结果与 clusterProfiler enrichKEGG 的进行比较,理论上应该完全一致。
好了,今天就介绍到这里,后续有时间我再将那些年手搓过的代码整理出来,不知道大家喜不喜欢看。
我们有一门Galaxy经典课程,感兴趣的朋友可以报名参加:
中国银河生信云平台(UseGalaxy.cn)以“让生信分析更简单”为使命,致力于为科研工作者、医疗机构和生物产业技术人员提供全栈式生物信息学分析解决方案。为了加强交流,我们建立了“Galaxy生信云平台”讨论群,添加小编微信usegalaxy邀请你入群,请备注“单位-姓名-专业-职称/年级”。
自己整理的ChIP seq分析步骤,有需要可以参考(持续更新)