4. 数据收集:公共数据库(PubChem、ChEMBL、Tox21)
做 ADMET 预测,数据是地基。地基不稳,模型再花哨也是白搭。
我个人习惯,先把三大公共数据库摸透。PubChem、ChEMBL、Tox21,这三兄弟各有脾气,用好了事半功倍。今天咱们就把它们捋一遍。
4.1 PubChem:小分子数据的大超市
PubChem 是美国 NIH 维护的公共化合物数据库。说白了,它像个大超市,上亿种化合物,各种生物活性数据都能找到。
我做过一个肝毒性预测项目,一开始数据不够。后来从 PubChem 的 BioAssay 板块扒了上千条数据,模型效果直接提升了 15%。
拿数据,个人推荐两条路:
- PUG REST API:灵活但需要写代码。适合批量查询。
- 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 秒。
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 |
| Activity | 0/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 万级别,正好够做中小型模型。如果要做深度学习,可以把它作为正样本,再加其他数据库的负样本做扩充。
4.4 数据预处理:你的数据必须标准化
不管从哪个数据库拿数据,最后都要预处理。我踩过最离谱的坑就是 SMILES 标准化。
同一化合物,不同数据库可能写法不一样。比如水的 SMILES,有人写 O,有人写 [H]O[H]。不标准化,模型会把它当成两个东西。
我的标准化四步走:
- 去重:相同 SMILES 只保留一条,活性值取平均或中位数。
- 标准化 SMILES:用 RDKit 把 SMILES 统一成 Canonical 格式。
- 归一化活性值:IC50 pIC50 转换,或者 MinMax 缩放。
- 拆分数据集:按 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"
你看,就这么简单一行,避免了多少后续麻烦。
数据准备好了,下一步就是特征工程。但那就是第五章的内容了。目前先把数据拿对、整理好,模型才能学出东西来。