ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

TCMSP中药网络药理学:从成分筛选到GO/KEGG富集的完整R代码实操

TCMSP中药网络药理学:从成分筛选到GO/KEGG富集的完整R代码实操

简介:面向中药网络药理学入门与实操的R语言学习资料,聚焦TCMSP数据库应用,适合药理学、生物信息学方向的研究生和科研人员。压缩包内含217个文件,整体约23.93MB,视频教程讲解数据获取与处理流程,R/Perl脚本(r、pl)提供可复用分析代码,PDF课件梳理课程知识点,png图展示网络可视化结果,xml、tsv、csv等文件保存中间数据。已有1825人学习下载。内容覆盖TCMSP数据库介绍与访问、R语言环境搭建、数据清洗、药物-靶点网络绘制(igraph)、GO与KEGG功能富集分析等核心主题,视频演示与代码脚本一一对应,并配有PDF课件随堂笔记,便于边看边练、随时复习。通过系统学习可掌握从中药成分筛选、靶点预测到网络解析的完整知识链,为中药复杂作用机制研究和论文写作提供实用工具。

1. TCMSP 中药网络药理学资料:一套能直接跑通的视频与代码

搞中药复方机制研究的人,八成都被 TCMSP 卡过:要么数据库进不去,要么下载了成分表不知道下一步干啥。这套「TCMSP 中药网络药理学资料(视频+代码)」解决的就是从 TCMSP 拿数据到出图出表的完整链路问题——活性成分筛选、靶点预测、PPI 网络构建、GO/KEGG 富集,一套代码从头跑到尾,视频里每一步都有操作演示。适合正在写 network pharmacology 文章、需要补一套标准流程的硕博生和临床科研人员,也适合想快速验证一个复方有没有分析价值的从业者。我拆完这套资料最直接的感受是:它不是把步骤念给你听,而是把「哪里容易断、断了怎么续」也讲清楚了。

这套内容的技术栈核心就两个:TCMSP 数据库的检索与下载规范、R 语言的分析管道。下面按我实际复现的顺序,把数据获取、靶点处理、富集分析、绘图交付和踩坑记录逐一展开。

2. 从 TCMSP 拿数:成分筛选与靶点下载的完整操作

2.1 TCMSP 的 ID 构成与检索参数

TCMSP 的检索 URL 有固定套路,知道这个套路你就能用脚本批量拉数据,不用每次手动点网页。TCMSP 的化合物查询接口核心参数是herb_name,比如我们要分析黄连,URL 构造是:

# 黄连的 TCMSP 成分检索 curl -L "https://old.tcmsp-e.com/tcmspsearch.php?qr=黄连&qsr=herb_name&token=xxxx"

这里qr是查询内容,qsr是查询类型,herb_name表示按中药名检索。返回的是 HTML 页面,里面嵌着一张成分表,字段包括 Mol ID、分子量、OB、DL、HBD、HBA、LogP 等。实际工作中我不太建议直接解析 HTML,更稳的做法是在页面上手动筛选下载 CSV。

参数里有三个最关键的筛选阀值:OB(口服生物利用度)≥ 30%,DL(类药性)≥ 0.18,这是网络药理学文章里默认的筛选标准。有些文章会用 OB ≥ 30% 且 DL ≥ 0.18,也有用 OB ≥ 20% 的,但 TCMSP 官方推荐和大部分文献默认是 30 和 0.18。你如果做创新药筛选可以把阈值拉高到 40/0.25,做机制验证就用默认值,不然成分太少后面没法做网络。

2.2 成分 CSV 的下载与预处理

TCMSP 页面右上角有导出按钮,可以下载成分表的 CSV。这个 CSV 是半结构化数据,列名是中文或英文混排,读进 R 之前要先人工检查一遍。

读入 R 之后的清洗我一般这么写:

# 读取 TCMSP 下载的成分表 herb_csv <- read.csv("黄连_成分.csv", fileEncoding = "GBK", stringsAsFactors = FALSE) # 按 OB 和 DL 筛选活性成分 act_filter <- subset(herb_csv, OB >= 30 & DL >= 0.18) cat("筛选后剩余成分数:", nrow(act_filter), "\n") # 提取 Mol ID 列表,后面拿这个去查靶点 mol_ids <- act_filter$Mol.ID writeLines(mol_ids, "active_mol_ids.txt")

fileEncoding="GBK"是因为 TCMSP 导出的 CSV 是 GBK 编码,直接用read.csv读会乱码。OB >= 30 & DL >= 0.18是双条件同时满足,不是或的关系。writeLines把活性成分的 Mol ID 存成纯文本,下一步靶点获取要用。这里有个容易踩的细节:CSV 里的Mol ID列名可能带空格或不可见字符,读取后先names(herb_csv)确认列名再引用。

2.3 靶点获取的两种方式和推荐路径

活性成分确定后,需要拿 Mol ID 去 TCMSP 查对应靶点。TCMSP 的靶点数据在成分详情页里,每个 Mol ID 会列出它作用的 protein target。常见做法有两种:一是用 TCMSP 网页手动逐个复制,二是用脚本遍历 Mol ID 请求靶点接口。我推荐后者,但你得先确认 TCMSP 当前是否要求登录——这个问题在避坑章节细说,这里先给脚本方案。

# 遍历 Mol ID 获取靶点(适合 TCMSP 未强制登录时) library(httr) library(jsonlite) mol_list <- readLines("active_mol_ids.txt") target_list <- list() for (mid in mol_list) { url <- paste0("https://old.tcmsp-e.com/tcmspsearch.php?qr=", mid, "&qsr=mol_id&token=xxxx") res <- tryCatch(GET(url, timeout(20)), error = function(e) NULL) if (is.null(res)) next # 解析返回的靶点表,这里假设返回 JSON parsed <- tryCatch(fromJSON(content(res, "text", encoding = "UTF-8")), error = function(e) NULL) if (!is.null(parsed) && length(parsed) > 0) { target_list[[mid]] <- parsed$target_name } Sys.sleep(1) # 礼貌访问,别把 TCMSP 打挂了 } target_df <- stack(target_list) names(target_df) <- c("target", "mol_id") write.csv(target_df, "targets_raw.csv", row.names = FALSE)

timeout(20)防止某个请求卡死整个循环,Sys.sleep(1)做请求间隔,这是批量抓取的基本礼仪。fromJSON假设接口返回 JSON,如果 TCMSP 改版返回 HTML,这段就要换成rvest::html_table()解析。解析失败时tryCatch会返回NULL,循环继续跑,不会中断。

这里强调一句:如果 TCMSP 当前版本要求登录且做了人机验证,上面的脚本大概率拿不到数据。我的处理习惯是——先看视频里演示的是哪个版本的页面,再决定用脚本还是手动导出。视频里如果带的是新版页面,就把脚本当成备用方案,优先走手动下载。

3. 靶点名称标准化与 PPI 网络构建:避开 UniProt 的暗坑

3.1 从靶点名到标准 Gene Symbol

TCMSP 返回的靶点名通常是 protein name,比如「Prostaglandin G/H synthase 2」,这不是基因名。做网络药理学的标准动作是把它映射到 UniProt 的 Gene Symbol(比如 PTGS2)。这一步不做,后续 STRING 和富集分析全都会卡住。

TCMSP 页面里其实带了一个Gene Symbol字段,但很多情况下是空的或者对应的是旧 ID,我一般会拿 target name 去 UniProt 批量检索。

# 用 UniProt ID mapping API 做靶点标准化 library(httr) target_names <- unique(target_df$target) map_results <- c() for (tn in target_names) { query_url <- paste0("https://rest.uniprot.org/uniprotkb/search?query=", URLencode(paste0("protein_name:", tn)), "&fields=gene_primary&format=tsv") res <- GET(query_url, timeout(30)) if (status_code(res) == 200) { tsv_text <- content(res, "text", encoding = "UTF-8") lines <- strsplit(tsv_text, "\n")[[1]] if (length(lines) > 1) { gene_sym <- strsplit(lines[2], "\t")[[1]][1] map_results <- c(map_results, gene_sym) } else { map_results <- c(map_results, NA) } } else { map_results <- c(map_results, NA) } Sys.sleep(0.5) } target_df$gene_symbol <- map_results[match(target_df$target, target_names)]

这里有个细节:UniProt 检索protein_name:时要加URLencode,否则蛋白名里的空格和冒号会导致 400 错误。fields=gene_primary只要基因主名,避免返回多个别名。映射不上的是因为 TCMSP 的 target name 和 UniProt 的 protein name 不完全一致,比如带亚基描述或物种限定词。映射不上的别硬删,先用别名再查一轮,实在没有就标 NA,后续分析时会自动忽略。

3.2 STRING 网络构建与 TSV 导出

靶点基因标准化后,下一步是构建 PPI 网络。标准工具是 STRING 数据库,把基因列表粘贴到 STRING 的 «Multiple Proteins» 页面,选择物种 Homo sapiens,检索后导出 TSV。

关键参数设置是:confidence score 选 0.400(中等置信度),这个值最常用,网络不会太稀疏也不会太乱。meaning of network edges 选 confidence,这样边的粗细代表置信度。导出时勾选 «second shell» 的 no more than 5 interactors,不然网络会膨胀到没法看。

导出 TSV 后读入 R,我习惯转换成 edge list 格式:

# STRING 导出 TSV 转 edge list string_tsv <- read.table("string_interactions.tsv", header = TRUE, sep = "\t", quote = "") # string_tsv 的 node1 和 node2 是 Ensembl ID,先映射回 gene symbol # 这里假设你已经用 bitr() 转换过了,直接用转换后的结果 edges <- string_tsv[, c("node1_symbol", "node2_symbol", "combined_score")] # combined_score 是 0-1000 的整数值,一般按 >400 过滤 edges <- subset(edges, combined_score >= 400) write.csv(edges, "ppi_edges.csv", row.names = FALSE)

combined_score >= 400对应 STRING 网页上 0.4 的置信度阈值,800 对应 0.8。做核心网络用 700 以上,做全貌用 400。导出 TSV 的时候注意勾选 «displayed data» 而不是全量数据,不然文件里多出很多无关列。

3.3 Cytoscape 出图与节点布局

拿到 edge list 以后,Cytoscape 里 Import Network from File 直接拖进去就能成图。我一般会再算一遍 degree 值,用 degree 映射节点大小,用 combined_score 映射边的透明度。布局用 force-directed 的预设,跑一遍后手动调几轮,把离群节点拉回来。

这里有个效率技巧:Cytoscape 每次手动调布局很费时间,你可以用 R 的RCy3包批量控制 Cytoscape 出图。但视频里演示的通常是纯手动路径,因为手动调整的空间更大;脚本出图适合做批量复方对比时用。

4. 功能富集分析:GO 与 KEGG 的落地实操

4.1 clusterProfiler 的 ORA 分析

PPI 网络建好之后,常规套路是把网络里的核心基因拿出来做 GO 和 KEGG 富集。这里用clusterProfiler做 ORA(过表达分析),不是 GSEA。ORA 适合基因数量在几十到几百的场景,GSEA 需要表达矩阵,网络药理学场景下基本用不到 GSEA。

library(clusterProfiler) library(org.Hs.eg.db) # 核心基因列表,从 PPI 网络里按 degree 取 top 50 core_genes <- readLines("core_genes.txt") # ORA 分析:GO 生物学过程 go_ora <- enrichGO(gene = core_genes, OrgDb = org.Hs.eg.db, keyType = "SYMBOL", ont = "BP", pAdjustMethod = "BH", pvalueCutoff = 0.05, qvalueCutoff = 0.05, readable = FALSE) head(go_ora@result[, c("ID", "Description", "pvalue", "p.adjust", "Count")])

keyType="SYMBOL"表示输入的是基因符号。如果你的输入是 Entrez ID,这里要改成ENTREZID。ont="BP"选生物学过程,也可以换成CC或MF,跑全量的话把ont参数设为"ALL",但结果会很长,阅读不友好。pAdjustMethod="BH"是 Benjamini-Hochberg 校正,网络药理学文章的标配,别选bonferroni,太严格会把结果压没了。

readable=FALSE是因为输入已经是 SYMBOL,不需要再转换。如果你输入的 Entrez ID,这里要设readable=TRUE把 ID 显示成基因名。

4.2 KEGG 富集与通路可视化

KEGG 富集和 GO 几乎一样,区别是数据库不同。clusterProfiler的enrichKEGG函数需要联网访问 KEGG API,网络不稳定时会失败,建议设置镜像或多次重试。

# KEGG 通路富集 kegg_ora <- enrichKEGG(gene = core_genes, organism = "hsa", keyType = "kegg", pvalueCutoff = 0.05, qvalueCutoff = 0.05, use_internal_data = FALSE) # 看前 10 条显著通路 kegg_result <- as.data.frame(kegg_ora) head(kegg_result[order(kegg_result$p.adjust), ][1:10, c("ID", "Description", "p.adjust", "Count")])

organism="hsa"是人类,别的物种要改成对应的 KEGG 三字母缩写,比如小鼠是mmu,大鼠是rno。use_internal_data=FALSE表示从 KEGG 在线 API 取数据,如果设成TRUE会用本地缓存的 KEGG 数据,但那个数据更新不一定及时。keyType="kegg"是 KEGG 自己的基因 ID,如果你的核心基因是 SYMBOL,先用bitr()转成 Entrez ID 再传进来:

# SYMBOL 转 Entrez ID conv <- bitr(core_genes, fromType = "SYMBOL", toType = "ENTREZID", OrgDb = org.Hs.eg.db) kegg_ora2 <- enrichKEGG(gene = conv$ENTREZID, organism = "hsa", pvalueCutoff = 0.05)

bitr转换会丢失匹配不上的基因,转换后看看conv的行数,如果丢太多回去查基因名拼写。

4.3 富集结果的可视化与解读

富集结果的图一般三件套:气泡图(dotplot)、条形图(barplot)、通路网络图(cnetplot)。clusterProfiler自带绘图函数,直接传对象就行。

# 气泡图:横轴是 GeneRatio,纵轴是通路名,点大小是基因数,颜色是 p.adjust dotplot(kegg_ora, showCategory = 15, font.size = 10) ggsave("kegg_dotplot.png", width = 8, height = 6, dpi = 300) # cnetplot:展示基因-通路连接关系 cnetplot(kegg_ora, showCategory = 5, categorySize = "pvalue")

showCategory=15控制显示的条目数,不是越多越好,15 条以内读者能一眼看到主要富集结果。font.size=10是防止通路名太长互相遮挡。cnetplot 的categorySize="pvalue"让节点大小反映显著性,如果图太密,把showCategory降到 3 或者把边缘模糊关掉。

富集结果解读是很多人的知识盲区:不要照着 p 值最小的通路逐条念,核心是看通路之间的关联模式——比如多个条目都指向炎症反应,那结论就是该复方可能通过抗炎通路起效。这条逻辑要写进文章讨论部分,不是罗列表格。

5. 避坑与常见问题:TCMSP 网络药理学最容易翻车的五个点

5.1 TCMSP 强制登录导致脚本失效

现象:脚本批量请求 TCMSP 接口时返回 302 重定向或验证码页面,解析不到任何靶点数据。

原因:TCMSP 新版加强了访问控制,需要登录才能查看靶点,部分接口还加了 JS 人机验证。旧版old.tcmsp-e.com的接口保持兼容,但不是所有数据都能通过脚本拿全。

解决:优先走视频里演示的路径——先手动登录,在网页端筛选和导出 CSV。脚本方案保留在本地,但只用于 TCMSP 开放接口还正常时。登录后的 session 如果要用脚本维持,可以在浏览器开发者工具里复制 Cookie 到httr::set_cookies(),但改版频繁,不建议长期依赖。

5.2 UniProt 映射大量失败,基因列表少了一半

现象:TCMSP 的 target name 拿去查 UniProt,三分之一查不到 Gene Symbol。

原因:TCMSP 的靶点数据是早年整理的,蛋白名包含旧名、别名或带物种注释(如 "human")。UniProt 搜索对精确匹配要求高,蛋白名的空格和特殊字符会影响查询结果。

解决:换检索字段,把protein_name:换成protein_name:"..."精确短语搜索;或者先用 TCMSP 页面自带的 Gene Symbol 字段,缺失的再用 UniProt 补。别名映射问题可以用org.Hs.eg.db的mapIds()做二次匹配,能捞回来不少。

5.3 STRING 导出 TSV 后基因名对不上

现象:STRING 导出的 TSV 里 node1 和 node2 列是 Ensembl ID(如 ENSG0000012),和你输入的 gene symbol 不一致。

原因:STRING 默认以 Ensembl ID 作为内部标识,即使输入的是 gene symbol,导出时仍可能显示为 Ensembl ID。

解决:在 STRING 页面导出 TSV 时,勾选 «Export as tabular» 的下拉选项里选 gene symbol 版本,或者导出后用bitr()把 Ensembl ID 映射回 SYMBOL。我一般用后者,因为bitr()的结果可以直接用于后续分析。如果是stringdb的 R 包导出,调用get_edges()后手动指定id_type="gene_symbol"。

5.4 富集分析结果 p 值全为 1

现象:enrichGO跑完,所有条目 pvalue 都是 1 或接近 1,没有任何显著富集。

原因:多数时候是基因列表太短,或者基因列表里混入了大量非编码基因和假基因,导致背景集和基因集重叠率过高。也有可能是keyType传错了,比如传了 SYMBOL 但设置了ENTREZID,全部匹配失败。

解决:检查core_genes里基因名是否为标准 SYMBOL 写法,比如EGFR不能写成Egfr。然后用bitr()做一次校验,看转换成功的比例。如果基因数少于 20,富集分析没有统计学意义,建议回到 PPI 网络,扩大置信度阈值把更多节点纳入核心基因集合,或者改用超几何检验手算。

5.5 TCMSP 下载的 CSV 用 R 打开乱码

现象:read.csv("xxx.csv")打开后,中文列名变成乱码或问号。

原因:TCMSP 导出 CSV 的编码是 GBK / GB18030,R 默认按 UTF-8 读取,必然乱码。Windows 下 R 4.0 之后的read.csv默认fileEncoding="",不会自动识别 GBK。

解决:read.csv加上fileEncoding="GBK"或"GB18030"。如果你已经读进来且乱码了,用iconv(text, "GBK", "UTF-8")重新编码。Mac 和 Linux 上 R 对 GBK 支持稍差,必要时先在 Excel 里另存为 UTF-8 CSV 再读。

这五条是我复现时实际撞过的墙,前两条影响数据完整性,后三条影响分析结果,每一条都能卡住半天以上。视频里有几条已经讲过,但我更建议你把上面五条存成一个 checklist,每次跑新复方时先过一遍。

6. 从跑通到交付:结果验证、批量备图与交付清单

一套网络药理学跑通和跑好之间还差一个验收集。我自己的习惯是,任何复方分析都要经过以下三个验证才算交付。

第一步是结果合理性验证。富集到的通路里必须有 1 到 2 条与复方主治疾病强相关的通路,否则前面数据可能就有问题。比如分析黄连解毒汤,结果里没有炎症相关通路和氧化应激条目,那大概率是靶点映射阶段出错了。验证方法是:随便抽 5 个核心基因,去 PubMed 上查它们与目标疾病的关联文献,关联度低就得回头查基因映射。

第二步是图表参数的统一。网络药理学文章通常要拼多张图,单张图配色、字号、分辨率要一致。导图时我统一用dpi=300、字号不小于 8pt、图片宽度统一 8 英寸。以下是交付文件的最小集合:

文件内容格式
活性成分表OB≥30% 且 DL≥0.18 的成分列表CSV
靶点映射表TCMSP 靶点与 Gene Symbol 映射CSV
PPI edge listSTRING 导出的置信度≥0.4 的边CSV
GO BP 富集表校正后 p<0.05 的条目CSV
KEGG 富集表通路名、校正 p 值、基因数CSV
核心网络图Cytoscape 导出 PNGPNG
富集气泡图关键通路 dotplotPNG

文件命名我建议统一用复方名_数据类型.ext的格式,比如huanglian_tcmsp_components.csv,一方面自己能分清,另一方面投稿时审稿人看起来也专业。

第三步是代码环境的留档。R 包的版本差异经常导致结果对不上,交付时我会在 R 里跑一次sessionInfo(),把输出存成session_info.txt一并附上。这个动作很多教程不会教你,但对复现至关重要——三个月后再回来看自己的脚本,没有版本记录等于给未来挖坑。

拆完这套资料,我最大的感受是:TCMSP 网络药理学不是一个黑匣子,它是一套有固定节奏的流水线。数据获取、ID 标准化、网络构建、富集分析、交付成图,每一段都有标准动作和对应坑位。从那以后我每次拿到新复方,都强制自己走一遍「先下载 CSV → 校验基因名 → 跑 PPI → 看富集 → 存 sessionInfo」的完整闭环,宁可慢半小时,也不在投稿前夜返工。这套资料里的视频和代码给我省掉的不是学习时间,而是和 TCMSP 斗智斗勇的暗坑时间。希望帮到你——少踩一个坑,就多一篇论文的时间。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进