MoleculeNet(Wu 等,Chemical Science 2018)是分子机器学习领域第一个系统性的基准套件。它极大地推动了领域发展——但它的一些设计缺陷被后续工作不加检验地沿用,反而成了误导的来源。
包含的数据集
| 类别 | 数据集 | 规模 |
|---|---|---|
| 量子力学 | QM7、QM8、QM9 | 7K~134K |
| 物理化学 | ESOL、FreeSolv、Lipophilicity | 0.6K~4K(很小) |
| 生物物理 | PCBA、MUV、HIV、BACE | 1.5K~440K |
| 生理学 | BBBP、Tox21、ToxCast、SIDER、ClinTox | 1.4K~8K |
它的真实贡献
- 统一了评测方式:在此之前,每篇论文用自己的数据与划分,结果无法比较;
- 提出了骨架划分:这是最重要的贡献之一——它明确指出随机划分会高估性能,并提供了基于 Bemis-Murcko 骨架的划分方式;
- 提供了标准的评价指标:分类用 ROC-AUC/PRC-AUC,回归用 RMSE/MAE;
- 降低了入门门槛:通过 DeepChem 提供一行代码加载(见 134《DeepChem 平台解读》)。
必须知道的问题
# 问题一:【数据集太小】
# ESOL: 1128 个分子
# FreeSolv: 642 个分子
# BACE: 1513 个分子
#
# 后果:
# - 不同随机种子的结果差异可能大于方法间的差异
# - 论文报告的「提升 0.02 AUC」可能纯属噪声
# - 【必须报告多次运行的均值与标准差】
#
# 检验方法:
# 用同一个方法跑 10 个不同种子,
# 看结果的标准差有多大
# → 如果标准差 0.03,那么 0.02 的「提升」没有意义
# 问题二:【标签质量参差】
# BBBP(血脑屏障通透性):
# 标签来自多个文献来源,定义不统一
# 有研究发现其中存在明显的标注错误
# ClinTox:
# 「临床试验失败」的原因多样,
# 不全是毒性 —— 标签定义模糊
# Tox21/ToxCast:
# 体外测定,与体内毒性的关系间接
#
# 后果:
# 模型的性能上限被标签噪声限制
# 刷到 0.95 AUC 可能意味着在拟合噪声
# 问题三:【随机划分仍被广泛使用】
# 虽然 MoleculeNet 提出了骨架划分,
# 但很多论文仍然报告随机划分的结果
# → 随机划分下,测试集分子的近似物在训练集中
# → 严重高估真实性能(见 167)
#
# 典型差距:
# 同一模型在 BACE 上
# 随机划分 AUC 0.88,骨架划分 AUC 0.78
# → 【差距巨大】
# 问题四:【与实际决策脱节】
# 预测 ESOL 的溶解度 RMSE 从 0.60 降到 0.55,
# 对实际项目意味着什么?
# → 论文通常不回答这个问题(见 133)
正确的使用方式
- 只用骨架划分或时间划分:随机划分的结果不应作为主要结论;
- 报告多个种子的均值 ± 标准差:单次运行的结果在小数据集上没有说服力;
- 与强基线比较:ECFP + 随机森林/LightGBM,且给基线同等调优预算(见 131《Chemprop / D-MPNN 论文精读》);
- 不要只看排行榜名次:关注提升的绝对幅度与统计显著性;
- 作为「快速验证代码能跑通」的工具,而非「证明方法优越」的依据。
加载与正确划分
import deepchem as dc
# DeepChem 提供的加载器
tasks, datasets, transformers = dc.molnet.load_bace_classification(
featurizer="ECFP",
splitter="scaffold", # 【不要用 "random"】
reload=False,
)
train, valid, test = datasets
print(f"训练 {len(train)}, 验证 {len(valid)}, 测试 {len(test)}")
# 或者自己用 RDKit 做骨架划分(更透明可控)
from rdkit import Chem
from rdkit.Chem.Scaffolds import MurckoScaffold
from collections import defaultdict
import numpy as np
def scaffold_split(smiles_list, frac_train=0.8, frac_valid=0.1, seed=0):
scaffolds = defaultdict(list)
for i, smi in enumerate(smiles_list):
mol = Chem.MolFromSmiles(smi)
if mol is None:
continue
scaf = MurckoScaffold.MurckoScaffoldSmiles(mol=mol, includeChirality=False)
scaffolds[scaf].append(i)
# 按骨架大小降序排列(大骨架优先进训练集)
groups = sorted(scaffolds.values(), key=len, reverse=True)
n = len(smiles_list)
n_train, n_valid = frac_train * n, frac_valid * n
train_idx, valid_idx, test_idx = [], [], []
for g in groups:
if len(train_idx) + len(g) <= n_train:
train_idx += g
elif len(valid_idx) + len(g) <= n_valid:
valid_idx += g
else:
test_idx += g
return train_idx, valid_idx, test_idx
# 【验证划分的有效性】:
# 计算训练集与测试集之间的最大 Tanimoto 相似度分布
# 如果很多测试分子与某个训练分子相似度 > 0.7,
# 说明划分不够严格
更好的替代基准
| 基准 | 优势 |
|---|---|
| TDC(见 133《TDC 论文精读》) | 任务更贴近研发链条;划分方式更严格 |
| Polaris | 强调数据质量与评测严谨性 |
| LIT-PCBA(见 242《LIT-PCBA》) | 更真实的虚拟筛选场景 |
| 自家历史数据 | 最有说服力的评测 |
最重要的一条:真正的评测应该在自家数据上做时间划分——用 2023 年前的数据训练,预测 2024 年的实验结果。这才是模型在生产中面对的情形。
关键要点
- 多个数据集只有 1000 量级——种子间的方差可能大于方法间的差异;
- BBBP、ClinTox 等的标签质量存在已知问题,性能上限被噪声限制;
- 随机划分与骨架划分的差距可达 0.1 AUC——只应报告骨架划分结果;
- 真正有说服力的评测是在自家数据上做时间划分。
延伸资源
- TDC:133《TDC 论文精读》;DeepChem:134《DeepChem 平台解读》;Chemprop:131《Chemprop / D-MPNN 论文精读》;
- Benchmark 陷阱:169《Benchmark 陷阱》;模型外推性:167《模型外推性》。