第2章 药物数据资源:公共数据库的使用

2.1 三大数据库,我拿来做什么

做AI药物发现,数据就是燃料。巧妇难为无米之炊,没有高质量的结构化数据,你模型再花哨也白搭。我个人习惯把公共数据库分成三类:ChEMBL管活性,DrugBank管成药,PubChem管化合物。听起来简单,但实际用起来坑不少。

我刚开始接触这个领域时,以为随便爬一个库就能训模型。结果呢?IC50和Ki混在一起,单位有的是nM有的是μM,一个批次下来数据全是乱的。后来学乖了,先摸清每个库的脾气。

我的经验:前期花1天做数据源调研,后面能省10天清洗时间。别急于撸代码。

2.2 ChEMBL:活性数据的金标准

ChEMBL由欧洲生物信息学研究所维护,收录了从文献中人工提取的小分子-靶点亲和力数据。说白了,它是目前最干净的活性数据集之一。

  • 核心内容:化合物结构、靶点ID、活性值(IC50 / Ki / Kd / EC50)、实验条件
  • 数据特点:人工校验,质量高,但更新较慢
  • 访问方式:Web界面、RESTful API、Python包chembl_webresource_client

我个人用得最多的操作就是按靶点名拉取所有活性数据。下面这段代码我在三个项目里都复用过了:

from chembl_webresource_client.new_client import new_client

target = new_client.target
target_name = "Serotonin transporter"
targets = target.filter(pref_name__icontains=target_name)

activity = new_client.activity
if targets:
    target_id = targets[0]['target_chembl_id']
    res = activity.filter(target_chembl_id=target_id)
    print(f"Get {len(res)} activities")
    for r in res[:3]:
        print(r['molecule_chembl_id'], r['standard_type'], r['standard_value'])
注意:返回的数据中standard_type可能是IC50、Ki或EC50。同一个靶点可能混用多种类型,建议只保留一种。我一般统一用IC50,单位全转成nM。

2.3 DrugBank:从分子到药物

DrugBank是个宝藏。它收录了FDA批准的药物以及临床试验中的候选药物,不光有靶点,还有药代动力学、相互作用、通路信息。做虚拟筛选或ADMET预测时,它经常被我当正样本库用。

字段内容我的用法
Drug IDDB开头的唯一标识关联外部数据
靶点列表靶点名称 + Uniprot ID + 作用类型构建靶点-药物二分图
SMILES2D结构输入分子指纹/图模型
LogP / MW / HBD理化性质基于规则的类药性过滤

要注意的是,DrugBank的完整数据需要申请学术许可才能下载XML/JSON。没许可时可以在Web上搜索,但批量抓取要遵守robots.txt。

我曾经踩过的坑:直接拿DrugBank里所有药物当正样本,但其中有些是诊断试剂或保健品,结构根本不满足类药五原则。后来我加了过滤:只保留评分≥5且分子量在200-600之间的Drug小分子。

2.4 PubChem:海量化合物目录

PubChem由美国NIH管理,覆盖1亿+化合物,包括从供应商采购、文献提取和用户提交的数据。它很适合做负样本库,或者用来补充ChEMBL没有覆盖的化合物空间。

  • 三大子库:Substance(提交物)、Compound(标准化后)、BioAssay(生物实验)
  • 我最常用:通过PCID or CID和SMILES之间的转换,以及BioAssay数据
  • API:Power User Gateway (PUG) 支持REST和SOAP

下面是从PubChem批量获取SMILES的简洁写法:

import requests

cid_list = ["2244", "3676", "5311"]  # 阿司匹林、布洛芬、对乙酰氨基酚
base_url = "https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/{cid}/property/MolecularFormula,MolecularWeight,CanonicalSMILES/JSON"

for cid in cid_list:
    r = requests.get(base_url.format(cid=cid))
    if r.status_code == 200:
        data = r.json()
        props = data['PropertyTable']['Properties'][0]
        print(cid, props['MolecularFormula'], props['CanonicalSMILES'])
实用技巧:PubChem的REST API有速率限制(约每秒5次),异步请求时记得加sleep。我在一个虚拟筛选项目里并发请求被限,折腾半小时才跑完。加上time.sleep(0.2)后稳如老狗。

2.5 如何选择与组合?

你可能会问:三个库看着重叠,到底用哪个?我的经验是这样的:

场景推荐数据源理由
构建活性预测模型ChEMBL活性值标准化程度高
药物-靶点相互作用网络DrugBank + ChEMBLDrugBank有获批标签,ChEMBL有活性值
大规模负样本采样PubChem化合物空间大,且可关联BioAssay的无效结果
ADMET预测训练DrugBank + PubChemDrugBank有体内数据,PubChem有体外

组合的时候要注意去重。不同库对同一化合物的描述可能略有差异——比如阿司匹林的CAS号、SMILES、InChI都一致,但Chembl ID和PubChem CID不同。我个人习惯先用InChI或标准SMILES做统一标识符。

药物数据资源核心逻辑图 ChEMBL DrugBank PubChem 人工校验活性值 IC50 / Ki / Kd FDA药物+靶点通路 ADMET / 相互作用 亿级化合物目录 BioAssay + 供应商 日常Pipeline组合策略 活性预测 → ChEMBL优先;靶点网络 → DrugBank+ChEMBL;负样本 → PubChem

2.6 数据获取 pipelines 实战

光说理论不过瘾,我直接给个能跑通的流程。假设你要做某个靶点(比如EGFR)的活性预测模型,你可以这样搭:

  1. 从ChEMBL拉EGFR的活性数据:只保留IC50(nM),去除重复分子。
  2. 从DrugBank拿已知的EGFR抑制剂做正样本增强:虽然ChEMBL里也有,但DrugBank有获批状态标记。
  3. 从PubChem随机选一批结构不同的化合物做负样本:注意排除在ChEMBL里已标注有活性的。
  4. 统一用标准SMILES去重:用RDKit的MolFromSmiles + MolToSmiles标准化。

下面是整合三类API的伪代码框架:

import pandas as pd
from chembl_webresource_client.new_client import new_client
import requests
from rdkit import Chem

def fetch_chembl(target_name, activity_type='IC50'):
    acts = new_client.activity
    targs = new_client.target
    t = targs.filter(pref_name__icontains=target_name)
    if not t: return []
    tid = t[0]['target_chembl_id']
    res = acts.filter(target_chembl_id=tid, standard_type=activity_type)
    return [(r['molecule_chembl_id'], r['standard_value'], r['standard_units']) for r in res]

def fetch_drugbank_by_target(target_name):  
    # 模拟:实际需通过XML或官方API
    # 这里展示数据结构
    pass

def pubchem_random_negative(count=1000):
    # 随机抽取PubChem CID
    # 用PUG REST轮训
    pass

# 主流程
chembl_egfr = fetch_chembl('EGFR')
smiles_standard = []
for chembl_id, val, unit in chembl_egfr:
    mol = Chem.MolFromSmiles(some_func_to_get_smiles(chembl_id))
    if mol:
        smiles_standard.append(Chem.MolToSmiles(mol))
核心思路:不要把三个库的数据直接拼接,应该以ChEMBL为主干,DrugBank和PubChem做补充和验证。我见过有人直接把三个库的CSV合并训模型,结果是过拟合到PubChem噪音上,准确率虚高。

2.7 避坑指南(我摔过的跤)

  • 曾有一次,我从DrugBank下载XML时没注意版本号,结果解析字段全是旧标签,白白浪费一整天。建议每次使用前先看官方Changelog。
  • PubChem的Substance和Compound傻傻分不清。Substance是原始提交物,可能包含多个副本;Compound是标准化后的唯一结构。建模一定用Compound,别问我怎么知道的。
  • ChEMBL的unit字段经常是nM,但也有μM甚至pM(很少)。做回归任务前务必统一转换。我写了段小函数,见下面的check:
def normalize_to_nm(value, unit):
    unit = unit.strip().lower()
    if unit in ['nm', 'nanomolar']:
        return float(value)
    elif unit in ['μm', 'micromolar', 'um']:
        return float(value) * 1000
    elif unit in ['mm', 'millimolar']:
        return float(value) * 1_000_000
    else:
        raise ValueError(f"Unknown unit: {unit}")

记住:数据无小事。你训练集里一个nM被当成μM,模型在临床上可能推荐一个无效分子,那可不是闹着玩的。

小心license:ChEMBL和PubChem是开放数据,DrugBank完整版需授权。商业项目里别直接拿DrugBank XML发论文或做产品,法律风险挺大的。如果只是做学术原型,用Web查询不多次下载是没问题的。

2.8 本章小结

这个章节我讲了不少实操层面的东西,其实核心就三句话:ChEMBL是活性主力,DrugBank是成药参考,PubChem是大海捞针。这三个库的API都不难调,难的是数据清洗和去重。后面章节我们会聊到RDKit处理分子结构,以及怎么把这些数据喂进图神经网络。现在先把数据源搭好,磨刀不误砍柴工。

嗯,记住我前面说的取数流程,动手写个demo跑一遍。代码是练会的,不是看会的。