4. COVID-19相关药物数据源介绍:DrugBank、PubMed、ClinicalTrials

做知识图谱,数据源就是你的“弹药库”。弹药质量决定了下游能打出什么样的子弹。这一节,我把构建COVID-19药物知识图谱时,最常用的三种数据源梳理一遍。

4.1 数据源概述与选择取舍

先说结论:没有哪个数据源是万能的。DrugBank擅长大分子药理,PubMed是文献海洋,ClinicalTrials则聚焦临床试验。我习惯把它们组合起来用,形成一条数据采集流水线。

下表罗列了三者的核心维度对比:

数据源 数据类型 更新频率 获取方式 主要用途
DrugBank 结构化药物-靶点关系 约每季度 API / XML 下载 药物实体、靶点关系、ADMET
PubMed 文献元数据 & 摘要 每日 NCBI E-utilities 文本挖掘、关系抽取、证据溯源
ClinicalTrials 临床试验方案 & 结果 每周 AACT 数据库 / API 药物与疾病干预实验验证

你想想看,如果一个药物在DrugBank里有明确的靶点,在ClinicalTrials里有正在进行的临床试验,同时还有PubMed文献支撑其作用机制——那这个关系就非常可信了。在项目中我称之为“三源证据链”。

4.2 DrugBank:结构化药物知识的首选

DrugBank是我做药物KG时的起点。它本质上是一个手工审核的、结构化的药物-靶点数据库。对于COVID-19药物来说,它包含的信息非常规整。

4.2.1 数据特征

  • 药物实体:药物名称、同义词、CAS号、UNII标识符
  • 靶点关系:靶点名称、基因符号、UniProt ID、作用类型
  • 关键字段:type(small molecule / biotech), mechanism-of-action, category

我个人习惯直接下载XML dump做批量解析,而不是每次都调API。下面这个命令是我经常用的,用来提取所有COVID-19相关的药物条目:

# 下载DrugBank XML (需要注册获取API key)
wget --user=xxx --password=xxx https://go.drugbank.com/releases/latest/full.xml.gz
gunzip full.xml.gz

# 用xmlstarlet提取药物通用名和靶点名称(简化版)
xmlstarlet sel -t -v "//drugbank:drug[drugbank:categories/drugbank:category/@term='COVID-19']/drugbank:name" full.xml | head -20

4.2.2 在实际项目中的避坑

我曾经在解析DrugBank时踩过一个坑:它的小分子药物和生物药使用的是两套不同的XML schema。小分子药的靶点放在<targets>下,而生物药的靶点可能嵌套在<polypeptide>里。如果你直接用XPath一杆子打到底,会漏掉大量关系。嗯,这里一定要做分支处理。

经验提示:解析要分 type 走两路。小分子走 drugbank:targets/drugbank:target,生物药走 drugbank:drugbank-polypeptide 下的 target 引用。

4.3 ClinicalTrials:真实世界的临床证据

如果说DrugBank告诉你能不能结合,ClinicalTrials就告诉你在人身上到底管不管用。这一步我在构建COVID-19知识图谱时特别看重,因为很多老药是在临床试验中才被发现有效的。

4.3.1 查询策略

我一般不会去爬全量数据,那太大了。通常的做法是,先用API按“COVID-19”作为Condition查询:

# 查询所有COVID-19相关的干预性临床试验 (JSON格式)
# 使用ClinicalTrials.gov API v2
curl "https://clinicaltrials.gov/api/query/study_fields?expr=COVID-19&fields=NCTId,BriefTitle,Condition,InterventionName,Phase,OverallStatus&min_rnk=1&max_rnk=100&fmt=json"

# 用jq提取药物干预列表
curl -s "https://clinicaltrials.gov/api/query/study_fields?expr=COVID-19&fields=InterventionName&fmt=json" | jq '.StudyFieldsResponse.StudyFields[] | .InterventionName[]'

返回的数据里,InterventionName字段经常会混入“Drug: Remdesivir”这样的格式。你需要做一次正则清洗才能映射到DrugBank的药物ID。这部分工作量很大,逃不掉的。

4.3.2 关键字段解析

字段 说明 在KG中的用途
NCTId 试验唯一标识 作为“临床试验”节点的ID
Phase Phase 1/2/3/4 指示证据级别
OverallStatus Completed / Recruiting 指示活性状态
InterventionName 药物干预名称 映射到药物节点
Condition 疾病名称 映射到疾病节点

4.4 PubMed:非结构化证据的富矿

最后聊PubMed。说实话,这是最难处理的数据源,但也是信息最丰富的。DrugBank和ClinicalTrials给的是事实,PubMed给的则是上下文和机制解释。

4.4.1 检索与获取

我习惯用NCBI的E-utilities来做批量检索。先用ESearch找到相关文献ID,再用EFetch拿摘要。下面是我常用的三步走:

# 第一步:搜索COVID-19和相关药物的文献ID
curl "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=COVID-19+AND+remdesivir&retmax=100&retmode=json"

# 第二步:获取摘要信息
curl "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id=33258446,33258445&retmode=xml&rettype=abstract"

# 第三步:解析XML,提取PMID、Title、Abstract、MeshTerms

返回的XML结构比较复杂。我建议用Python的xml.etree.ElementTree或者BeautifulSoup来解析。核心是要提取AbstractText标签下的所有段落,再按标点符号拼回完整文本。

软限制注意:NCBI API有频率限制,默认每秒3次请求。批量采集时最好在每次请求之间sleep(0.4)秒。我试过一次开10个线程并发,结果直接被封IP了。稳一点,数据总会拿到的。

4.4.2 从摘要中提取关系

这一步是文本挖掘的活。对于COVID-19药物KG,我们主要关注三种语义关系:

  • 治疗关系:文本中出现“treat COVID-19 with ...”
  • 靶点关系:文本中出现“binds to ACE2”
  • 疗效关系:文本中出现“reduced viral load”

我个人习惯的做法是先用规则匹配做一轮粗筛,再用预训练的BioBERT做精排。别一上来就上深度学习,成本太高,而且初期数据量不够的时候效果并不比规则好。

4.5 数据源整合框架图

下面这张SVG图,画的是三种数据源在知识图谱构建中的角色与数据流。你可以直观看到文本数据与结构化数据的汇合点。

知识图谱数据源整合框架 (COVID-19) DrugBank ClinicalTrials PubMed XML / API → 结构化解析 JSON → 字段映射与清洗 XML → 文本挖掘 + 关系提取 知识图谱核心节点与关系 药物节点 | 疾病节点 | 靶点节点 | 临床试验节点 COVID-19药物知识图谱 (三元组 + 证据链)

4.6 数据获取与处理的实践技巧

说到底,数据源介绍得再清楚,最后还是得落到代码上。我把自己常用的Python工具链列在下面,你可以在项目中直接复用:

  • DrugBank解析:lxml + pandas,输出药物-靶点CSV
  • ClinicalTrials批量拉取:ctg_utils (python包) 或直接请求AACT PostgreSQL dump
  • PubMed摘要提取:biopython.Entrez + xmltodict
  • 命名实体对齐:用基本字符串匹配 + 标准API映射
实用小技巧:当你需要批量对齐药物名称时,别直接用字符串精确匹配。很多数据源的名称不统一。我一般先用unidecode对药物名做一次转写,然后使用最长的公共子串做模糊匹配,最后留一个手工审核队列兜底。