分子标准化是把不同来源、不同书写方式的分子转换成统一形式的过程。不做标准化,同一个化合物可能被当成多个不同的分子——这会污染训练集、破坏去重、让数据合并出错。
需要处理的问题
| 问题 | 例子 | 后果 |
|---|---|---|
| 盐与共晶 | 盐酸盐 vs 游离碱 | 被当成不同分子 |
| 电荷形式 | COO⁻ vs COOH | 指纹不同 |
| 互变异构体 | 酮式 vs 烯醇式 | 结构表示不同 |
| 官能团的书写 | 硝基的两种画法 | 子结构匹配失败 |
| 芳香性感知 | 凯库勒式 vs 芳香式 | 通常可自动处理 |
| 立体化学 | 未指定 vs 明确指定 | 需要决定策略 |
| 同位素标记 | 氘代化合物 | 视任务决定是否保留 |
| 金属配位 | 配位键的表示 | 处理复杂 |
标准的处理流程
from rdkit import Chem
from rdkit.Chem.MolStandardize import rdMolStandardize
def standardize(smiles, keep_stereo=True, neutralize=True,
canonical_tautomer=True):
"""完整的分子标准化流程"""
mol = Chem.MolFromSmiles(smiles)
if mol is None:
return None
# ---- 1) 基本清理 ----
# 官能团的规范化(如硝基的表示)
# 去掉不必要的显式氢
# 金属离子的处理(断开配位键)
mol = rdMolStandardize.Cleanup(mol)
# ---- 2) 去掉盐/溶剂,保留最大的有机片段 ----
# CC(=O)[O-].[Na+] → CC(=O)[O-]
mol = rdMolStandardize.FragmentParent(mol)
if mol is None:
return None
# ---- 3) 中和电荷(可选)----
if neutralize:
mol = rdMolStandardize.Uncharger().uncharge(mol)
# ---- 4) 规范互变异构体(可选,较慢)----
if canonical_tautomer:
te = rdMolStandardize.TautomerEnumerator()
mol = te.Canonicalize(mol)
# ---- 5) 立体化学的处理 ----
if not keep_stereo:
Chem.RemoveStereochemistry(mol)
# ---- 6) 最终的规范 SMILES ----
return Chem.MolToSmiles(mol)
# 【或用一步到位的 API】
def standardize_simple(smiles):
mol = Chem.MolFromSmiles(smiles)
if mol is None:
return None
# 【父结构】:去盐 + 中和 + 去同位素
parent = rdMolStandardize.ChargeParent(mol)
return Chem.MolToSmiles(parent) if parent else None
关键的判断:每一步该不该做
# 【去盐:几乎总是要做】
# 例外:如果研究的性质与盐型相关
# - 溶解度(不同盐型溶解度不同)
# - 固态性质
# → 【这种情况下应该保留盐型信息作为额外特征】
#
# 【中和电荷:取决于任务】
# ✓ 做的理由:
# 统一表示,避免同一化合物的不同电荷形式被分开
# ✗ 不做的理由:
# - 【对接需要生理 pH 下的实际电荷】(见 106)
# - 静电相互作用的建模需要真实电荷
# → 【建模用中性形式,对接用生理形式】
# 两套数据分别准备
#
# 【互变异构体规范化:谨慎】
# ✓ 做的理由:
# 酮式与烯醇式是同一化合物
# ✗ 风险:
# - 【RDKit 选择的「规范」形式
# 未必是实际占优的形式】
# - 可能改变氢键供受体的角色
# - 计算较慢
# → 【用于去重与匹配时做;
# 用于对接与三维建模时要小心】
#
# 【立体化学:取决于数据】
# ✓ 保留:数据中明确标注了立体化学
# ✗ 去掉:
# - 数据中大部分未标注(避免不一致)
# - 任务与立体化学无关
# → 【混合标注与未标注的数据是常见问题】
# 应该统一策略
#
# 【最重要的一条】:
# 【无论选什么策略,都要在整个项目中保持一致,
# 并明确记录】
# → 不一致的标准化,比不标准化更糟
批量处理与质量检查
import pandas as pd
from collections import Counter
def standardize_dataset(df, smiles_col="smiles", **kwargs):
"""批量标准化并报告统计"""
results, failures = [], []
for i, smi in enumerate(df[smiles_col]):
std = standardize(smi, **kwargs)
if std is None:
failures.append((i, smi))
results.append(std)
df = df.copy()
df["std_smiles"] = results
print(f"总数: {len(df)}")
print(f"【标准化失败: {len(failures)}】")
if failures:
print(" 失败示例:", failures[:3])
valid = df.dropna(subset=["std_smiles"])
print(f"唯一分子数: {valid['std_smiles'].nunique()}")
dup = len(valid) - valid["std_smiles"].nunique()
print(f"【标准化后发现 {dup} 个重复】")
# 【检查标准化改变了什么】
changed = valid[valid[smiles_col].apply(
lambda s: Chem.CanonSmiles(s) if Chem.MolFromSmiles(s) else None
) != valid["std_smiles"]]
print(f"标准化改变了 {len(changed)} 个分子")
return df, failures
# 【必做的检查】:
# 1) 【标准化前后的分子式是否一致?】
# 去盐会改变分子式(这是预期的)
# 但如果非预期地改变,说明有问题
#
# 2) 【抽样人工检查】
# 随机取 20 个标准化改变了的分子,
# 画出前后对比,确认改变是合理的
#
# 3) 【记录标准化的版本与参数】
# RDKit 版本、使用的选项
# → 【不同版本的结果可能不同】
def verify_standardization(before, after, n_sample=20):
from rdkit.Chem import Draw
import random
pairs = [(b, a) for b, a in zip(before, after)
if a and Chem.CanonSmiles(b) != a]
sample = random.sample(pairs, min(n_sample, len(pairs)))
mols, legends = [], []
for b, a in sample:
mols += [Chem.MolFromSmiles(b), Chem.MolFromSmiles(a)]
legends += ["原始", "标准化后"]
return Draw.MolsToGridImage(mols, molsPerRow=4, legends=legends)
ChEMBL Structure Pipeline
# ChEMBL 团队开源了他们的标准化流程
# → 与 ChEMBL 数据库的处理一致
# → 【如果你的数据来自 ChEMBL,用它能保证一致性】
# pip install chembl_structure_pipeline
from chembl_structure_pipeline import standardizer, checker
def chembl_standardize(molblock):
# 标准化
std = standardizer.standardize_molblock(molblock)
# 提取父结构(去盐)
parent, exclude = standardizer.get_parent_molblock(std)
return parent, exclude
# 【checker 模块】:检查结构问题
# issues = checker.check_molblock(molblock)
# 返回问题列表与严重程度
# → 【可以用来自动标记可疑结构】(见 048)
# 【选择建议】:
# 数据来自 ChEMBL → 用 ChEMBL Structure Pipeline
# 其它来源 → RDKit MolStandardize 通常够用
# 【关键是一致性,而非用哪个工具】
关键要点
- 建模用中性形式,对接用生理 pH 下的实际电荷——两套数据分别准备;
- 互变异构体规范化要谨慎——RDKit 选的「规范」形式未必是实际占优的;
- 无论选什么策略都要全项目一致并记录——不一致比不标准化更糟;
- 标准化后抽样人工检查改变了的分子,确认改变合理。
延伸资源
- 去盐去重:047《去盐与去重复》;异常结构识别:048《异常结构识别》;InChI:033《InChI 与 InChIKey》;
- RDKit:013《RDKit Cookbook》;ChEMBL:226《ChEMBL》;QSAR:044《QSAR 入门》。