数据源调研 — 摸清家底才能干活

做知识图谱,第一件事不是写代码,是搞清楚数据从哪来。我个人习惯先把所有可能用的数据源列出来,然后一个一个试,看看质量、更新频率、接口好不好用。说实话,这一步被很多人跳过,结果后面清洗到一半发现字段对不上、缺数据,整个重来。

这一章我们就聊聊常用的药品数据库、临床数据、以及文献全文。你想想看,这些来源的特点完全不同,融合的时候必须心里有数。

为什么数据源调研这么重要

我在项目里见过最惨的一次:团队花了三个月写代码,把 DrugBank 和 PubChem 的数据合并到一张表里,结果发现 PubChem 里化合物的 SDF 结构字段在 DrugBank 里根本不存在,而且两者对“药物靶点”的定义不一样。为啥?因为没提前调研数据模型。

说白了,调研阶段就是给你自己打预防针。知道哪个字段可能缺失、哪个接口有速率限制、哪个数据需要处理同义词,后面做清洗就能少走弯路。

四大类数据源一图览

下面这个图是我自己画的数据源调研框架,每次做新项目都会先对着它过一遍。

数据源调研整体框架 药品数据库 临床数据 文献全文数据 知识库/词典 DrugBank PubChem CTD EHR 临床试验注册 真实世界数据 PubMed PMC 全文PDF解析 UMLS SNOMED CT 医学词典 数据清洗与融合 实体对齐 · 属性合并 · 冲突解决 药物知识图谱
这个图我放在项目白板上贴了两年,每次新同学问数据怎么来的,直接指着图讲一遍。

药品数据库三巨头

对做药物图谱来说,DrugBank、PubChem 和 CTD 是绕不开的三个库。我一个个说。

DrugBank — 药物领域的维基百科

DrugBank 是目前最权威的药物数据库之一,不仅包含药物分子信息,还有靶点、通路、给药途径、副作用等。我个人特别喜欢它的靶点-药物关联,清洗时可以直接拿来当标准正例。

它的 XML 导出文件结构很清晰,我一般是先解析成表再入库。核心字段大概长这样:

字段说明示例
drugbank-id唯一标识DB00001
name药物名称Leuprolide
type类型(small_molecule / biotech)biotech
targets靶点列表(JSON)[{"id":"BE0001","name":"GNRHR"}]
cpd计算化学性质{"logP":3.2,"mw":500.6}
注意:DrugBank 允许学术免费下载,但商业使用需要付费。我们内部项目用学术版,字段完全一样。

PubChem — 化合物宇宙

PubChem 是老大哥,化合物数量超过 1 亿。它的 REST API 很好用,我经常直接写脚本调取。

举个例子,查阿司匹林的 CID:

curl -X GET "https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/name/aspirin/property/MolecularFormula,MolecularWeight,InChIKey/JSON"

返回的 JSON 干净省心:

{
  "PropertyTable": {
    "Properties": [
      {
        "CID": 2244,
        "MolecularFormula": "C9H8O4",
        "MolecularWeight": 180.16,
        "InChIKey": "BSYNRYMUTXBXSQ-UHFFFAOYSA-N"
      }
    ]
  }
}

我在项目里用 PubChem 做药物成分标准化,因为它覆盖全,而且有标准 InChIKey,对齐起来特别准。不过要注意 API 有速率限制,爬大量数据时记得加延时。

CTD — 化学物-基因-疾病的三角关系

CTD (Comparative Toxicogenomics Database) 的核心价值在于它把化学物、基因和疾病三者的关联都整理好了。说白了,你想知道“阿司匹林影响哪个基因,这个基因又和什么病有关”,CTD 直接给你表。

它的数据以 TSV 形式提供,下载后直接导入数据库。字段包括 ChemicalName、GeneSymbol、DiseaseName、ReferenceCount 等。我遇到过一个问题:CTD 里的化学名不是标准名,需要和 PubChem 做映射。嗯,这又是另一道清洗工序。

临床数据 — 真实世界的金矿

药品数据库再全,也只是体外表征。真正能反映药物效果和副作用的是临床数据。包括电子病历(EHR)、临床试验结果、以及真实世界数据(RWD)。

但临床数据有个老大难问题:隐私。我曾在一个项目中尝试爬取公开的临床试验结果(ClinicalTrials.gov),发现里面虽然脱敏了,但字段非常稀疏,很多试验只报了顶线结果,没有个体级数据。这时我通常会结合文献全文来补细节。

另外,电子病历如果拿不到结构化数据,就只能靠 NLP 从文本中抽。我之前用过一个开源工具 MedSpacy,效果还不错,但速度慢。一般来说,临床数据我只在内部项目用,对外发布的图谱很少直接用 EHR,因为合规风险高。

文献全文数据 — 大海捞针

文献全文是知识图谱的“增量知识源”。新发现的药物-靶点关系、不良反应报道、老药新用,通常先出现在论文里。

常用来源:

  • PubMed:摘要免费,全文不一定。我会用 Entrez API 批量拉取 PMID 和摘要。
  • PMC:开放获取全文库,可以直接下载 XML 格式,解析后做 NER。
  • 预印本:如 medRxiv、bioRxiv,信息更新更快但质量参差不齐。
我曾经从 PMC 的 XML 里解析出了 200 多篇文献的全文,然后用 BERN 做实体识别,抽出了 3000 多条新的药物-疾病关联,准确率大概 80%。这比纯靠数据库更新快了一个季度。

但全文数据噪音大,图表里的描述词、参考文献列表需要过滤。我一般先用句子边界检测切分,然后只拿包含药物名称的句子喂给关系抽取模型。

数据源选择策略

当你面对多个数据源,怎么选?我做了个对照表,每次调研时直接套用:

数据源覆盖范围更新频率接口限制推荐用途
DrugBank~15k 药物,~5k 靶点每年 2-3 次学术免费下载,无速率限制药物-靶点标准关系
PubChem>1亿 化合物每日更新5次/秒化合物属性、结构对齐
CTD~2万 化学物,~7万 基因每月更新TSV下载无限制化学-基因-疾病三角关联
ClinicalTrials.gov~50万 试验每周更新REST API 无限制但请求量大限药物-不良反应、试验结果
PubMed/PMC~3500万 摘要,~800万 全文每日更新Entrez API 3次/秒新发现、关系抽取

我自己做项目时,首选 DrugBank + PubChem 作为骨架,再视场景补充 CTD 或临床数据。文献全文一般只在做前沿挖掘时加进去。

避坑指南 — 我踩过的那些坑

  • ID 不通用:DrugBank ID 和 PubChem CID 和 CHEBI ID 完全不同,融合前一定要建映射表。我曾经直接拿名称做 join,结果同义词对不上,数据丢了三分之一。
  • 版本陷阱:不同时间下载的数据版本可能不同。我建议每次下载都记录日期和版本号,在融合时带上数据源版本标签。
  • 接口变化:PubChem API 在 2022 年改过一次返回格式,老脚本直接崩溃。定期检查接口文档,或者给我自己写的爬虫加监控。
  • 数据重复:同一个药物可能在多个来源出现,但名称写法不同(比如“Aspirin” vs “Acetylsalicylic acid”)。不处理重复,图谱就乱。我习惯用 InChIKey 作为第一候选去重字段。
  • 许可证问题:前面提到了,DrugBank 商业版要钱,CTD 是 CC BY 许可证。先看清条款再开工,不然后面发不出论文。
最后分享一个习惯:每次接到新数据集,我第一时间跑一个统计脚本,看看空值比例、唯一值个数、字段长度分布。这个脚本我写了模板,以后可以复用。