4. 常用ADMET数据集介绍:ClinTox、Tox21、SIDER、BACE、ESOL、FreeSolv等

做多任务ADMET预测,数据就是粮食。没有高质量的数据集,再牛的模型也只是空中楼阁。

我自己刚开始搞这个方向的时候,就被各种数据集搞得一头雾水。有的只给分类标签,有的给连续数值,有的样本量大但噪声多,有的样本少但标注精准。

今天我会结合我的项目经验,把最常用的几个ADMET数据集掰开揉碎讲清楚。你想想看,掌握了这些数据集的特性,后面搭建多任务模型时,你才能知道哪些任务能一起学,哪些任务得分开处理。

4.1 数据集概览对比

先给个总览表,方便你快速定位每个数据集的价值。

数据集任务类型样本量标签特点我的常用场景
ClinTox分类(二分类)~1,500FDA批准状态 + 临床试验毒性毒性筛查的起点
Tox21多标签分类~8,00012种毒性通路,有活性/无活性多任务毒性预测的基准
SIDER多标签分类~1,400586种不良反应(部分关联药物)副作用预测与不良反应识别
BACE分类(二分类)~1,500β-分泌酶抑制剂(有活性/无活性)靶点特异性活性预测
ESOL回归~1,100水溶解度(LogS,mol/L)溶解度预测的经典小样本
FreeSolv回归~640水合自由能(kcal/mol)计算物理驱动的能量预测

注意看,这里既有分类又有回归,样本量从六百到八千不等。我在最初搭建多任务模型时,常把ClinTox和BACE的毒性/活性任务组合在一起,因为样本量相近、标签密度也接近。

4.2 ClinTox —— 临床毒性把关

ClinTox数据集包含了约1,500个药物分子,提供了两个标签:FDA批准状态和临床试验毒性。说白了,它会告诉你这个药是获批上市了,还是在临床试验阶段因为毒性被干掉了。

我习惯把这个数据集当作毒性预测的"第一关"。为什么呢?因为它样本量不大,但标注相对干净,适合快速验证模型是否学到了基本的毒性判别能力。

不过要注意一点——数据存在严重的类别不平衡。大部分分子是"未批准"或"有毒性"的,正样本很少。我曾经踩过的坑就是直接拿原始分布去训练,结果模型学成了"全部预测为无毒"。

经验技巧:处理ClinTox时,我建议先做分层采样,保证训练集和测试集中批准/未批准的比例一致。如果只用随机拆分,很容易把稀有类别全丢到测试集里。
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骨架做分组,保证训练集和测试集的骨架尽量不同。我推荐这种,更贴近真实应用场景。
  • 时间拆分:如果数据包含时间戳,可以用早期化合物做训练、晚期做测试,模拟进筛选流程。
多任务注意点:在Tox21上训练时,务必处理缺失标签。我一般会设置一个mask,在loss计算时只对非NaN的标签求梯度,而不是用零填充。

4.4 SIDER —— 药物副作用地图

SIDER数据集收录了1,400多种药物及其对应的586种不良反应。数据是从药品说明书和临床文献中整理出来的。每个药物-不良反应对都用一定证据级别标注(比如III期临床试验数据、上市后报告等)。

这个数据集特点非常鲜明:

  • 标签矩阵极度稀疏——一个药物平均只关联几十种副作用,其余都是负样本。
  • 副作用之间存在层级关系(例如"心脏病"下属有"心肌梗死"、"心力衰竭"等)——直接做多标签预测时,可以利用这种结构信息。
避坑指南:我曾经在这里翻过车——直接把SIDER的所有586个任务一起放进多任务模型,结果模型训练不动,因为正负样本比例严重失衡(有些任务正样本只有个位数)。我的建议是:先筛选出现频率最高的50-100种副作用(比如阳性样本数 > 50),再开始训练。

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)。

注意:这两个数据集标签分布差异很大——ESOL的LogS范围大致在-10到+2之间,而FreeSolv的ΔGhyd在-5到-30 kcal/mol之间。如果要把它们放进同一个多任务模型,最好先对每个任务做独立的标准化。我一般会Z-score归一化,让各个任务的loss量级保持一致。

4.7 数据集使用的一般原则与工具

聊了这么多具体数据集,我来总结几条我在项目中反复验证的原则:

  1. 多任务选择要遵循"任务相干性"。比如毒性预测(ClinTox、Tox21)和靶点活性预测(BACE)相关性较低,但两个毒性任务之间相关性较高。我习惯先计算任务标签之间的互信息,再决定是否联合训练。
  2. 样本量差异大时考虑加权。如果一个数据集有8,000样本,另一个只有600,那么在mini-batch抽样时,后者可能几个epoch才能见到一次。我会对少样本数据集做上采样,或者在loss里加权。
  3. 不要直接拼合SMILES不做清洗。不同数据集可能使用不同的盐形式、电荷表示、立体化学标记。我在做多数据联合之前,会用rdkit.Chem.MolFromSmiles做标准化,清除盐,统一中性分子。
  4. 用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 本章知识结构图

下面我画了一张图,把六个数据集的核心特征、任务类型和常见陷阱串起来,方便你对照记忆。

常用ADMET数据集总览 多任务ADMET数据集 ClinTox ~1.5k | 批准+毒性 Tox21 ~8k | 12通路 SIDER ~1.4k | 586副反应 BACE ~1.5k | 活性+IC50 ESOL ~1.1k | LogS FreeSolv ~640 | ΔGhyd 注意点: • 分类与回归任务混用时需做归一化,避免loss量级失衡 • 高度稀疏任务(如SIDER部分副作用)需做任务筛选,否则模型学不到东西

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等)。

我的建议:刚开始做多任务ADMET研究时,先拿Tox21(多分类)加上ESOL(单回归)练手,搞清数据加载、标签mask、多任务loss计算这些基本操作。等这个流程跑熟了,再逐步往里面加SIDER或ClinTox。