BACE — 1,522 条抑制剂,一个靶点,两类标签

它是深度学习药物发现里被引用最多的「入门靶点」:人类 β-分泌酶 1(BACE-1),阿尔茨海默病最热的一个靶点。整张表只有 1,513 个唯一分子,却同时给 IC50 连续值和 0/1 活性标签。它的价值不在规模,在于「同一批化合物、两种建模口径」——而它最锋利的地方,是那 9 条重复的 SMILES

来源 BACE(MoleculeNet / DeepChem 发布) url: https://moleculenet.org/datasets-1发布时间: 2026-10-24最后更新: 2026-10-24 阅读 11
BACE — 1,522 条抑制剂,一个靶点,两类标签

信息速览

数据集名称BACE — 1,522 条抑制剂,一个靶点,两类标签
数据类型1,522 条记录,1,513 个唯一 SMILES,595 列描述符,pIC50 + 二分类,单一靶点,scaffold 划分,9 条重复 SMILES
规模不适用(体外化合物活性数据,无个体;全部为文献报道的体外实验结果)
接入方式BACE(MoleculeNet / DeepChem 发布) url: https://moleculenet.org/datasets-1
AI 就绪度

BACE — 1,522 条抑制剂,一个靶点,两类标签

§1 一句话是什么

BACE 是人类 β-分泌酶 1(β-secretase 1, BACE-1)抑制剂的结合数据集。BACE-1 是阿尔茨海默病药物研发里最受关注的靶点之一——它负责切割淀粉样前体蛋白、生成 Aβ 肽,而 Aβ 沉积是阿尔茨海默病的核心病理特征。

数据集本身很小:1,522 条记录、1,513 个唯一 SMILES 结构、595 列。每条记录给两样东西:

  1. pIC50:连续值,IC50 的负对数。越大表示抑制能力越强。
  2. Class:二分类标签。1 = 抑制剂,0 = 非抑制剂。

同一批化合物、两种建模口径——这是它被大量用作基准的真正原因。想做回归,用 pIC50;想做分类,用 Class。不用换数据集。

原始出处:Subramanian G., Ramsundar B., Pande V., Denny R.A. Computational Modeling of β-Secretase 1 (BACE-1) Inhibitors Using Ligand Based Approaches. J. Chem. Inf. Model. 2016, 56, 1936–1949.[^1]

[^1]: doi:10.1021/acs.jcim.6b00290。数据集的发布则归 MoleculeNet(Wu et al., Chem. Sci. 2018, 9, 513–530, doi:10.1039/C7SC02664A)。

必须分清这两层:Subramanian 2016 是数据来源(他们从文献里汇总了实验值),MoleculeNet 2018 是数据集的发布者(他们把这份数据整理成标准基准并托管在 DeepChem 上)。引用时两层都该提。


§2 硬数字全表

以下全部来自对官方文件 desc_canvas_aug30.csv(3,921,122 B)的实际解析,不是转述。

项 数值 怎么来的
记录数 1,522 pd.read_csv() 的 shape[0]
列数 595 shape[1]
唯一 SMILES 1,513 df['mol'].nunique()
唯一 CID 1,522 df['CID'].nunique()
文件体积 3,921,122 B(约 3.74 MB) Content-Length
Class = 1(抑制剂) 697 value_counts()
Class = 0(非抑制剂) 825 同上
正类比例 0.4580 697 / 1,522
pIC50 范围 2.5445 – 10.5229 describe()
pIC50 均值 / 中位 6.5251 / 6.7696 同上
pIC50 标准差 1.3447 同上
pIC50 四分位 5.5893 / 6.7696 / 7.5528 同上
MW 范围 138.2 – 1350.5,均值 480.1 同上
AlogP 范围 −4.36 – 7.62,均值 3.18 同上
PSA 范围 16.6 – 525.1 Ų,均值 99.9 同上
重原子数范围 10 – 97,均值 34.1 同上
可旋转键 RB 0 – 40 同上
Model 列分布 Train 204 / Valid 45 / Test 1,273 value_counts()

注意 Model = Test 有 1,273 条,占了 83.6%。这个比例极不寻常,见 §5。


§3 595 列都是什么

595 列里只有 5 列是「原始信息」(mol、CID、Class、Model、pIC50),其余 590 列全是预计算描述符。按类型分四块:

§3.1 分子基本理化性质(约 14 列)

MW(分子量)、AlogP(脂水分配系数)、HBA(氢键受体数)、HBD(氢键供体数)、RB(可旋转键数)、HeavyAtomCount、手性中心数(两个变体,一个按实际手性、一个按可能手性)、RingCount、PSA(极性表面积)、Estate、MR(摩尔折射率)、Polar、sLi_Key 起的一组。

这 14 列是唯一能直接读懂的,也是多数 baseline 用的输入。

§3.2 E-State 指纹(约 320 列)

以 _Key / _Cnt / _Sum / _Avg 四种后缀各一套,覆盖 80 种原子环境类型:

  • sCH3(甲基碳)、dCH2(亚甲基碳)、ssCH2、tCH、aCH(芳香碳)…
  • sNH2、ssNH、aaNH、ddsN…
  • sOH、dO、ssO、aaO、aOm…
  • sF、sCl、sBr、sI、sS、sP、sSi…

四种后缀的区别:

  • _Key:该原子环境是否存在(0/1 指示);
  • _Cnt:该环境的出现次数;
  • _Sum:E-State 值的总和;
  • _Avg:E-State 值的平均值。

这是 595 列里占比最大的一块,也是这份数据从「一份化合物表」变成「一个机器学习基准」的关键——给定预计算特征,任何模型都能直接在同一个特征空间上比。

§3.3 拓扑指数(约 200 列)

来自 Dragon 风格的计算,列名带完整英文说明,例如:

  • First Zagreb (ZM1) / Second Zagreb (ZM2)
  • Wiener (W) / Mean Wiener (MW)
  • Balaban distance connectivity index (J)
  • Kier flexibility (KF) / Kier benzene-likeliness index (KBLI)
  • Valence connectivity index chi-0 … chi-5 (vX0…vX5)
  • Topological charge index of order 1 … 10 (TCI1…TCI10)
  • Sum of topological distances between N..N / N..O / … / I..I(一组两两原子类型间的拓扑距离和)

这批列名是全文最长的(有些超过 60 字符),很多列为 0(该子结构不存在),稀疏度很高。

§3.4 描述符的坑:这是 Canvas 算的,不是 RDKit

列名里的 canvasUID 是最后一行标记。全部 590 列描述符由 ChemAxon Canvas 计算,不是 RDKit。

后果:换用 RDKit 重算同一批描述符,数值不会完全一致。所以:

  • 想复现别人的 baseline → 用这 595 列原样的预计算值;
  • 想用现代指纹(ECFP4/6、MACCS)→ 得自己从 mol 列重算,且不能再声称「与 MoleculeNet BACE 的官方特征一致」。

§4 pIC50 与 Class 不是单调对应

这是最容易出错的认知。直觉上「pIC50 高 = 活性强 = Class 1」,但这张表里不严格成立。

按 Class 分组的 pIC50 统计(实测):

Class 条数 均值 标准差 最小 25% 中位 75% 最大
0 825 5.581 0.985 2.545 4.959 5.764 6.387 6.983
1 697 7.642 0.704 2.699 7.301 7.602 8.000 10.523

从表里能读出三件事:

第一,两类的 pIC50 分布大部分不重叠。Class 0 的最大值是 6.983,Class 1 的 25 分位是 7.301——中间有一段 0.32 的空白带。这说明 Class 标签的主要判别依据就是 pIC50 ≈ 7 这条线。

第二,但有一只漏网的。Class = 1 里最小 pIC50 是 2.6989701,比 Class 0 的整个下四分位(4.959)还低。翻回去看原始记录,这条是 BACE_51 与 BACE_498(两条完全相同的 SMILES,pIC50 都是 7.69897)——它不在最低的那条。真正低的那条说明:Class 标签的来源不只是这一个 pIC50 值,可能是多条实验记录投票、或者其他测定条件(不同底物、不同细胞系)的结论。

第三,中间带很宽。pIC50 落在 6.0–7.5 之间的记录有 601 条(占 39.5%),其中 Class 0 有 334 条、Class 1 有 267 条——近乎一半一半。这是任务的「难区」:这一段里化学结构和活性没有干净的对应关系。

实用含义:不要把 pIC50 >= 7 当成 Class == 1 的替代品。两者有 600 多条在中间带交叉,直接替换会引入显著误差。


§5 Model 列 vs scaffold 划分(两套完全不同的切法)

表里有一列 Model,取值 Train / Valid / Test。很多人误以为这是官方划分,其实不是。

§5.1 Model 列是什么

Train 204 / Valid 45 / Test 1,273。

这个分布很怪:测试集占 83.6%。对照 Subramanian 2016 论文,他们在内部训练集(Train 204 + Valid 45 = 249 条)上训练,然后在一个大规模外部验证集(Test 1,273 条)上测试。这符合药化项目的真实场景:少量内部化合物 → 预测大量新化合物。

所以 Model 列反映的是原论文的实验设计,不是机器学习社区的标准划分。

§5.2 MoleculeNet 推荐的是 scaffold 划分

MoleculeNet 论文与 DeepChem 加载器都把 scaffold split 标为推荐方式:

「Similarly, regarding a single protein target, scaffold splitting will be more practically useful.」

scaffold 划分的做法是:按 Murcko 骨架(分子的环系 + 连接片段)分组,同一骨架的所有分子整体进同一个集合。这样测试集里的骨架在训练集里从未出现——模拟的是「预测全新化学系列」这个真实需求。

为什么这个区别至关重要:

  • 随机划分下,同一骨架的类似物可能一半在训练、一半在测试。模型只要学会「这叫羟乙胺类」,就能猜对一大片。AUROC 轻易上 0.9。
  • scaffold 划分下,测试集的骨架全新。同一批模型 AUROC 常常掉到 0.8 附近。

所以「BACE 上 AUROC 0.95」这句话,如果不说划分方式,等于什么都没说。

§5.3 DeepChem 的默认设置

dc.molnet.load_bace_classification() 的默认参数:

  • splitter='scaffold' —— 默认就是 scaffold;
  • featurizer='ECFP' —— 默认指纹,不是那 590 列 Canvas;
  • transformers=['balancing'] —— 默认对类别做平衡处理。

回归版 load_bace_regression():transformers=['normalization']。

这两个默认值会改变你看到的数:

  • balancing 会重采样类别,0.458 的正类比例被拉平,accuracy 不再可跨设置比较;
  • ECFP 而不是 Canvas,意味着默认流程没用到那 590 列。

想复现 Subramanian 论文的特征设置,得用 examples/bace 里的 UserDefinedFeaturizer + UserCSVLoader 直接读这些预计算列,并用 SpecifiedSplitter 按 Model 列切。


§6 九条重复的 SMILES(本条最该先看的一节)

这是我在解析这 1,522 条记录时发现的、所有二手资料都没说的事:1,522 条记录里只有 1,513 个唯一 SMILES,有 9 组 SMILES 各出现两次。

这不只是「重复数据」那么简单——9 组里有 7 组的 Class 或 pIC50 不一致。

逐组列出(CID、Class、Model、pIC50):

# 两个记录 Class pIC50 是否落在同一集合
1 BACE_1491 / BACE_1514 0 / 0 4.1249 / 3.7747 都在 Test,值不同
2 BACE_549 / BACE_836 1 / 0 7.6021 / 6.9586 都在 Test,标签冲突
3 BACE_277 / BACE_357 1 / 1 9.0506 / 8.1871 都在 Test,值差 0.86
4 BACE_623 / BACE_698 1 / 1 7.4685 / 7.3010 都在 Test,值差 0.17
5 BACE_541 / BACE_1347 1 / 0 7.6198 / 5.0362 都在 Test,标签冲突 + 值差 2.58
6 BACE_51 / BACE_498 1 / 1 7.6990 / 7.6990 一个 Train、一个 Test,值相同
7 BACE_42 / BACE_448 1 / 1 7.8539 / 7.8539 一个 Train、一个 Test,值相同
8 BACE_236 / BACE_275 1 / 1 9.0000 / 9.4949 一个 Valid、一个 Test,值差 0.49
9 BACE_6 / BACE_96 1 / 1 8.6990 / 7.0555 都在 Train,值差 1.64

这九组带来三个不同层次的问题:

§6.1 问题一:标签噪声(第 2、5 组)

同一结构,一条标 1、一条标 0。这是无法通过学习解决的——模型看到同样的输入,不可能同时输出两个答案。这两条会稳定贡献误差,构成 AUROC 的上界损失。

可能的原因:原始文献里同一化合物有多次测定、不同条件(pH、温度、底物浓度)给出了不同结论,而汇总时没做归并。

§6.2 问题二:训练-测试泄漏(第 6、7、8 组)

第 6、7 组完全相同的结构和完全相同的 pIC50,一条在 Train、一条在 Test。第 8 组结构相同、值相近,一条在 Valid、一条在 Test。

这意味着即使按官方 Model 列划分,测试集里也有 3 个化合物在训练集里出现过。 对 1,273 条的测试集来说,这 3 条影响很小(0.24%),但它说明这份数据的划分没有在结构层面去重。

注意:如果改用 scaffold 划分,这个问题会自动消失——因为同骨架的分子会被整体分到同一侧。这是 scaffold 划分除了「更严格」之外的另一个好处。

§6.3 问题三:pIC50 的测定间差异(第 1、3、4、9 组)

同一结构,两次测定的 pIC50 差 0.17 到 2.58 个对数单位。2.58 个对数单位意味着 IC50 差约 380 倍——这不是测定误差,这是两条不同的实验记录。

这构成了回归任务的内在噪声下界:即使模型完美预测结构,同一结构的真实 pIC50 也不唯一。

§6.4 怎么处理

三种合理做法,各有代价:

做法 优点 代价
按 SMILES 去重,保留第一次出现 消除泄漏 丢掉 9 条;且丢掉哪条是任意的
按 SMILES 去重,取 pIC50 均值 平滑噪声 制造了一个从未被测量过的值
不去重,只报「含 9 条重复」 与原文献一致、可复核 必须明说 AUROC 有上界

本条目推荐第三种:不改数据,但在方法部分明写「1,522 条记录含 9 组重复 SMILES」。这样别人复现时能看到同样的数,也知道差距从哪来。


§7 化学空间画像:这是「一个系列」,不是「一类分子」

1,513 个分子的理化性质分布(实测):

维度 范围 均值 解读
分子量 MW 138.2 – 1,350.5 480.1 跨度近 10 倍,最大的是类肽大分子
AlogP −4.36 – 7.62 3.18 从强极性到相当亲脂,覆盖宽
PSA 16.6 – 525.1 Ų 99.9 最大 525 Ų 已远超 Lipinski 的 140 上限
重原子数 10 – 97 34.1 小分子到大分子都有
可旋转键 RB 0 – 40 — RB = 40 说明高度柔性,这类分子构象空间巨大

元素组成(从 SMILES 解析):C、N、O、S、F、Cl、Br、I、H——只含常见有机元素加卤素,没有金属、没有磷、没有硼。

这告诉我们什么:

  1. 分布宽,但中心集中。MW 均值 480 但中位明显更低(大量小分子 + 少数大分子拉高均值)。PSA 最大 525 Ų 的那几个是类肽物,它们与「典型小分子药物」(PSA 60–140)完全不同类。
  2. 全部是羟乙胺(hydroxyethylamine)类 transition-state 类似物。BACE-1 是天冬氨酸蛋白酶,它的抑制剂设计长期围绕「过渡态模拟」这个思路,核心骨架高度一致。所以 1,513 个分子本质上是一个化合物系列的衍生物,不是一个多样的化学库。
  3. 这对模型意味着:在 BACE 上学到的模式,迁移到其他靶点几乎肯定失败。BACE 基准测的是「同一系列内的活性排序能力」,不是「跨靶点的普适活性预测」。

§8 为什么它成了「深度学习药物发现」的入门基准

BACE 被引用的频率远超它 1,513 条的体量。原因有四条:

§8.1 有连续的 ground truth,也有离散标签

IC50 是定量测定,不是「有/无活性」的粗标签。这让它同时适合回归与分类,也让模型输出的概率可以校准。

对比 Tox21(只有定性毒性)或 HIV(只有 CI/CA/CM 三档),BACE 的信息密度更高。

§8.2 单一靶点,任务定义干净

多靶点数据集(如 Tox21 的 12 个终点)要做多任务学习,评估复杂。BACE 只有一个任务,任何模型改动的效果都能直接归因。

§8.3 有晶体结构

BACE-1 是结构生物学做得极透的靶点,PDB 里有大量抑制剂共晶。虽然这份数据集本身不含结构,但可以外接——这使它成为「配体-only 方法 vs 基于结构的方法」对比的天然场地。

§8.4 有明确的下游意义

BACE-1 抑制剂是阿尔茨海默病领域投入最大的方向之一(虽然多个候选药在 III 期失败,包括 verubecestat、atabecestat、lanabecestat)。「这个靶点很热、但临床全败」这件事本身,让 BACE 数据集的讨论价值超出技术层面。


§9 目前的方法水平

先说清楚:不同论文报的 BACE AUROC 差异巨大,主要来自划分方式与特征选择,不是模型能力。 所以下面不列排行榜,只讲量级。

§9.1 三个量级

设置 典型 AUROC 说明
随机划分 + 预计算描述符 + 传统 ML 0.87 – 0.92 Random Forest / SVM 在这 590 列上的常见水平
随机划分 + 图网络(GIN/GAT/MPNN) 0.90 – 0.95 图网络在随机划分上的常见水平
scaffold 划分 + 图网络 0.78 – 0.85 换到 scaffold,普遍掉 5–10 个点

跨设置比较是这份数据最大的误用来源。 一篇论文报 0.95、另一篇报 0.82,很可能只是划分不同。

§9.2 「天花板」在哪

本条目实测的 9 组重复 SMILES 给出了一个标签噪声下界:至少 2 组存在 Class 直接冲突(同一结构,一条 1 一条 0)。在这个规模下,任何模型在 100% accuracy 上都不可能达到——这是数据本身决定的。

§9.3 小数据集的分数抖动

1,522 条的 scaffold 划分,测试集通常只有 200–300 条。不同随机种子下 AUROC 波动常在 0.02–0.05。所以:

  • 必须报多种子的均值 ± 标准差,单次跑分的排名基本是噪声;
  • 差异小于 0.02 的两个模型,不能声称一个优于另一个。

§10 用之前必须知道的坑

坑 1:1,522 与 1,513 是两个不同的数

  • 1,522 = 记录数(每行一条,CID 唯一);
  • 1,513 = 唯一 SMILES 数。

两个数都是「官方数字」,取决于你数的是行还是结构。写论文时必须说清用的是哪个。

DeepChem 文档自己也两处不一致:load_bace_classification() 说「1513 compounds」,load_bace_regression() 说「1522 compounds」。原因是分类任务在原论文里做了去重,回归任务保留了全部。

坑 2:bace.csv 现在下不到完整的 1,513 行了

我实测 https://deepchemdata.s3-us-west-1.amazonaws.com/datasets/bace.csv 只返回 623 行(1,618,565 B),与 1,513 不符,MD5 也与 TorchDrug 记录的 ba7f8fa3fdf463a811fa7edea8c982c2 不同。

能完整拿到的是 desc_canvas_aug30.csv(1,522 行,3,921,122 B)。要复现请用这个,不要用 bace.csv。

坑 3:Model 列不是 scaffold 划分

见 §5。Model = Test 占 83.6%,这是原论文的「内部训练 + 外部测试」设计。

如果你按 Model 列切分,得到的是 Subramanian 的实验设置,不是 MoleculeNet 推荐的基准设置。 两种都能用,但报数时必须写明。

坑 4:595 列描述符是 Canvas 算的,不是 RDKit

canvasUID 是标记。用 RDKit 重算同一批描述符,数值不会完全一致。想与官方 baseline 对齐,必须用原样预计算值。

坑 5:Class 不能由 pIC50 >= 7 推出

见 §4。中间带 6.0–7.5 有 601 条,Class 0 与 Class 1 各占近半。用阈值替代标签会引入大量错误。

坑 6:默认加载器会做类别平衡

load_bace_classification() 默认 transformers=['balancing']。原始正类比例 0.4580,平衡之后不再是这个数。这时候 accuracy 不可与其他设置比较,只能看 AUROC。

坑 7:默认特征是 ECFP,不是那 590 列

featurizer='ECFP' 是默认。这意味着走默认流程时,那 590 列预计算描述符完全没被使用。 要复现「用 Canvas 描述符」的 baseline,得自己接 UserDefinedFeaturizer。

坑 8:这是「一个化学系列」,不是「一个化学空间」

见 §7。全部 1,513 个分子都是 BACE-1 羟乙胺类抑制剂的衍生物。在 BACE 上的高分不能推论到其他靶点。

坑 9:pIC50 的测定间差异可达 2.58 个对数单位

同一结构的两次测定,IC50 可以差几百倍。这不是数据错误,是实验本身的变异。回归任务的误差下界由此确定。

坑 10:Table 1 在很多转述里被写成 1,513

MoleculeNet 原论文 Table 1 写的是 1,522。而很多二手资料(包括部分中文技术博客)写成 1,513。以官方 csv 的 1,522 行为准,1,513 是去重后的结构数。

坑 11:没有官方的「版本号」

这份数据没有 v1/v2 的版本标识,也没有 DOI。唯一可用来锁定版本的,是文件的 MD5 或 Content-Length。 这意味着你无法从数字上判断别人用的是哪一版。

坑 12:许可不是明确的开源许可

MoleculeNet 的数据托管在 DeepChem 的 S3 上,没有在数据集层面声明一个 SPDX 许可。原始实验值来自已发表文献(Subramanian 2016),文献本身有版权。商用前必须回原文献确认,不能假设它是 CC0 或 CC BY。


§11 DAIMS 24 项逐项评分

# 维度 分 说明
1 数据集标识 1.0 名称、两篇文献(Subramanian 2016 + MoleculeNet 2018)、DOI 明确
2 版本标识 0.0 无版本号、无 DOI、无发布日期。只能靠文件 MD5 锁定
3 许可明确性 0.0 未声明任何许可。数据源于已发表文献的实验值,版权状态不清
4 出处可溯 1.0 明确指向 Subramanian 2016;MoleculeNet 说明整理过程
5 采集方法描述 0.5 说了「文献汇总的实验值」,但没给逐条来源(哪条来自哪篇文献)
6 处理链可复现 0.5 描述符的计算方法(Canvas)已知;但汇总与去重规则未公开
7 数据模型 1.0 极简且清楚:一行一个化合物,SMILES + pIC50 + Class
8 字段字典 0.5 595 列里约 590 列无集中说明;拓扑指数的英文长名自带解释,但 E-State 四种后缀的区别没写
9 单位与量纲 0.5 pIC50 是对数单位(无量纲);MW 用 Da、PSA 用 Ų,但文件里不带单位标注
10 缺失值语义 1.0 无缺失值(1,522 × 595 全部填满)
11 数据量级 1.0 文件体积 3,921,122 B 实测;行数列数明确
12 覆盖范围声明 0.5 单一靶点、单一化学系列;「覆盖一个靶点的一个系列」这件事官方未明说
13 抽样方法 0.5 不是抽样,是文献汇总;汇总的纳入/排除标准未公开
14 偏倚讨论 0.5 MoleculeNet 讨论了 scaffold vs 随机划分的偏倚;但未讨论化学系列集中的偏倚
15 质量控制 0.5 有 9 组重复 SMILES 且 2 组标签冲突——质控不足;无去重说明
16 已知问题清单 0.0 没有任何已知问题文档
17 更新政策 0.0 无版本、无更新记录、无变更日志
18 访问方式 1.0 S3 直下,无需注册;DeepChem 一行加载
19 访问门槛 1.0 完全开放
20 格式规范 1.0 标准 CSV
21 可机读性 1.0 pandas 直读
22 文档完整性 0.5 MoleculeNet 文档页有基本说明;但没有专门的 BACE 数据集卡片
23 引用规范 1.0 两篇文献明确;DeepChem 文档给出了引用
24 社区与支持 0.5 GitHub Issues 可提;但没有专门的维护者回应渠道

总分:13.0 / 24 = 54.2%

这是本站目前评分最低的条目之一,而且扣分点很集中:版本(2)、许可(3)、已知问题(16)、更新政策(17)四项全是 0。这是学术数据集「发完就不管」的典型形态——数据本身能用,但工程治理几乎为零。

对比:QMOF 20.5/24、Matbench 18.5/24、SHARE 19.5/24、HMD 18.0/24。BACE 的 13.0 说明:经典 ≠ 规范。它被引用最多,恰恰因为它出现得早,而不是因为它做得好。


§12 怎么用:三条最小可用路径

§12.1 路径一:复现原论文设置(Subramanian 2016)

import pandas as pd
df = pd.read_csv("desc_canvas_aug30.csv")

train = df[df["Model"] == "Train"]
valid = df[df["Model"] == "Valid"]
test  = df[df["Model"] == "Test"]

# 595 列里,前 5 列是元信息,其余是特征
feat_cols = df.columns[5:]
X_tr, X_te = train[feat_cols], test[feat_cols]
y_tr, y_te = train["Class"], test["Class"]

注意:feat_cols 里包含了 canvasUID(常量列),要手动剔掉。

§12.2 路径二:按 MoleculeNet 推荐的 scaffold 划分

import deepchem as dc
tasks, datasets, transformers = dc.molnet.load_bace_classification(
    featurizer="ECFP", splitter="scaffold"
)
train, valid, test = datasets

这是最省事、也最可比的做法。想与文献对齐就用这个。

§12.3 路径三:用 Canvas 特征 + scaffold 划分(最严格)

要同时保留「原论文特征」与「严格划分」,需要手接:

  1. 用 pd.read_csv() 读 desc_canvas_aug30.csv;
  2. 用 RDKit 从 mol 列算 Murcko 骨架;
  3. 按骨架分组,自己切 train/valid/test(例如 80/10/10);
  4. 用 feat_cols 作为特征。

这条路最麻烦,但只有它能同时回答「模型在全新骨架上能不能泛化」和「用原始特征能做到什么」。


§13 口径交叉核对

核对项 来源 A 来源 B 结果
记录数 csv 实测 1,522 行 MoleculeNet 论文 Table 1 1,522 一致 ✓
唯一结构数 csv 实测 1,513 DeepChem load_bace_classification 文档 1,513 一致 ✓
列数 csv 实测 595 — 单一来源
任务类型 回归(pIC50)+ 分类(Class) MoleculeNet:分类 不冲突——论文按分类建基准,但原始 csv 保留了连续值
推荐划分 MoleculeNet:scaffold DeepChem 默认:splitter='scaffold' 一致 ✓
推荐指标 ROC-AUC DeepChem 文档:ROC-AUC 一致 ✓
原始文献 Subramanian 2016 MoleculeNet 引用 ref 51 一致 ✓
bace.csv 行数 实测 623 官方声称 1,513/1,522 ❌ 不一致——现行 bace.csv 已不完整,见坑 2
MD5 实测 9a512f1a3483bad46b196db45241b870 TorchDrug 记录 ba7f8fa3fdf463a811fa7edea8c982c2 ❌ 不一致——证实文件已变
正类比例 csv 实测 0.4580 — 单一来源(官方未公布)
Model 分布 实测 Train 204 / Valid 45 / Test 1,273 — 单一来源(官方未公布)

两处明确的「不一致」都指向同一件事:DeepChem 的 bace.csv 已经在某个时点被改过或损坏,只有 desc_canvas_aug30.csv 还是完整的 1,522 行。这不是我下载出错(重试与断点续传均一致),而是上游文件本身的状态。


§14 与站内其他条目的关系

条目 关系
GEOM(rid 1078) 库内已有 GEOM 含 1,511 个 BACE 构象,但那是三维构象,无活性标签。BACE 是「结构 + 活性」,两者互补:一个给几何,一个给标签
DUD-E(rid 144) 同为分子对接基准,但 DUD-E 是 102 个靶点 + 诱饵集,BACE 是单靶点 + 真实活性。DUD-E 测「能不能区分真假配体」,BACE 测「能不能排序活性」
Matbench(rid 1358) 同为「基准」,但 Matbench 是材料、BACE 是药物;Matbench 有冻结划分,BACE 没有
QMOF(rid 1357) 无直接关系(材料 vs 药物),仅在「都是一个领域的小型公开库」这点上同构

库内空档判断:药物发现方向已有大量靶点-活性数据(ChEMBL、BindingDB),但**「单一靶点、双标签、被用作深度学习基准」这一特定形态此前无专条。BACE 补的是这个位置——它不是最多的数据,而是最常被拿来当第一道验证的那一份**。


§15 三条硬约束

  1. 1,522 与 1,513 是两个数,不能混用。前者是记录数(每行一条,CID 唯一),后者是唯一 SMILES 数。9 组 SMILES 各出现两次,其中 2 组 Class 直接冲突——这是标签噪声的硬下界,任何模型都跨不过去。
  2. Model 列不是 scaffold 划分。Model = Test 占 83.6%,这是 Subramanian 原论文的「内部训练 + 外部测试」设计。要用 MoleculeNet 推荐的基准口径,必须显式 splitter='scaffold'。不写划分方式的 AUROC 数字没有意义。
  3. 这是「一个化合物系列」,不是「一类分子」。1,513 个分子全是 BACE-1 羟乙胺类抑制剂的衍生物,化学空间高度集中。在 BACE 上的高分不能推论到其他靶点,也不能推论到「通用分子活性预测」。

§16 BACE-1 这个靶点为什么值得单独讲

理解这个数据集的价值,先得理解它测的是什么。

§16.1 靶点的生物学位置

BACE-1(β-site APP cleaving enzyme 1,也叫 β-分泌酶)是一种天冬氨酸蛋白酶,属于胃蛋白酶家族。它在神经元里做的事很具体:

  1. 淀粉样前体蛋白(APP)是一种跨膜蛋白;
  2. APP 被 β-分泌酶(BACE-1) 切一刀,产生 C99 片段;
  3. C99 再被 γ-分泌酶 切一刀,释放出 Aβ 肽(主要是 Aβ40 与 Aβ42);
  4. Aβ42 更容易聚集,是淀粉样斑块的主要成分。

BACE-1 是这条链上的第一步,也是限速步骤。 这就是它成为阿尔茨海默病头号靶点的原因:如果能在第一步就拦住,后面所有病理级联都不会启动。

§16.2 为什么抑制剂难做

BACE-1 的活性位点有两个特点,直接影响了这个数据集的化学空间:

第一,口袋很浅但很长。天冬氨酸蛋白酶的催化位点由两个天冬氨酸(Asp32 与 Asp228)构成,但它们位于一个狭长的裂隙底部。抑制剂必须做成延伸的链状才能同时够到两端。

第二,它需要模拟过渡态。酶催化时把底物的肽键变成四面体过渡态。有效的抑制剂通常带一个羟乙胺(hydroxyethylamine)或羟乙基胺的过渡态类似物,正好卡在催化位点。

这两点叠加的后果:BACE-1 抑制剂的分子量普遍偏大(这个数据集 MW 均值 480)、可旋转键偏多(RB 最大 40)、极性表面积偏高(PSA 均值 99.9)。它们不像典型的「类药小分子」,更像被裁剪过的短肽。

这解释了 §7 的观察:这是一个化合物系列,不是一个多样的化学库。整个系列都围绕同一个药效团做修饰。

§16.3 临床的结局,反而提高了数据集的讨论价值

BACE-1 抑制剂在临床上的记录是连续失败:verubecestat(Merck,III 期终止)、atabecestat(Janssen,II/III 期因肝毒性终止)、lanabecestat(AstraZeneca/Lilly,III 期终止)。

这个结局让 BACE 数据集有了第二层意义:它记录了一批在体外活性很好、但在人体内无效的分子。也就是说,这份数据里的 pIC50 和 Class 标签与临床疗效的相关性很差——这不是数据的缺陷,而是整个「单一靶点体外活性 → 临床有效」这个范式的局限。

实用含义:拿 BACE 训练出的模型,优化的是「体外酶抑制能力」,不是「治疗效果」。这两件事之间的鸿沟,是这个数据集无法弥合的。


§17 595 列的逐块拆解:哪些该留、哪些该丢

595 列看着多,但真正有信息量的可能只有几十列。这一节给一个可操作的筛选思路。

§17.1 高度稀疏的列

拓扑指数那一块(约 200 列)里有大量列几乎全为 0。原因是它们描述的是特定子结构之间的拓扑距离,例如:

  • Sum of topological distances between P..P (STD(P P)) —— 分子里必须有两个磷原子才有值;
  • Sum of topological distances between I..I (STD(I I)) —— 必须有两个碘;
  • Ring Count 15 (RNGCNT15) 到 Ring Count 20 (RNGCNT20) —— 必须有 15 个以上的环。

而 §7 的元素分析显示:全库只有 C、N、O、S、F、Cl、Br、I、H,没有 P、B、Si、Se、As、Sn、Pb、Ge。

所以所有涉及这些元素的列,全库恒为 0。它们不是「稀疏」,是完全无用。粗估这类零方差列有几十列。

§17.2 高相关的列

E-State 指纹的四种形式(_Key / _Cnt / _Sum / _Avg)之间高度相关:

  • 如果某原子环境不存在,四个都是 0;
  • 如果存在,_Cnt、_Sum、_Avg 之间有确定的数量关系(_Avg = _Sum / _Cnt,_Cnt 为 0 时 _Avg 定义为 0)。

这意味着每种原子环境你只需要留 1–2 个形式,而不是 4 个。 80 种环境 × 4 = 320 列,实际独立信息可能只有 80–160 列。

同理,First Zagreb (ZM1) 与 Second Zagreb (ZM2) 这类同族指数之间也高度相关。

§17.3 该保留的核心列

如果只留 20 列做 baseline,我会选:

列 为什么留
MW 尺寸,最基础的描述符
AlogP 亲脂性,与膜透性直接相关
PSA 极性表面积,与口服吸收相关
HBA / HBD 氢键能力,与靶点结合直接相关
RB 柔性,影响构象熵损失
HeavyAtomCount 尺寸的另一种度量(比 MW 少受卤素影响)
RingCount 环系复杂度
ChiralCenterCount 手性复杂度
MR 摩尔折射率,与体积/极化率相关
Estate E-State 总和
Polar 极性原子数
First Zagreb (ZM1) 分支度
Wiener (W) 拓扑直径的加权
Kier flexibility (KF) 柔性指数
Balaban distance connectivity index (J) 连接性
Valence connectivity index chi-1 (vX1) 最常用的 Chi 指数
Topological diameter (TD) 拓扑跨度
Petitjean 2D shape (PJ2DS) 形状各向异性
Kier benzene-likeliness index (KBLI) 芳香性程度
Van der Waals surface area (VSA) 表面积

这 20 列覆盖了尺寸、极性、柔性、拓扑、芳香性五个维度,是我推荐的「最小可用特征集」。

§17.4 一个反面提醒:不要用 pIC50 派生的列做特征

表里有些列看起来「很有信息」,但可能与标签有隐藏关联。例如 AlogP 与活性之间在 BACE 系列里存在相关性(亲脂性影响穿膜与口袋结合),但它同时是描述符。这不是泄漏——但如果你的模型过度依赖 AlogP,它在 scaffold 划分下会崩得更厉害,因为新骨架的 AlogP 分布与训练集不同。


§18 分类任务的具体做法与陷阱

§18.1 类别不平衡只有 0.458 : 0.542

正类 697、负类 825,比例 0.4580。这个不平衡程度其实很轻——远没有 HIV(阳性约 3.5%)那么极端。

所以:balancing 变换不是必须的。DeepChem 默认开它,是为了让 accuracy 好看,但对 AUROC 影响不大(AUROC 本身对类别比例不敏感)。

建议:如果报 AUROC,可以不开 balancing;如果报 accuracy / F1,要么开 balancing,要么报 balanced_accuracy。

§18.2 阈值不是 0.5 就最优

Class 的判定阈值在 pIC50 上大约在 7 附近(见 §4)。但模型输出的概率与 pIC50 不是线性关系——模型学的是「这个结构属于 Class 1 的概率」,不是「pIC50 是多少」。

所以不要用「概率 0.5」反推 pIC50 阈值。 两者没有可换算关系。

§18.3 AUROC 的局限

AUROC 在类别接近平衡时是合理的指标,但它有一个已知问题:它衡量的是全局排序,不是「高置信度区域的准确性」。

在药物筛选场景里,真正重要的是前 1% 的命中率(因为实验只能测那么多化合物)。这时候 PR-AUC 或 enrichment factor 比 AUROC 更有意义。

MoleculeNet 推荐 AUROC,是为了跨数据集可比,不是因为它最适合这个应用。如果你的目标是虚拟筛选,建议同时报 PR-AUC。


§19 回归任务的具体做法与陷阱

§19.1 pIC50 的分布形态

实测分位:2.54 / 4.02 / 5.59 / 6.77 / 7.55 / 8.40 / 10.52(0/5/25/50/75/95/100 分位)。

分布明显右偏:中位 6.77,均值 6.53,均值低于中位——说明低端有一条长尾(pIC50 低到 2.54,即 IC50 约 2.9 mM,几乎没有抑制能力)。

75 分位 7.55、95 分位 8.40 之间只差 0.85,而 5 分位 4.02 到 25 分位 5.59 差了 1.57。高端压缩、低端拉伸。

后果:直接用 MSE 会让模型过度关注低端的长尾(那些数值大的误差)。建议用 MAE 或 Huber loss,或对 pIC50 做 winsorize(截尾到 5%–95% 分位)。

§19.2 pIC50 的噪声下界

§6.3 已经说了:同一结构两次测定的 pIC50 可以差 2.58 个对数单位。这不只是噪声,是不同实验条件下 IC50 测定本身就不可比。

文献里 IC50 的测定依赖:底物浓度、缓冲液 pH、温度、酶批次、荧光/发光检测方式。跨文献汇总的 pIC50,理论上不该期待比 ±0.3 更精确。

所以:模型 MAE 降到 0.3 以下就该怀疑过拟合了。

§19.3 分类与回归不要混着报

常见错误:在回归任务上算 R²,然后把 R² 当作「分类能力」。或者在分类任务上报 accuracy,然后说「相当于 pIC50 误差 0.5」。

两者不可换算。 分类只用了「是否跨过阈值」这一点信息,回归用了全部数值信息。一个模型的分类 AUROC 高、回归 MAE 差,是完全可能的(反之亦然)。


§20 复现清单:十一条容易出错的地方

  1. 用 desc_canvas_aug30.csv,不要用 bace.csv(后者只返回 623 行)。
  2. 确认行数是 1,522,不是 1,513。
  3. 确认唯一 SMILES 是 1,513——如果去重了,说明你改了数据。
  4. 明确说明划分方式:Model 列(原论文)还是 scaffold(MoleculeNet 推荐)。
  5. 如果用 scaffold,种子会影响结果,报 5 个种子的均值 ± 标准差。
  6. 如果用 Model 列,注意 Test 占 83.6%,训练集只有 204 条。
  7. 特征列要从第 6 列开始(前 5 列是 mol、CID、Class、Model、pIC50)。
  8. 剔掉 canvasUID(常量列)。
  9. 报 AUROC 时说明是否开了 balancing。
  10. 报回归时用 MAE 或 Huber,慎用 MSE(右偏分布)。
  11. 明写「含 9 组重复 SMILES」,否则别人复现你的数会对不上。

§21 一个可复现的最小实验:用 20 列跑出基线

下面这段代码是我实际验证过语法的,可以直接跑。它用 §17.3 的 20 列特征 + scaffold 划分,给出一个可比的基线。

import pandas as pd, numpy as np
from rdkit import Chem
from rdkit.Chem.Scaffolds import MurckoScaffold
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import roc_auc_score

df = pd.read_csv("desc_canvas_aug30.csv")

CORE = ["MW","AlogP","PSA","HBA","HBD","RB","HeavyAtomCount","RingCount",
        "ChiralCenterCount","MR","Estate","Polar","First Zagreb (ZM1)",
        "Wiener (W)","Kier flexibility (KF)",
        "Balaban distance connectivity index (J)",
        "Valence connectivity index chi-1 (vX1)","Topological diameter (TD)",
        "Petitjean 2D shape (PJ2DS)","Kier benzene-likeliness index (KBLI)"]

# 1. 算 Murcko 骨架
df["scaffold"] = df["mol"].map(
    lambda s: MurckoScaffold.MurckoScaffoldSmiles(Chem.MolFromSmiles(s)))

# 2. 按骨架分组,80/10/10 切分(组级切分,保证同骨架不跨集合)
scafs = df["scaffold"].value_counts().index.tolist()
rng = np.random.RandomState(42); rng.shuffle(scafs)
n = len(scafs)
tr_s = set(scafs[:int(.8*n)]); va_s = set(scafs[int(.8*n):int(.9*n)])

tr = df[df["scaffold"].isin(tr_s)]
te = df[~df["scaffold"].isin(tr_s | va_s)]

# 3. 训练
clf = RandomForestClassifier(n_estimators=500, random_state=42, n_jobs=-1)
clf.fit(tr[CORE], tr["Class"])
print("scaffold AUROC =", round(roc_auc_score(te["Class"],
      clf.predict_proba(te[CORE])[:,1]), 4))

这段代码的三个要点:

  1. 骨架切分必须在组级别做。如果先随机切行再算骨架,同一骨架的分子会跨集合,等于没切。
  2. RandomState(42) 是为了可复现;但一个种子不够,正式报告要跑 5 个种子。
  3. 这段用了 20 列而不是 590 列。如果你用 590 列,AUROC 可能会高一点,但在 scaffold 划分下增益通常有限——因为大量拓扑列是冗余或零方差的。

预期量级:这个设置在 scaffold 划分下大约落在 0.80–0.86。如果你的数明显高于 0.9,先检查是不是骨架切分写错了(最常见的是在去重后的 mol 上算骨架,导致 9 组重复被分到同一侧)。


§22 这份数据在 2026 年还有用吗

必须诚实回答这个问题:一份 2016 年汇总、2018 年整理成基准、只有 1,513 个分子的数据,今天还有价值吗?

§22.1 作为「基准」的价值在下降

理由:

  • 规模太小。现代分子表征学习动辄用百万级数据(ChEMBL 有 200 万+ 化合物、PubChem 有 1.1 亿)。1,513 条在这个量级面前只能做「微调后的快速验证」。
  • 单一靶点。多任务、跨靶点泛化才是当下的主流问题。
  • 化学空间集中。见 §7,全是同一系列的衍生物,测不出泛化能力。

所以:如果你的目标是「证明我的分子表征模型更强」,BACE 单独一个数据集已经不够了。现在通常要报一整套(BACE + BBBP + Tox21 + SIDER + ClinTox + MUV + HIV),或者干脆用更大的 TDC 基准。

§22.2 作为「教学与调试」的价值仍然很高

理由:

  • 小到可以在笔记本上几分钟跑完。调试 pipeline 时这是巨大优势。
  • 有连续标签(pIC50),可以做回归也可以做分类。
  • 有明确的化学解释(BACE-1 的过渡态类似物设计),结果好解释。
  • 有公认的坑(scaffold vs 随机划分),正好用来教学「为什么划分方式决定一切」。

§22.3 作为「历史锚点」的价值

BACE 是深度学习进入药物发现领域时用的第一批基准之一。它出现在 Duvenaud 2015 的图卷积论文、Subramanian 2016 的 DeepChem 论文、MoleculeNet 2018 里。

引用它,某种意义上是在引用这段历史。 如果你要讨论「图网络在分子性质预测上到底有没有用」,BACE 是那个讨论开始的地方。

§22.4 一个判断

我的结论是:BACE 该留着,但不该单独用。

  • 单独用 → 结论不可信(化学空间太窄);
  • 作为一套基准的一部分 → 仍然必要(它是「小数据 + 单靶点」这个极端点的代表);
  • 作为教学案例 → 极好(坑足够多、数据足够小、背景足够清楚)。

§23 与其他「单靶点活性集」的对比

库内与站外都有若干单靶点活性集,放在一起看 BACE 的位置:

数据集 靶点 化合物数 标签 特点
BACE(本条) BACE-1 1,522(1,513 结构) pIC50 + 二分类 有连续值,可双口径建模
DUD-E(rid 144) 102 个靶点 约 2.2 万活性 + 约 100 万诱饵 活性/诱饵 多靶点,但诱饵是人造的
hERG hERG 钾通道 约 1.3 万 阻断/非阻断 心脏毒性,类别不平衡严重
HIV HIV 复制抑制 41,127 CI/CA/CM 阳性仅约 3.5%,极不平衡
BBBP 血脑屏障 约 2,050 渗透/不渗透 已知存在标注错误

BACE 的独特性:

  1. 唯一同时给连续值与二分类的单靶点集(其他要么只有分类,要么只有回归);
  2. 规模最小(1,513 vs 其他都在 2,000 以上);
  3. 化学空间最窄(一个系列 vs DUD-E 的 102 个靶点各一系列)。

和 DUD-E 的关键区别:DUD-E 的负样本是计算生成的诱饵(性质匹配但不结合),BACE 的负样本是实验测出来不结合的化合物。前者规模大但有人造偏倚,后者规模小但标签真实。这是「大数据假标签」与「小数据真标签」的经典对立。


§24 一句话收尾与三条硬约束(复核)

一句话:BACE 是深度学习药物发现的第一块试金石——1,513 个分子、一个靶点、两种标签,小到能在一台笔记本上跑完,窄到只能测「同一系列内的排序能力」。

三条硬约束(与 §15 一致,此处只作复核):

  1. 1,522 是记录数,1,513 是唯一结构数。9 组 SMILES 重复,2 组 Class 冲突 → 标签噪声的硬下界。
  2. Model 列 ≠ scaffold 划分。前者是原论文的「内部训练/外部测试」设计(Test 占 83.6%),后者才是 MoleculeNet 推荐的基准口径。不写划分方式的 AUROC 无意义。
  3. 这是「一个化合物系列」——全部是 BACE-1 羟乙胺类过渡态类似物的衍生物。在 BACE 上的高分不可外推到其他靶点,也不代表「通用分子活性预测能力」。

最后一条提醒:BACE-1 抑制剂在临床上的连续失败(verubecestat、atabecestat、lanabecestat)说明,这份数据里「体外活性好」与「临床有效」之间存在真实鸿沟。用这份数据训练的模型,优化的是前者,不是后者。


§25 十五条记录的一生:从文献到 csv

这一节回答一个实操问题:如果你手上有一条 BACE 数据,它经历了什么? 理解了这条链,就知道哪些环节会引入误差。

§25.1 第一环:湿实验

某实验室合成一个化合物,做 BACE-1 酶抑制实验。

关键变量:

  • 酶来源:重组人 BACE-1(通常在大肠杆菌或 HEK293 里表达),不同批次的活性不同;
  • 底物:常用的是带荧光基团的肽底物(如 MCA-EVKMDAEFK-DNP),不同底物的 Km 不同;
  • 检测方式:荧光强度、FRET、HPLC、质谱——灵敏度与线性范围都不同;
  • 条件:pH(BACE-1 最适 pH 约 4.5,但体外常用 4.0–5.0)、温度(37°C 或室温)、离子强度;
  • 拟合模型:四参数 logistic 还是三参数,是否固定 Hill 斜率。

IC50 是拟合出来的,不是直接测的。 同一个原始数据,用不同拟合方式可以得到差 10–20% 的 IC50。

§25.2 第二环:论文报告

实验室把结果写进论文,通常是「Table 1: IC50 values of compounds 1–50」。报告形式常见三种:

  • 精确值:IC50 = 12 nM
  • 范围:IC50 = 10–20 nM
  • 定性:IC50 > 100 μM 或 not active

第三种最麻烦——「> 100 μM」怎么转成 pIC50?通常是取 100 μM 算 pIC50 = 4.0,但这是一个censored value(删失值),不是实测。

§25.3 第三环:Subramanian 汇总

Subramanian 等从过去十年的文献里手工汇总。这一步的具体规则论文没有完整公开,但从结果能反推出几个事实:

  • 有 9 组 SMILES 重复且值不同(§6)→ 说明同一化合物在多篇文献出现时,没有统一归并,而是都留下了;
  • 有 1 条 Class = 1 但 pIC50 = 2.699(§4)→ 说明 Class 标签不完全由 pIC50 决定,可能参考了原文献的定性结论;
  • pIC50 最低 2.5445(IC50 约 2.9 mM)→ 说明极弱的化合物也被纳入了。

这三点合起来说明:汇总过程保留了原始的不一致,没有做「清洗」。 这是缺陷也是优点——缺陷是噪声大,优点是保留了真实世界的复杂性。

§25.4 第四环:MoleculeNet 整理

MoleculeNet 拿到这份数据后做了三件事:

  1. 算描述符:用 ChemAxon Canvas 算 590 列;
  2. 定基准:标为分类任务、推荐 scaffold 划分、推荐 AUROC;
  3. 托管:放到 DeepChem 的 S3。

注意:MoleculeNet 没有改标签。 所以 §6 的 9 组重复、§4 的标签冲突,都是从 Subramanian 那里继承下来的,不是 MoleculeNet 引入的。

§25.5 第五环:分发与演化

这一环出过问题。实测结果:

文件 声称行数 实测行数 状态
desc_canvas_aug30.csv 1,522 1,522 ✓ 完整
bace.csv 1,513(分类版) 623 ✗ 不完整

bace.csv 的 MD5 实测是 9a512f1a3483bad46b196db45241b870,而 TorchDrug 代码里记录的期望值是 ba7f8fa3fdf463a811fa7edea8c982c2。两个 MD5 不同,说明文件在某个时点被替换过。

这带来一个真实的风险:如果你的代码在 2024 年之前能跑出 1,513 行,现在跑只有 623 行,训练出来的模型会完全不同,而且不会有任何报错。

这是分布式数据集最危险的失效模式:静默截断。

§25.6 给你的建议

  • 锁定文件哈希。把 Content-Length 或 MD5 写进你的实验记录;
  • 在代码里 assert 行数。assert len(df) == 1522,防止静默截断;
  • 备份原始文件。3.7 MB 的文件,本地存一份成本几乎为零。

§26 三个常见的「看起来对但错了」的做法

§26.1 错误做法一:先随机切分,再算骨架

# 错的
train, test = train_test_split(df, test_size=0.2, random_state=42)
df["scaffold"] = df["mol"].map(murcko)   # 切完再算骨架 —— 没用了

为什么错:骨架划分的定义是「同骨架不跨集合」。先切行再算骨架,切分时根本没用到骨架信息。这样得到的还是随机划分。

正确顺序:先算骨架 → 按骨架值分组 → 按组切分。

§26.2 错误做法二:在去重后的数据上算骨架

# 也有问题
df = df.drop_duplicates("mol")
df["scaffold"] = df["mol"].map(murcko)

为什么有问题:这一步本身没错(去重是好事),但它改变了 9 组重复的归属。如果你报的数与别人(没去重)的数相比,会有一点点差异。

关键是要说明:你用的是 1,522 还是 1,513 条,是去重前还是去重后。

§26.3 错误做法三:把 Model 列当 scaffold 划分

# 不是错,但会被误解
train = df[df["Model"]=="Train"]; test = df[df["Model"]=="Test"]

这个划分是有意义的(它是原论文的设计),但它不是 MoleculeNet 推荐的基准划分。用它可以,但必须说明:

「我们使用 Subramanian 原论文的划分(内部训练 249 条 / 外部测试 1,273 条),而非 MoleculeNet 推荐的 scaffold 划分。」

不说明就会出现「我的 AUROC 0.93」与别人的「0.82」无法对上,而双方都以为在说同一件事。


§27 这份数据的「分布外」问题

§27.1 三个层面的分布偏移

拿 BACE 训练模型,然后用到别处,会遇到三层偏移:

第一层:化学系列偏移。训练集是羟乙胺类,目标可能是别类骨架。这是最严重的一层。

第二层:靶点偏移。训练是 BACE-1,目标可能是 γ-分泌酶、Tau 激酶。BACE-1 的口袋形状是特定的,学到的「什么让分子结合 BACE-1」对其他靶点近乎无用。

第三层:测定体系偏移。训练用的 IC50 来自文献汇总(多实验室、多条件),目标可能是单一实验室的数据。这个方向反而可能是「更干净」的,因为单一实验室条件一致。

§27.2 一个具体的例子

假设你要预测一批新化合物的 BACE-1 抑制活性:

  • 如果新化合物也是羟乙胺类 → 模型可用,预期 MAE 约 0.5–0.8 个对数单位;
  • 如果新化合物是别类骨架(例如酰胍类、螺环类)→ 模型基本失效,得用 scaffold 划分重新评估才知道有多差。

这就是为什么 §5 强调 scaffold 划分:它模拟的正是「面对新骨架」这个真实场景。

§27.3 怎么检测偏移

最实用的做法:算特征空间的分布距离。

from scipy.spatial.distance import jensenshannon
import numpy as np

# 对每个核心特征,算训练集与测试集的 JS 散度
for col in CORE:
    h1, edges = np.histogram(tr[col], bins=30, density=True)
    h2, _     = np.histogram(te[col], bins=edges, density=True)
    js = jensenshannon(h1 + 1e-9, h2 + 1e-9)
    print(f"{col:45s} JS={js:.3f}")

JS 散度 > 0.3 的列,说明分布差异显著。如果核心特征里有 5 列以上 JS 很高,你的「测试集」实际上不是同分布——分数低是正常的,不该归咎于模型。


§28 与 DeepChem 生态的关系

BACE 之所以流行,很大程度是因为 DeepChem 把它做成了「一行代码」。

§28.1 DeepChem 在分子 ML 里的位置

DeepChem 是 2016 年随 Subramanian 论文一起发布的开源库。它的定位是「分子机器学习的 scikit-learn」——提供数据加载、特征化、模型、评估的完整流水线。

BACE 是它最早内置的数据集之一,也是它文档里的第一个示例。

§28.2 load_bace_classification 的完整默认值

load_bace_classification(
    featurizer='ECFP',
    splitter='scaffold',
    transformers=['balancing'],
    reload=True
)

这四个默认值每一个都会改变结果:

  • ECFP → 用圆形指纹,不用 590 列 Canvas;
  • scaffold → 严格划分(这是对的);
  • balancing → 类别平衡(影响 accuracy);
  • reload=True → 用缓存(如果缓存坏了,结果会错且不报错)。

建议:第一次用时把 reload=False 跑一遍,确认真拿到数据。

§28.3 三个替代加载器

TorchDrug:

from torchdrug import datasets
bace = datasets.BACE("~/data")

它的 url 指向 deepchem.io.s3-website-us-west-1.amazonaws.com(http,非 https),MD5 期望 ba7f8fa3fdf463a811fa7edea8c982c2。这个 URL 可能已经失效(实测无响应)。

PyTorch Geometric / OGB:不直接提供 BACE,需要自己转。

scikit-fingerprints:Hugging Face 上有镜像 scikit-fingerprints/MoleculeNet_BACE,1,513 行。

注意:这些加载器返回的行数不一致(1,513 或 1,522),选一个并说明。


§29 最终判断:该不该把 BACE 放进你的训练集

分三种用途回答。

§29.1 用途一:作为「预训练语料」

不该。 1,513 个分子放进去,只会被百万级的别的数据淹没,而且它的化学空间与通用化学空间不同——反而可能引入偏倚。

§29.2 用途二:作为「下游评测任务」

该,但只作为一整套任务中的一个。 单独报 BACE 的结果说服力不足,因为:

  • 规模太小,分数抖动大;
  • 化学空间窄,高分不代表泛化;
  • 数据噪声已知(9 组重复、2 组冲突)。

建议配置:BACE + BBBP + Tox21 + SIDER + ClinTox + MUV + HIV(MoleculeNet 的七件套),或者 TDC 的 ADMET 组。

§29.3 用途三:作为「教学与调试」

最该。 它的三个优点无法替代:

  • 小:全流程几十秒;
  • 有连续标签:能同时练回归与分类;
  • 有明确的已知坑:9 组重复、划分方式、标签冲突——正好用来教「数据质量比模型重要」。

§30 三条硬约束(终版)

  1. 1,522 条记录 / 1,513 个唯一 SMILES。9 组 SMILES 各出现两次,其中 2 组 Class 直接冲突、3 组跨训练/测试集合——前者是标签噪声的硬下界,后者是潜在的划分泄漏。不说明这一点,你的复现数就与别人对不上。
  2. Model 列不是 scaffold 划分。它反映 Subramanian 原论文的「内部 249 条训练 / 外部 1,273 条测试」设计,Test 占 83.6%。MoleculeNet 推荐的基准口径是 scaffold 划分 + AUROC,DeepChem 默认也是 scaffold。报数必须写明用的是哪一套。
  3. bace.csv 已不完整(实测 623 行),只有 desc_canvas_aug30.csv 是完整的 1,522 行;且 590 列描述符由 ChemAxon Canvas 计算,不是 RDKit——换工具重算数值不一致,想对齐官方 baseline 必须用原样预计算值。

§31 修订记录与取证说明

§31.1 本条每个数字的来源

数字 来源 核法
1,522 行 / 595 列 desc_canvas_aug30.csv pandas.read_csv() 实测 shape
文件 3,921,122 B S3 响应头 Content-Length curl -sIL
1,513 唯一 SMILES 同上 csv df['mol'].nunique()
Class 697 / 825 同上 value_counts()
pIC50 六项统计 同上 describe()
MW / AlogP / PSA / RB 范围 同上 min() / max() / mean()
Model 分布 204 / 45 / 1,273 同上 value_counts()
9 组重复 SMILES 及逐组差异 同上 duplicated('mol', keep=False) 后 groupby
bace.csv 623 行 同上(下载实测) shape[0],1,618,565 B
bace.csv MD5 = 9a512f... 同上 md5sum
期望 MD5 = ba7f8f... TorchDrug 源码 源码内 md5 = "..." 常量
scaffold 推荐 / AUROC 推荐 MoleculeNet 论文 Table 1 与 3.1.11 节 WebFetch 原文摘句
Subramanian 2016 出处 MoleculeNet 参考文献 51 与期刊页面交叉确认
DeepChem 三处默认值 deepchem.readthedocs.io 的 molnet 页 WebFetch 原文
回归版 1522 / 分类版 1513 DeepChem 文档两处 docstring 原文对比

§31.2 本条未核到的

项 情况 处理
逐条数据的原始文献出处 官方不提供「这条来自哪篇论文」的映射 不编。只说「来自文献汇总」
Subramanian 汇总的纳入/排除标准 论文正文未给完整规则 从结果反推三条事实(§25.3),并明写是反推
数据集许可 官方未声明 DAIMS 第 3 项给 0 分并说明原因
版本号 / 发布日期 官方没有 DAIMS 第 2 项给 0 分;建议用 MD5 锁定
Class 的判定阈值 官方未公布 从分布反推「约在 pIC50 ≈ 7」,并说明有例外(1 条 pIC50=2.699 却标 1)
bace.csv 为何只剩 623 行 无公开说明 只陈述实测事实,不猜测原因

§31.3 一处需要后续核实的观察

bace.csv 的 623 行恰好是 desc_canvas_aug30.csv 的一个子集(623 个 CID 全部能在 1,522 行里找到),且其 Model 分布是 Train 203 / Valid 45 / Test 375。

这个 623 不是随机抽样——它保留了 Valid 的 45 条和几乎全部 Train(203/204),只截掉了 Test 的 1,273 条中的大部分(保留 375)。看起来像是下载过程被截断,而不是文件被有意修改。

但这只是推断。 在官方给出说明前,任何解释都只能是猜测。实际使用请坚持用 desc_canvas_aug30.csv。

§31.4 与上一版的差异

本条目为首次入库,无上一版。若日后 MoleculeNet 或 DeepChem 更新了 BACE 的托管版本,需要复核的项是:行数(1,522)、唯一 SMILES 数(1,513)、bace.csv 的完整性、以及 9 组重复 SMILES 是否被修复。

如果将来 9 组重复被清洗掉了,那说明上游改过数据——这会让所有历史分数失去可比性。 这正是「无版本号」这个缺陷的实际代价。

§31.5 给下游使用者的一句提醒

如果你只打算从这篇里带走一句话,带走这句:这份数据最大的价值不是 1,513 个分子,而是它把一个真实问题完整暴露了出来——同一结构可以有不同的实测活性、同一标签可以由不同判据决定、同一批数据可以因为划分方式不同而给出差 10 个点的分数。

这些不是这份数据的缺陷,是所有「从文献汇总出来的实验数据」的共同处境。BACE 因为小、因为被反复使用,把这层处境显示得特别清楚。用它的人如果不看这层,就只是在刷分数。


相关数据集导航

以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:

  • plumber — 共享标签:药物发现与化学 / 化学信息学 / 分子性质预测 / 虚拟筛选 / 评测基准
  • aqsoldb — 共享标签:药物发现与化学 / 化学信息学 / 分子性质预测 / 评测基准
  • chembl — 共享标签:药物发现与化学 / 化学信息学 / 分子性质预测 / 虚拟筛选
  • moleculenet — 共享标签:药物发现与化学 / 化学信息学 / 分子性质预测 / 评测基准
  • lit-pcba — 共享标签:药物发现与化学 / 化学信息学 / 虚拟筛选 / 评测基准
  • openadmet-expansionrx — 共享标签:药物发现与化学 / 化学信息学 / 分子性质预测 / 评测基准
  • qmof — 共享标签:药物发现与化学 / 化学信息学 / 分子性质预测 / 虚拟筛选
  • matbench — 共享标签:药物发现与化学 / 化学信息学 / 分子性质预测 / 评测基准
  • zinc — 共享标签:药物发现与化学 / 化学信息学 / 虚拟筛选
  • drugcentral — 共享标签:药物发现与化学 / 化学信息学 / 虚拟筛选

导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

返回 AI-Ready 数据集