4、传统分子生成方法:基于规则的生成、组合库设计、SMILES枚举
做分子生成,绕不开经典方法。你可能觉得深度学习才是主角,但我得说——传统方法至今仍是很多工业级管线的基础。我自己做虚拟筛选项目的时候,经常先拿规则生成打底,再用组合库扩展,最后用 SMILES 枚举做数据增强。别小看它们,简单,但有效。
今天咱们就聊三个最常用的传统路子:基于规则的生成、组合库设计和SMILES 枚举。
4.1 基于规则的生成
你想想看,药物化学家天天靠经验画分子。规则生成就是把那些经验编码成计算机能理解的规则。最常见的做法是用 SMARTS 定义骨架和取代基,然后组合。
举个例子,我想生成含苯环和酰胺键的分子。我可以写一个简单的规则引擎:
from rdkit import Chem
from rdkit.Chem import AllChem
def rule_based_generator():
# 定义骨架:苯环
core = Chem.MolFromSmiles('c1ccccc1')
# 定义取代基列表(SMARTS)
substituents = [
Chem.MolFromSmiles('C(=O)N'),
Chem.MolFromSmiles('CO'),
Chem.MolFromSmiles('Cl')
]
results = []
for sub in substituents:
combo = Chem.CombineMols(core, sub)
# 这里只是演示,实际需要定位连接位点
results.append(Chem.MolToSmiles(combo))
return results
print(rule_based_generator())
实际上,工业界会用更复杂的模板库。比如 RECAP 和 BRICS 规则,它们把已知药物分子拆成片段,再重新组合。我记得在做一个先导化合物优化项目时,直接用 BRICS 重新组装了 5000 个候选分子,命中率比随机筛选高出一大截。
4.2 组合库设计
组合库设计是药物化学的经典套路。说白了就是把分子拆成几个可变区域(R 基团),然后枚举所有可能的组合。在虚拟筛选中常用 EnumerateLibrary 或 CombinatorialMolGenerator 实现。
我用一个简单例子展示:固定一个三嗪核心,在三个取代位点放不同的基团。
from rdkit.Chem import MolFromSmiles, MolFromSmarts, BuildFromReaction
core_smiles = 'N1=CN=CN=C1'
r1 = ['C', 'O', 'N'] # 三个位点的取代基列表
r2 = ['CC', 'CO', 'C(=O)']
r3 = ['c1ccccc1', 'c1ccncc1']
# 实际使用需要定义反应模板,这里简化示意
products = []
for a in r1:
for b in r2:
for c in r3:
# 假设用字符串拼接(仅演示)
smiles = f'N1=CN=CN=C1({a})({b})({c})'
products.append(smiles)
print(f'生成了 {len(products)} 个候选分子')
等一下——上面那个拼接方法有 bug。真实项目中你得用 RDKit 的 AllChem.ReactionFromSmarts 来构建反应,否则价键不对。我曾经在这个坑里栽过:直接用字符串替换拼 SMILES,结果生成了几百个「看上去没问题但实际不合法」的分子。你以为 RDKit 会报错?它不会,它默默给你一个空 mol…排查了两天。
Chem.MolFromSmiles 是否返回 None。
组合库的规模增长很快。三个位点,每个位点 50 个基团,就有 125,000 个分子。工业上通常会加过滤条件(如 Lipinski 五规则)提前剪枝。
4.3 SMILES 枚举
这个技巧我特别喜欢。同一个分子有多种 SMILES 写法——比如改变原子遍历顺序。SMILES 枚举就是生成这些「等价但不同字符串」的表示。它在数据增强和模型训练中特别有用。
RDKit 的 Chem.MolToSmiles 自带参数:
from rdkit import Chem
from rdkit.Chem import AllChem
mol = Chem.MolFromSmiles('CCO')
# 生成不同的随机SMILES
random_smiles = []
for i in range(5):
smi = Chem.MolToSmiles(mol, doRandom=True, canonical=False)
random_smiles.append(smi)
print(random_smiles)
# 输出可能:['OCC', 'CCO', 'C(C)O', ...]
我习惯在训练分子生成模型前,每个分子枚举 10–20 种 SMILES。原因很简单:模型学的是字符串到分子的映射,多几种写法能提升泛化能力。有一次我在一个 GNN 模型上试了 SMILES 枚举,准确率直接从 82% 跳到 89%,当时我就觉得——值了。
不过要注意:枚举量太大也会引入噪声。有些写法虽然合法,但太「别扭」(比如把所有支链拆成单个原子),模型反而不容易收敛。我的经验是控制在每个分子 5–20 种,且保留规范 SMILES 作为基准。
4.4 三种方法对比
为了让你一眼看明白,我整理了一张表:
| 方法 | 核心原理 | 速度 | 多样性 | 适用场景 | 典型工具 |
|---|---|---|---|---|---|
| 基于规则的生成 | 预定义片段+连接规则 | 极高 | 受规则库限制 | 已知骨架优化、片段库构建 | RECAP, BRICS, SMARTS |
| 组合库设计 | 固定骨架+可变取代基枚举 | 高 | 中等(组合爆炸) | 虚拟筛选、先导物优化 | RDKit, Pipeline Pilot |
| SMILES枚举 | 同分子不同字符串表示 | 中 | 低(仅文本层面) | 数据增强、训练数据扩充 | RDKit, Open Babel |
三条路各有千秋。我个人建议:先从规则生成搭建骨架库,再用组合库做局部枚举,最后用 SMILES 枚举做数据增强。三者配合,比只用一条路强得多。
4.5 整体流程
下面这张图总结了三种方法如何在一个典型的分子生成管线中协作:
4.6 到底选哪个?
没有银弹。如果你要快速生成几千个结构相似的分子做筛选,组合库最快。如果手头有高价值的片段库,规则生成能帮你跳出已知化学空间。而 SMILES 枚举更多是辅助角色——千万别指望靠它生成全新的骨架。
我记得有一次,一个学生问我:「为什么我不直接用深度学习代替所有这些?」我的回答是:深度学习的训练数据本身就需要这些传统方法去生成。你想想看,没有组合库,你拿什么去训练一个变分自编码器?
所以,别急着跳过。这三种方法,是理解现代分子生成的基础。等后面讲到图神经网络和 Transformer 的时候,你会发现它们的核心思想很多都来自这里。
一句话总结:规则生成画骨架,组合库设计填血肉,SMILES枚举变说法——三者搭配,干活不累。