4. 常用ADMET数据集介绍:ClinTox、Tox21、SIDER、BACE、ESOL、FreeSolv等
做多任务ADMET预测,数据就是粮食。没有高质量的数据集,再牛的模型也只是空中楼阁。
我自己刚开始搞这个方向的时候,就被各种数据集搞得一头雾水。有的只给分类标签,有的给连续数值,有的样本量大但噪声多,有的样本少但标注精准。
今天我会结合我的项目经验,把最常用的几个ADMET数据集掰开揉碎讲清楚。你想想看,掌握了这些数据集的特性,后面搭建多任务模型时,你才能知道哪些任务能一起学,哪些任务得分开处理。
4.1 数据集概览对比
先给个总览表,方便你快速定位每个数据集的价值。
| 数据集 | 任务类型 | 样本量 | 标签特点 | 我的常用场景 |
|---|---|---|---|---|
| ClinTox | 分类(二分类) | ~1,500 | FDA批准状态 + 临床试验毒性 | 毒性筛查的起点 |
| Tox21 | 多标签分类 | ~8,000 | 12种毒性通路,有活性/无活性 | 多任务毒性预测的基准 |
| SIDER | 多标签分类 | ~1,400 | 586种不良反应(部分关联药物) | 副作用预测与不良反应识别 |
| BACE | 分类(二分类) | ~1,500 | β-分泌酶抑制剂(有活性/无活性) | 靶点特异性活性预测 |
| ESOL | 回归 | ~1,100 | 水溶解度(LogS,mol/L) | 溶解度预测的经典小样本 |
| FreeSolv | 回归 | ~640 | 水合自由能(kcal/mol) | 计算物理驱动的能量预测 |
注意看,这里既有分类又有回归,样本量从六百到八千不等。我在最初搭建多任务模型时,常把ClinTox和BACE的毒性/活性任务组合在一起,因为样本量相近、标签密度也接近。
4.2 ClinTox —— 临床毒性把关
ClinTox数据集包含了约1,500个药物分子,提供了两个标签:FDA批准状态和临床试验毒性。说白了,它会告诉你这个药是获批上市了,还是在临床试验阶段因为毒性被干掉了。
我习惯把这个数据集当作毒性预测的"第一关"。为什么呢?因为它样本量不大,但标注相对干净,适合快速验证模型是否学到了基本的毒性判别能力。
不过要注意一点——数据存在严重的类别不平衡。大部分分子是"未批准"或"有毒性"的,正样本很少。我曾经踩过的坑就是直接拿原始分布去训练,结果模型学成了"全部预测为无毒"。
from rdkit import Chem
from rdkit.Chem import PandasTools
import pandas as pd
# 读取ClinTox数据(简化示例)
df = pd.read_csv('clintox.csv')
print(df.columns) # ['smiles', 'FDA_APPROVED', 'CT_TOX']
print(df['FDA_APPROVED'].value_counts())
# 0: 未批准(Negative) 1: 已批准(Positive)
# 通常比例约 9:1
4.3 Tox21 —— 多任务毒性通路专家
Tox21是我个人在学术和工业项目中最常用的毒性数据集。它来自美国国土安全部和FDA的一个联合项目,包含了约8,000个化合物,覆盖12种不同的毒性通路(比如核受体激活、应激反应等)。
每个分子对每个通路都给出一个标签:1(有活性/毒性)、0(无活性)或用NaN表示未测试。这就自然形成了多任务二分类的结构。你想想看,这不就是多任务学习的天生试验场吗?
我做实验时,会同时预测所有12个任务。但要注意:不同通路之间正样本比例差异巨大,有的通路只有1%的阳性率,有的能达到10%。这会直接影响模型的梯度分配。
常用的拆分策略:
- 随机拆分:最简单,但不考虑分子骨架相似性,容易高估泛化能力。
- 骨架拆分:基于Murcko骨架做分组,保证训练集和测试集的骨架尽量不同。我推荐这种,更贴近真实应用场景。
- 时间拆分:如果数据包含时间戳,可以用早期化合物做训练、晚期做测试,模拟进筛选流程。
4.4 SIDER —— 药物副作用地图
SIDER数据集收录了1,400多种药物及其对应的586种不良反应。数据是从药品说明书和临床文献中整理出来的。每个药物-不良反应对都用一定证据级别标注(比如III期临床试验数据、上市后报告等)。
这个数据集特点非常鲜明:
- 标签矩阵极度稀疏——一个药物平均只关联几十种副作用,其余都是负样本。
- 副作用之间存在层级关系(例如"心脏病"下属有"心肌梗死"、"心力衰竭"等)——直接做多标签预测时,可以利用这种结构信息。
4.5 BACE —— 靶点活性预测
BACE数据集专门针对β-分泌酶(BACE-1)抑制剂,这是一个重要的阿尔茨海默症药物靶点。约1,500个分子,每个分子标注为"有活性"或"无活性",还附带IC50(半数抑制浓度)的测量值。
我习惯用BACE来测试模型对靶点特异性活性的区分能力。因为它的化学空间相对集中(都是围绕同一靶点设计的类似物),所以能很好地检验模型是否能捕捉到这种细微的构效关系。
这里有个有意思的点:BACE的活性阈值通常设为pIC50 > 5为活性。不过我在复现一些论文时发现,不同论文选择阈值略有差异(有的用4.5,有的用5.5),会影响最终模型效果。建议大家做对比实验时统一标准。
# BACE标签的pIC50分布(示例)
import numpy as np
pics = np.random.normal(5.0, 1.0, 1513) # 类似真实分布
threshold = 5.0
labels = (pics >= threshold).astype(int)
print(f"活性分子数: {labels.sum()}, 占比: {labels.mean():.2%}")
4.6 ESOL 和 FreeSolv —— 物理化学性质回归
这两个数据集是回归任务的代表,和前面几个分类任务形成了互补。
ESOL(水溶解度估算数据集)包含约1,100个分子,标签是LogS(以mol/L为单位的溶解度对数)。样本量不大,但覆盖范围较广,从极难溶到极易溶都有。我通常用它来评估模型的连续值预测精度,尤其是与物理化学相关的回归任务。
FreeSolv(水合自由能数据集)更小,只有约640个分子,但标签计算非常精确(来自量子力学计算或高精度力场)。它的标签是水合自由能ΔGhyd(kcal/mol)。
4.7 数据集使用的一般原则与工具
聊了这么多具体数据集,我来总结几条我在项目中反复验证的原则:
- 多任务选择要遵循"任务相干性"。比如毒性预测(ClinTox、Tox21)和靶点活性预测(BACE)相关性较低,但两个毒性任务之间相关性较高。我习惯先计算任务标签之间的互信息,再决定是否联合训练。
- 样本量差异大时考虑加权。如果一个数据集有8,000样本,另一个只有600,那么在mini-batch抽样时,后者可能几个epoch才能见到一次。我会对少样本数据集做上采样,或者在loss里加权。
- 不要直接拼合SMILES不做清洗。不同数据集可能使用不同的盐形式、电荷表示、立体化学标记。我在做多数据联合之前,会用
rdkit.Chem.MolFromSmiles做标准化,清除盐,统一中性分子。 - 用ChemBERTa等预训练模型时注意Tokenizer差异。有些Tokenizer对括号和数字敏感,直接拼接不同数据集可能导致tokenization不一致。
# 数据标准化示例
from rdkit import Chem
def standardize(smiles):
try:
mol = Chem.MolFromSmiles(smiles)
if mol is None:
return None
# 移除盐和水
mol = Chem.RemoveHs(mol)
# 返回规范SMILES
return Chem.MolToSmiles(mol, isomericSmiles=False)
except:
return None
# 对数据集统一处理
df['clean_smiles'] = df['smiles'].apply(standardize)
df = df.dropna(subset=['clean_smiles'])
4.8 本章知识结构图
下面我画了一张图,把六个数据集的核心特征、任务类型和常见陷阱串起来,方便你对照记忆。
4.9 小贴士:数据集的获取与格式
这些数据集在MoleculeNet、DeepChem、Therapeutics Data Commons (TDC)中都有整理好的版本。我个人推荐直接使用DeepChem的loader,可以一行代码下载并预处理:
import deepchem as dc
# 加载ClinTox
clin_tox_loader = dc.molnet.load_clintox()
tasks, datasets, transformers = clin_tox_loader
train, valid, test = datasets
# 加载Tox21
tox21_loader = dc.molnet.load_tox21()
# 同样返回 tasks, datasets, transformers
如果你更关注可复现性,也可以用TDC的接口,它提供了更细粒度的拆分(包括 scaffold split、random split、time split等)。