4. 数据收集:公共数据库(PubChem、ChEMBL、Tox21)

做 ADMET 预测,数据是地基。地基不稳,模型再花哨也是白搭。

我个人习惯,先把三大公共数据库摸透。PubChem、ChEMBL、Tox21,这三兄弟各有脾气,用好了事半功倍。今天咱们就把它们捋一遍。

三大公共数据库结构图 公共数据库数据收集流程 PubChem 小分子活性数据 ChEMBL 药化活性数据 Tox21 毒性筛选数据 PUG REST API / FTP 化合物描述符+活性 ChEMBL Web资源客户端 靶点-化合物-活性 Tox21 CSV 下载 13个核受体/应激通路 数据预处理流水线 去重 → 标准化 SMILES → 归一化活性值 → 拆分训练/验证/测试 ADMET 预测建模数据集

4.1 PubChem:小分子数据的大超市

PubChem 是美国 NIH 维护的公共化合物数据库。说白了,它像个大超市,上亿种化合物,各种生物活性数据都能找到。

我做过一个肝毒性预测项目,一开始数据不够。后来从 PubChem 的 BioAssay 板块扒了上千条数据,模型效果直接提升了 15%。

拿数据,个人推荐两条路:

  1. PUG REST API:灵活但需要写代码。适合批量查询。
  2. FTP 下载:适合一次拉全量。巨大,能到 TB 级。

举个 API 的例子,查某个化合物的 SID 和活性:

import requests
import json

# 查询阿司匹林的 CID 对应的 BioAssay 结果
url = "https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/2244/property/MolecularFormula,MolecularWeight/JSON"
response = requests.get(url)
data = response.json()
print(data['PropertyTable']['Properties'])

返回结果里能找到分子式、分子量,进一步能关联到 BioAssay 的活性数据。嗯,这里要注意,接口有频率限制,大量请求间隔至少 0.5 秒。

小技巧:用 PubChem 的 assay ID 过滤数据。先选几个跟你预测目标相关的 assay,再批量拉化合物和活性值。这样数据质量比盲目全量下载高得多。

4.2 ChEMBL:药物化学家的首选

ChEMBL 是欧洲的数据库,主打高质量药化数据。数据来源主要是文献和专利,人工审核过,靠谱。

我记得有次做 CYP450 抑制预测,对比了 PubChem 和 ChEMBL 的数据。ChEMBL 的 IC50 值标注更规范,实验条件也记录得很详细。那个模型收敛速度快了不少。

ChEMBL 有自己的 Python 客户端,这是我最常用的方式:

from chembl_webresource_client.new_client import new_client

molecule = new_client.molecule
# 查询 阿司匹林 的 ChEMBL ID 和活性数据
results = molecule.filter(pref_name__icontains='aspirin')
for mol in results:
    print(mol['molecule_chembl_id'], mol['molecule_structures']['canonical_smiles'])

# 再查对应靶点活性
activities = new_client.activity
act = activities.filter(molecule_chembl_id='CHEMBL25')
for a in act[:5]:
    print(a['assay_description'], a['standard_value'], a['standard_units'])

客户端会自动处理分页,省事。不过千万注意,filter() 返回的是生成器,取数据前最好加个 limit 或 [:100],否则网络不稳可能会断。

避坑指南:我曾经直接 list(activities) 拉一个靶点的全部数据,结果内存涨了 8GB 直接 OOM。建议先 count 确认数据量,再分批拉取。

4.3 Tox21:毒性预测的宝藏

Tox21 是美国 EPA 发起的项目,专门测化合物毒性。数据集中有 13 个核受体和应激通路测试,全是标准化实验,复现性好。

Tox21 的数据格式比较统一,CSV 为主。下载后,字段大概是这样:

字段说明示例
SMILES化合物结构C[C@@H](O)C1=CC=CC=C1
Assay ID测试通路编号NR-AR, SR-ARE
Activity0/1 或连续值1.0
Concentration测试浓度(μM)10.0

我个人觉得,Tox21 最大的优点是数据干净。它已经帮你筛掉了很多噪音。做二分类毒性预测,用它作为基准数据集,效果很稳。

下面是加载 Tox21 数据集的简单示例:

import pandas as pd

df = pd.read_csv('tox21_p1.csv')
# 查看有哪些 assay
print(df.columns.tolist())

# 查看 NR-AR 通路的分布
print(df['NR-AR'].value_counts())

你想想看,Tox21 的数据量大概 1 万到 10 万级别,正好够做中小型模型。如果要做深度学习,可以把它作为正样本,再加其他数据库的负样本做扩充。

核心思路:PubChem 做广度覆盖,ChEMBL 做深度精细,Tox21 做毒性专攻。三个数据库互补,基本能覆盖 ADMET 预测 70% 以上的数据需求。

4.4 数据预处理:你的数据必须标准化

不管从哪个数据库拿数据,最后都要预处理。我踩过最离谱的坑就是 SMILES 标准化。

同一化合物,不同数据库可能写法不一样。比如水的 SMILES,有人写 O,有人写 [H]O[H]。不标准化,模型会把它当成两个东西。

我的标准化四步走:

  1. 去重:相同 SMILES 只保留一条,活性值取平均或中位数。
  2. 标准化 SMILES:用 RDKit 把 SMILES 统一成 Canonical 格式。
  3. 归一化活性值:IC50 pIC50 转换,或者 MinMax 缩放。
  4. 拆分数据集:按 scaffold 拆分,避免结构相似泄漏。
from rdkit import Chem
from rdkit.Chem import AllChem

def standardize_smiles(smiles):
    mol = Chem.MolFromSmiles(smiles)
    if mol is None:
        return None
    return Chem.MolToSmiles(mol, canonical=True)

smiles_raw = "[H]O[H]"
smiles_std = standardize_smiles(smiles_raw)
print(smiles_std)  # "O"

你看,就这么简单一行,避免了多少后续麻烦。

进阶建议:去重时别只去重 SMILES,还要考虑 assay 类型。同一个化合物测了 10 次同一个 assay,取中位数是稳妥的做法。

数据准备好了,下一步就是特征工程。但那就是第五章的内容了。目前先把数据拿对、整理好,模型才能学出东西来。