如何用R语言做差异代谢物的kegg富集分析

编写:王采荷

感觉已经很久没有在简书上分享自己的东西了,今天在集合其他大佬的力量终于把“如何用R语言做差异代谢物的kegg富集分析”这个问题给解决了。我决定将这个过程分享到简书上,一来可以给在这方面有需求的其他朋友一个参考;二来如果有错误的地方也能得到大佬的指点。这篇短文主要分为以下三个部分组成;

一、将代谢物及对应的KEGG数据库信息进行下载并整理

  • 数据下载
# 加载所需要的R包
rm(list = ls())
library(XML)
library(RCurl)
library(tidyverse)
library(ggplot2)
library(magrittr)
library(clusterProfiler)
#' 第一步下载KEGG数据库信息
extractCompounds <- function(pathwayId) {
  compoundUrl <- paste0("https://www.genome.jp/dbget-bin/get_linkdb?-t+compound+path:", pathwayId)
  compoundDoc <- htmlParse(getURL(compoundUrl), encoding = "utf-8")
  compoundLinks <- getNodeSet(compoundDoc, "/html/body/pre/a")
  compoundIds <- sapply(compoundLinks, function(node) xmlGetAttr(node, "href"))
  compoundNames <- sapply(getNodeSet(compoundDoc, "/html/body/pre/text()"), xmlValue)[-1]
  data.frame(compoundId = paste(compoundIds, collapse = ";"), compoundName = paste(compoundNames, collapse = ";"))
}

# Main process
keggUrl <- "https://www.genome.jp/kegg/pathway.html#global"
keggDoc <- htmlParse(getURL(keggUrl), encoding = "UTF-8")

pathwayLinks <- getNodeSet(keggDoc, "//a[@href]")
pathwayIds <- sapply(pathwayLinks[65:276], function(node) gsub("/pathway/", "", xmlGetAttr(node, "href")))
pathwayNames <- sapply(pathwayLinks[65:276], xmlValue)

# Applying extractCompounds function to each pathwayId
compoundDataList <- Map(extractCompounds, pathwayIds)
pathwayData <- do.call(rbind, compoundDataList)

# Combine all data into a single data frame
finalData <- data.frame(pathwayId = pathwayIds, pathwayName = pathwayNames, pathwayData)
finalData %>% write_csv(paste0("KeggAllcompounds-",Sys.Date(),".csv"))
finalData2 <- finalData[finalData$compoundId != "", ]

==注意事项==
finalData2 <- finalData[finalData$compoundId != "", ]这一步的目的是为了将finalDate$compoundId中有空值的的进行删除,否则后面数据整理的时候会报错。

  • 数据整理
#' 分别采用for和map的方式将结果进行整理
#' 整理成为result_data和result_data2
#' 采用for循环的方式 
result_data <- data.frame()
nrow(finalData2)
for (i in 1:nrow(finalData2)) {
  cid <- finalData2$compoundId[i]
  extracted_cid <- str_extract_all(cid, "C\\d+")
  CID <- unlist(extracted_cid)
  CName <- finalData2$compoundName[i]
  split_CName <- strsplit(CName, "\n;")
  CompoundName <- lapply(split_CName[[1]], trimws) %>% unlist()
  pathway <- cbind(CID, CompoundName)
  pathwayId <- rep(finalData2$pathwayId[i], nrow(pathway))
  pathwayName <- rep(finalData2$pathwayName[i], nrow(pathway))
  dat <- cbind(pathway, pathwayId, pathwayName)
  result_data <- rbind(result_data, dat)
}

#' 采用map的方式
# Define a function to process each row
process_row <- function(row) {
  cid <- row$compoundId
  extracted_cid <- str_extract_all(cid, "C\\d+")
  CID <- unlist(extracted_cid)
  
  CName <- row$compoundName
  split_CName <- strsplit(CName, "\n;")
  CompoundName <- lapply(split_CName[[1]], trimws) %>% unlist()
  
  # Ensure the result is a data frame
  if (length(CID) > 0 && length(CompoundName) > 0) {
    pathway <- data.frame(CID, CompoundName, stringsAsFactors = FALSE)
    pathwayId <- rep(row$pathwayId, nrow(pathway))
    pathwayName <- rep(row$pathwayName, nrow(pathway))
    return(data.frame(pathway, pathwayId, pathwayName, stringsAsFactors = FALSE))
  } else {
    return(data.frame(CID = character(), CompoundName = character(), pathwayId = row$pathwayId, pathwayName = row$pathwayName, stringsAsFactors = FALSE))
  }
}

# Apply the process_row function to each row of finalData using map_df
result_data2 <- map_df(seq_len(nrow(finalData2)), ~process_row(finalData2[.x, ]))

result_data %>% write_csv(paste0("keggAllCompoundReshapedData2-",Sys.Date(),".csv")) #将整理好的结果进行储存,后面可以直接读取进来用,不用重复跑前面的代码,毕竟也需要时间的
result_data2 %>% write_csv(paste0("keggAllCompoundReshapedData22-",Sys.Date(),".csv")
表1 初步整理后的代谢物kegg数据库表
  • 对kegg代谢物数据库进一步整理
# 后期富集分析只需要保留表1的第1和第4列
keggannotation <- result_data %>% 
  select(c(-2,-3)) %>% set_colnames(c("ID", "pathway"))

二、进行kegg富集分析

  • 先将自己测定的正负离子模式代谢物鉴定的表(注意要包含kegg id这一列,如果没有,想方设法将代谢物的kegg id找到)读取后进行整理
uploadfile1 <- "D:/其他人员2/王书/公司结果/非靶向/Result-X101SC23124721-Z01-J002-B1-42/Result-X101SC23124721-Z01-J002-B1-42/2.MetAnnotation/HMDB_KEGG_Lipidmaps"
uploadfile2 <- "D:/其他人员2/王书/公司结果/非靶向/Result-X101SC23124721-Z01-J002-B1-42/Result-X101SC23124721-Z01-J002-B1-42/3.MetDiffScreening/MPP.vs.MPN" 
allkeggid <- read.csv(paste0(uploadfile1,"/meta_intensity_neg_hmdb_kegg_lipidmaps.csv")) %>% select(Kegg_ID) %>% 
  bind_rows(.,read.csv(paste0(uploadfile1,"/meta_intensity_pos_hmdb_kegg_lipidmaps.csv")) %>% select(Kegg_ID)) %>% 
  filter(Kegg_ID != "--") %>% 
  set_colnames("ID") %>% 
  mutate(across("ID",str_replace,"cpd:", ""))

其实就是把正负离子代谢物所对应的KEGG ID合并,如表2:


表2 正负离子代谢物表读取后只保留kegg id这一列
  • 读取自己的差异代谢物并保留kegg id
#'差异代谢物
diffkeggid <- read.csv(paste0(uploadfile2,"/MPP.vs.MPN_neg_diff.anno.csv")) %>% select(Kegg_ID) %>% 
  bind_rows(.,read.csv(paste0(uploadfile2,"/MPP.vs.MPN_pos_diff.anno.csv")) %>% select(Kegg_ID)) %>% 
  filter(Kegg_ID != "--") %>% 
  set_colnames("ID") %>% 
  mutate(across("ID",str_replace,"cpd:", ""))
  • 数据整合
    这里需要大家理解的是,我们每个人做的课题不一样,所测定到的代谢物也不一样,所以需要根据自己实际测定到的代谢物具体多少,构建自己的代谢物kegg背景库,而不是直接采用表1来进行富集分析。如表3所示:
total <- right_join(keggannotation,allkeggid,by="ID") %>% select(2,1)
表3 基于自己项目测出的代谢物构建kegg库
  • kegg富集分析并导出结果
# 富集分析
x <- clusterProfiler::enricher(gene = diffkeggid$ID,TERM2GENE = total,minGSSize = 1,pvalueCutoff = 1,qvalueCutoff = 1)
# 结果导出
write.csv(as.data.frame(x@result) %>% select(-1,-2),
          file = paste0(uploadfile2,"/MP_KEGG_enrichment_result.csv"))

我们来看看富集分析的结果怎么样,如表4所示:


表4 代谢物kegg富集分析结果

三、对富集的结果进行整理和可视化

#' 1.数据清洗
df <- read_csv(paste0(uploadfile2,"/MP_KEGG_enrichment_result.csv")) %>%
  dplyr::rename("Description"="...1") %>% 
  arrange(desc(Count)) %>%
  select(1,2,3,4,8) %>% 
  separate(`GeneRatio`,into=c("A","B"),sep="/") %>%
  mutate(A=as.numeric(A),B=as.numeric(B)) %>%
  mutate(count=A/B) %>% head(10) %>% arrange(Count)

#' 2.定义因子
df$Description <- factor(df$Description,levels = c(df$Description %>% as.data.frame() %>% pull()))

#' 3.数据可视化
p <- df %>% ggplot(aes(count,Description))+
  geom_point(aes(size=Count,color=pvalue,fill=pvalue),pch=21)+
  scale_color_gradientn(colours = (rev(RColorBrewer::brewer.pal(11,"RdBu"))))+
  scale_fill_gradientn(colours =(rev(RColorBrewer::brewer.pal(11,"RdBu"))))+
  guides(size=guide_legend(title="Count"))+
  labs(x=NULL,y=NULL)+
  theme(axis.title = element_blank(),
        axis.text.x=element_text(color="black",angle =0,hjust=0.5,vjust=0.5, margin = margin(b =5)),
        axis.text.y=element_text(color="black",angle =0,hjust=1,vjust=0.5),
        panel.background = element_rect(fill = NA,color = NA),
        panel.grid.minor= element_line(size=0.2,color="#e5e5e5"),
        panel.grid.major = element_line(size=0.2,color="#e5e5e5"),
        panel.border = element_rect(fill=NA,color="black",size=1,linetype="solid"),
        legend.key=element_blank(),
        legend.title = element_text(color="black",size=9),
        legend.text = element_text(color="black",size=8),
        legend.spacing.x=unit(0.1,'cm'),
        legend.key.width=unit(0.5,'cm'),
        legend.key.height=unit(0.5,'cm'),
        legend.background=element_blank(),
        legend.box="horizontal",
        legend.box.background = element_rect(color="black"),
        legend.position = c(1,0),legend.justification = c(1,0))+
  scale_y_discrete(labels = function(y) str_wrap(y,width=30))
ggsave(paste0(uploadfile2, "/MP_Kegg_enrichment.png"), plot = p, width = 6, height = 6, dpi = 300)
  • 结果如图所示


    图1 kegg富集分析通路图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容