第2章 分子指纹简介:MACCS、ECFP、FCFP 等常见指纹
做药物相似性计算,第一个绕不开的东西就是分子指纹。说白了,就是把一个分子——通常是个 SMILES 字符串或者 Mol 对象——转成一组0和1组成的向量。这个向量能告诉你分子里有没有某些结构片段、原子环境、或者拓扑特征。
我入行那会儿,公司老系统还在用 MDL 格式的固定长度指纹,后来才慢慢换到 ECFP、FCFP 这些。这几年做图神经网络,又经常把分子指纹作为节点特征输入 GNN。所以不管你是做传统相似性搜索还是做深度学习,这几种指纹都得吃透。
2.1 什么是分子指纹?
分子指纹本质上是分子结构的编码。早期化学家手动画分子时,全靠直觉判断两个化合物像不像。后来有了指纹编码,机器就能做高速对比了。
常见的做法是:把分子里的所有子结构(比如某个官能团、某条路径)枚举出来,再通过哈希或者预定义字典,映射到固定长度的位串。位串上的每一位代表一个结构特征存不存在(1表示有,0表示没有)。
你想想看,两个分子的指纹位串越相似,它们的 Tanimoto 系数越接近1,我们就说它们越相似。这也是后面相似性计算的基础。
核心概念:分子指纹 = 分子结构 → 比特向量(bit vector)
2.2 MACCS 指纹
MACCS 全称是 Molecular ACCess System,早年由 MDL 公司(现在属于 BIOVIA)开发。它使用一套固定的 166 个结构键(structural keys),每个键代表一个 predefined 的官能团或亚结构。
特点:
- 固定长度:最常见的版本是 166 位,也有 960 位版。一般说 MACCS 默认指 166 位。
- 预定义字典:每个位对应一个 SMARTS 模式,比如位1代表“含有卤素”,位42代表“含有芳环”等等。
- 可解释性强:你能直接查出某一位对应什么结构。
- 适用于骨架相似性:因为只检测预定义片段,对整体骨架变化敏感。
使用场景:早期虚拟筛选、公共数据库(如 PubChem)的快速过滤。我曾在一次项目中用 MACCS 做初筛,几百万个分子几分钟就跑完,配合 Tanimoto 系数直接淘汰掉一堆不相关的。
缺点:因为位点少,对微小结构变化(比如手性、同位素)不敏感。而且有些分子含有 MACCS 字典里没有的片段就会全零,这就尴尬了。
我的避坑经验: 千万不要在不对称催化筛查里只用 MACCS。我试过一次,两个手性异构体的 MACCS 指纹一模一样,Tanimoto 系数 1.0,但活性差 100 倍。必须配合 ECFP 这类拓扑指纹才能区分。
2.3 ECFP 指纹
ECFP 全称是 Extended-Connectivity Fingerprints,由 Rogers 和 Hahn 在 2010 年提出(RDKit 里有现成实现)。它不依赖预定义字典,而是根据分子中每个原子的局部环境来生成特征哈希到位串。
核心机制:
- 对每个非氢原子,提取它的特征(如元素类型、原子序数、电荷、连接度等)作为初始片段。
- 然后向外扩展半径(默认 2 圈),每扩展一圈就把邻居原子的特征哈希进去,生成新的片段标识。
- 最后把这些片段标识通过哈希函数映射到固定长度的位串(默认 2048 位)。
常见变体:
- ECFP0:半径 0,只考虑原子本身特征。
- ECFP2:半径 1,考虑原子及其直接邻居。
- ECFP4:半径 2(业界最常用)。
- ECFP6:半径 3。
为什么常用 ECFP4?
我在做化合物库多样性分析时对比过:ECFP4 对局部结构(比如官能团类型、取代模式)非常敏感,同时不会因为远离中心的变化(比如长烷基链的微小摆动)导致指纹剧变。这是个很好的平衡。
代码示例(Python + RDKit):
from rdkit import Chem
from rdkit.Chem import AllChem
mol = Chem.MolFromSmiles('c1ccccc1C(=O)O')
fp = AllChem.GetMorganFingerprintAsBitVect(mol, radius=2, nBits=2048)
# fp 是一个 DataStructs ExplicitBitVect 对象
# 可以用 fp.ToBitString() 查看位串
bit_string = fp.ToBitString()
print(len(bit_string)) # 2048
2.4 FCFP 指纹
FCFP 跟 ECFP 的算法逻辑一模一样,唯一的区别是原子特征的定义方式不同。ECFP 使用“原子拓扑特征”(反映化学环境),而 FCFP 使用“药效团特征”。
药效团特征包括:
- 氢键供体
- 氢键受体
- 正电性/负电性
- 芳香性
- 疏水性
- 等等
这意味着 FCFP 更关注分子中与药物-靶标相互作用相关的功能团分布。如果做基于药效团的虚拟筛选,FCFP 效果往往好于 ECFP。
我有个经验:做激酶抑制剂亲和力预测时,FCFP4 加 GNN 的组合经常比纯 ECFP4 提升 3-4% 的 AUC。因为激酶抑制剂通常需要特定的氢键和芳香作用。
注意: 不同的 RDKit 版本生成 FCFP 时药效团特征定义可能微调,导致同一分子得到不同指纹。建议固定 RDKit 版本号(比如 2023.03.1),否则在发表论文或复现时会踩坑。
2.5 其他常见指纹
除了 MACCS、ECFP、FCFP,还有一些指纹也值得了解:
| 指纹类型 | 长度 | 描述 | 典型应用 |
|---|---|---|---|
| RDKit 指纹 | 2048(默认) | 基于子图枚举,默认路径长度 1-7 | 一般相似性搜索 |
| AtomPair 指纹 | 可变 | 编码原子对的距离(拓扑距离)和特征 | 配体相似性分析 |
| Torsion 指纹 | 可变 | 编码可旋转键的二面角模式 | 构象相似性 |
| MAP 指纹 | 2048(默认) | 类似 ECFP,但使用更精确的原子特征哈希 | 深度学习特征输入 |
我的建议: 如果做传统筛选,首选 ECFP4(2048 位)配合 Tanimoto。如果做药效团过滤,先试 FCFP4。如果需要可解释性(比如向化学家解释结果),用 MACCS 是很好的选择,虽然精度差一些但一眼能看懂。
2.6 指纹生成的常见陷阱
我在项目里见过好多新手栽跟头,列几个你千万注意:
- SMILES 不规范:同一分子的不同 SMILES 写法(如正写/标准凯库勒)可能导致指纹不同。一定要用 RDKit 的
Chem.MolFromSmiles后再Chem.MolToSmiles得到规范 SMILES。 - 氢原子处理:ECFP 和 FCFP 默认排除氢原子。如果显式添加氢(
Chem.AddHs),指纹会不同。保持一致即可。 - 哈希冲突:2048 位里多个片段映射到同一位的概率虽然低,但不是零。有些场景(比如专利圈地)需要确定性,可以考虑转成整数列表。
- 大规模速度:不要循环调用
GetMorganFingerprintAsBitVect逐个处理。可以用AllChem.GetHashedMorganFingerprint批量操作,或者用多进程。
一句话总结: MACCS 给骨架,ECFP 给局部细节,FCFP 给药用功能,三者互补。别只用一种,尤其是做模型时多种指纹拼接往往效果更好。