第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 里有现成实现)。它不依赖预定义字典,而是根据分子中每个原子的局部环境来生成特征哈希到位串。

核心机制:

  1. 对每个非氢原子,提取它的特征(如元素类型、原子序数、电荷、连接度等)作为初始片段。
  2. 然后向外扩展半径(默认 2 圈),每扩展一圈就把邻居原子的特征哈希进去,生成新的片段标识。
  3. 最后把这些片段标识通过哈希函数映射到固定长度的位串(默认 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 给药用功能,三者互补。别只用一种,尤其是做模型时多种指纹拼接往往效果更好。

分子指纹常见类别与关系 分子指纹 固定键指纹 拓扑指纹 药效团指纹 MACCS (166位) RDKit子图 ECFP4 AtomPair FCFP4 MAP 核心区别 固定键 → 预定义字典;拓扑 → 原子环境扩展;药效团 → 物化特性 实际项目中常将 MACCS + ECFP4 拼接作为特征 长度:MACCS(166) | ECFP4(2048) | FCFP4(2048) | AtomPair(可变)