3. 分子指纹与相似性计算
分子指纹是把一个二维分子结构压缩成固定长度或稀疏位串的编码方式。它不保留完整的原子坐标,却能在毫秒级完成“这个分子像不像那个分子”的判断,因此成为虚拟筛选、去重、聚类和库设计的基础设施。本节围绕三类最常用的 RDKit 指纹展开:ECFP(扩展连接指纹)、MACCS(分子访问系统结构键)以及 RDKit 默认拓扑指纹,并说明如何用 Tanimoto 系数把它们变成可排序、可聚类、可挑选的相似性度量。
三类指纹的编码逻辑与适用场景
ECFP 属于圆形指纹。以 ECFP4 为例,半径参数 radius=2,意味着从每个重原子出发,向外扩展两个化学键范围,把“原子—邻居—邻居的邻居”这一局部环境哈希成一个整数,再折叠到指定位长(常用 2048 位)。它捕捉的是子结构环境,对骨架相似、取代基不同的类似物非常敏感,适合相似性搜索和 SAR 分析。MACCS 则是 166 位的结构键指纹,每一位对应一条人工定义的 SMARTS 式结构规则,例如“是否存在苯环”“是否存在羧酸”“是否含氮杂环”。它的可解释性强,但分辨率有限,更适合快速粗筛和结构类别统计。RDKit 默认的 Morgan 指纹与 ECFP 同源,但允许通过 useFeatures=True 切换为药效团特征指纹(如供体、受体、芳香环、疏水中心),在配体相似性比较中更贴近生物活性。
生成指纹的代码非常直接,但参数选择决定了后续所有计算的含义:
from rdkit import Chem
from rdkit.Chem import AllChem, MACCSkeys, RDKFingerprint
mol = Chem.MolFromSmiles('CC(=O)Oc1ccccc1C(=O)O') # 阿司匹林
# ECFP4 / Morgan,半径2,2048位
fp_ecfp = AllChem.GetMorganFingerprintAsBitVect(mol, radius=2, nBits=2048)
# MACCS 166位
fp_maccs = MACCSkeys.GenMACCSKeys(mol)
# RDKit 拓扑指纹,默认路径长度1-7
fp_rdk = RDKFingerprint(mol)
注意 GetMorganFingerprintAsBitVect 返回的是位向量,适合做集合运算;若需要计数型指纹(同一子结构出现多次则计数增加),应使用 GetMorganFingerprint 配合 GetNonzeroElements。计数型指纹在重复片段较多的分子(如糖苷、聚合物)上比二进制指纹更稳健。
Tanimoto 相似度:从位串到可比较的数值
Tanimoto 系数定义为两个位向量交集大小除以并集大小:T = |A ∩ B| / |A ∪ B|。对二进制指纹,它等价于共同为 1 的位数除以至少一个为 1 的位数。取值范围 0 到 1,1 表示完全相同。RDKit 提供了 DataStructs.TanimotoSimilarity 和批量计算接口 BulkTanimotoSimilarity,后者在库级搜索中能显著减少 Python 循环开销。
经验阈值方面,ECFP4 下 Tanimoto ≥ 0.85 通常视为高度相似(同一骨架的类似物),0.6~0.85 为中等相似(可能共享药效团),低于 0.4 一般视为不同化学系列。这些阈值不是绝对标准,应结合具体库的分布来校准。一个实用做法是先计算库内随机分子对的相似度分布,取 95 分位数作为“显著相似”的参考线。
相似性搜索与聚类
相似性搜索的典型任务是:给定一个查询分子,在 N 个化合物的库中找出最相似的 K 个。直接两两计算复杂度为 O(N),对百万级库仍可接受,但更高效的方式是先用 MACCS 或短位长 ECFP 做粗筛,再用 ECFP4 精排。RDKit 的 SimilarityMaps 和 rdFingerprintGenerator 模块支持生成器复用,避免重复构建指纹对象。
聚类则把“两两相似”转化为“分组”。常用方法有两种:Butina 聚类基于距离阈值做层次聚类,适合把库切成若干相似簇;Taylor-Butina 变体通过设定距离 cutoff(如 1 - Tanimoto = 0.3)控制簇的紧密度。另一种是 K-means 对指纹做降维后聚类,但二进制指纹的欧氏距离解释性不如 Tanimoto 直观,因此化学信息学中更常用 Butina。
多样性挑选:从聚类结果到实际库设计
多样性挑选的目标是用尽量少的分子覆盖尽量大的化学空间。常见策略是“聚类后每簇取代表”:先对库做 Butina 聚类,再在每个簇中选择与簇内其他成员平均相似度最高、或分子量/LogP 最接近簇中心的分子作为代表。另一种是 MaxMin 算法:每次选择与已选集合最小距离最大的分子,迭代直到达到目标数量。两种方法都依赖同一个相似度矩阵,区别在于是否显式聚类。
在真实化合物库中,这些步骤通常组合成一条流水线:清洗结构(去盐、标准化电荷)→ 生成 ECFP4 指纹 → 计算 Tanimoto 矩阵 → Butina 聚类 → 每簇选代表 → 人工检查结构多样性。对于 10 万级库,Tanimoto 矩阵约 5×10⁹ 个元素,直接存储不现实,因此实际实现中常用稀疏矩阵或分块计算,或先用 MACCS 粗筛把候选集降到几千个再精算。
实操中的判断依据与常见陷阱
第一,指纹位长不是越大越好。2048 位在多数药物分子库上已足够,位长过大反而稀释相似信号,使 Tanimoto 值整体偏低。第二,MACCS 只有 166 位,两个结构差异较大的分子也可能因为共享若干通用片段而得到 0.5 以上的相似度,因此 MACCS 适合粗筛,不适合精细排序。第三,ECFP 的半径参数需要与任务匹配:radius=1 更关注原子邻域,radius=3 会引入更大的环境,可能把同系列但取代基位置不同的分子判为不相似。第四,聚类前应检查库中是否存在重复结构或盐形式,否则同一化合物的不同盐会被分到不同簇,浪费多样性配额。
把上述步骤串起来,一个可复现的最小工作流是:读入 SDF → 用 Chem.MolFromSmiles 或 Chem.SDMolSupplier 解析 → 去盐并标准化 → 生成 ECFP4 位向量 → 用 BulkTanimotoSimilarity 计算查询分子与库的相似度 → 排序取 Top-K → 对 Top-K 做 Butina 聚类 → 每簇选一个代表。这条链路既可用于单次相似性搜索,也可用于构建一个覆盖化学空间多样性的筛选库。