「这个分子好不好合成」有多种量化方式,各自的原理与含义不同。选错指标会导致系统性的偏差——比如惩罚了本来容易合成的新颖结构。
三个指标的原理对比
| SA Score | SCScore | RAScore | |
|---|---|---|---|
| 提出 | 2009 | 2018 | 2021 |
| 原理 | 片段频率 + 复杂度惩罚 | 从反应数据学「产物比反应物复杂」 | 用逆合成求解结果训练的分类器 |
| 训练数据 | PubChem 片段统计 | Reaxys 反应对 | ChEMBL + AiZynthFinder 求解结果 |
| 输出 | 1(易)~10(难) | 1(简单)~5(复杂) | 0~1 的可解概率 |
| 速度 | 极快 | 快 | 快 |
| 直接对应 | 「片段常见程度」 | 「合成复杂度」 | 「能否找到路线」 |
SA Score:最快但最粗
from rdkit import Chem, RDConfig
import sys, os
sys.path.append(os.path.join(RDConfig.RDContribDir, "SA_Score"))
import sascorer
mol = Chem.MolFromSmiles("CC(=O)Oc1ccccc1C(=O)O")
print(f"SA Score: {sascorer.calculateScore(mol):.2f}")
- 原理:分子中的片段在 PubChem 中越常见,分数越低(越易合成);再加上手性中心、螺环、桥环、大环、尺寸的复杂度惩罚。
- 优点:毫秒级,可用于生成模型的每一步打分;
- 关键缺陷:它衡量的是「片段常见程度」而非「合成可行性」。一个用常规反应就能做出来、但骨架少见的分子,SA Score 会偏高——这系统性地惩罚了新颖性。
SCScore:基于反应数据的复杂度
# 从 ASKCOS 或独立仓库获取
# 训练思路:在 Reaxys 反应中,产物通常比反应物「更复杂」
# 用这个偏序关系训练一个神经网络打分器
from scscore.standalone_model_numpy import SCScorer
model = SCScorer()
model.restore()
smi = "CC(=O)Oc1ccccc1C(=O)O"
print(f"SCScore: {model.get_score_from_smi(smi)[1]:.3f}")
- 优点:基于真实反应数据,比片段频率更贴近合成逻辑;能反映「构建这个分子需要多少合成努力」。
- 局限:仍不考虑起始原料可得性;训练目标是相对复杂度而非绝对可合成性。
RAScore:直接预测「能否找到路线」
pip install rascore
from RAScore import RAScore_XGB
scorer = RAScore_XGB.RAScorerXGB()
smi = "CC(=O)Oc1ccccc1C(=O)O"
print(f"RAScore: {scorer.predict(smi):.3f}") # 0~1
- 原理:用 AiZynthFinder 对大量 ChEMBL 分子跑逆合成,把「能否找到完整路线」作为标签训练分类器。它是逆合成结果的快速代理。
- 优点:直接对应实际关心的问题(能否合成);速度快,可用于大规模筛选;
- 局限:继承了 AiZynthFinder 的偏差(模板库覆盖、库存定义);训练数据是 ChEMBL 分子,对差异很大的化学空间外推能力有限。
三者的相关性与差异
import pandas as pd
import numpy as np
# 对同一批分子算三个分数,看它们的一致性
df = pd.DataFrame({
"smiles": smiles_list,
"sa": [sascorer.calculateScore(Chem.MolFromSmiles(s)) for s in smiles_list],
"sc": [scscorer.get_score_from_smi(s)[1] for s in smiles_list],
"ra": [rascorer.predict(s) for s in smiles_list],
})
print(df[["sa", "sc", "ra"]].corr(method="spearman"))
# 典型观察:
# 三者的相关性中等(Spearman 常在 0.5~0.7)
# → 它们衡量的确实是不同的东西
#
# 分歧最有信息量的情况:
# SA 高但 RA 高(片段少见但能找到路线)
# → 新颖但可合成的结构,SA Score 误判了
# SA 低但 RA 低(片段常见但找不到路线)
# → 可能是起始原料不可得或需要特殊反应
选择建议
| 场景 | 推荐 | 理由 |
|---|---|---|
| 生成模型的每步打分 | SA Score | 只有它足够快 |
| 生成后的批量初筛 | RAScore | 直接对应可合成性 |
| 候选精选(top 100) | 实际跑逆合成 | 最可靠 |
| 比较分子的合成复杂度 | SCScore | 基于反应数据 |
| 最终决策 | 合成化学家评审 | 不可替代 |
分级使用的实际流程
# 生成阶段(每步都算,需要毫秒级)
# → SA Score,用平滑 transform 而非硬阈值
# 生成后初筛(几千个分子)
# → RAScore > 0.5 作为过滤
# 候选评估(几百个)
# → AiZynthFinder 实际跑逆合成(见 385)
# 看 is_solved 与 n_steps
# 最终确认(几十个)
# → 合成化学家评审路线可行性与成本
# → 这一步的通过率是所有前面步骤质量的真实检验
# 记录反馈:
# 把化学家的判断与各分数对比,
# 校准哪个分数在自家化学空间上最可靠
用自家数据校准
# 通用阈值不一定适合你的团队
import numpy as np
# 拿公司历史上真正合成过的分子算分数分布
historical = [sascorer.calculateScore(Chem.MolFromSmiles(s))
for s in synthesized_compounds]
print(f"历史合成分子 SA 分布:")
print(f" 中位数 {np.median(historical):.2f}")
print(f" 90 分位 {np.percentile(historical, 90):.2f}")
# 用 90 分位作为阈值,比照搬通用的 6.0 更贴合实际
# 不同公司的合成能力不同,阈值也应不同
# 更好的做法:
# 收集「设计了但最终没做出来」的分子,
# 看它们的分数分布 —— 这是真正的负样本
关键要点
- SA Score 衡量片段常见程度,会系统性惩罚新颖但易合成的结构;
- RAScore 直接预测「能否找到路线」,最贴近实际关心的问题;
- 三者相关性只有中等,分歧之处最有信息量;
- 用自家历史合成分子校准阈值,比照搬通用值合理得多。
延伸资源
- 生成约束:348《在分子生成中加入 SA Score 约束》;逆合成工具:385《AiZynthFinder》、386《ASKCOS》;
- 采购:232《Mcule》、233《eMolecules》。