☰
RDKit FingerprintUtils 深度解析:分子数据库指纹构建、分层预筛与反序列化机制
2026/10/13 12:22:21 网站建设 项目流程
  • 科学计算
  • 科研
  • 机器学习

【免费下载链接】rdkit

The official sources for the RDKit library

项目地址:https://gitcode.com/gh_mirrors/rd/rdkit
点击查看免费下载

rdkit.Chem.MolDb.FingerprintUtils是 RDKit 分子数据库(MolDb)工具链中的指纹构建中枢模块,官方 API 文档页见 Docs/Book/source/rdkit.Chem.MolDb.FingerprintUtils.rst(该页通过automodule指令直接展开 rdkit/Chem/MolDb/FingerprintUtils.py 的源码文档)。本文以该模块为核心,完整讲解其提供的七种指纹构建函数、LayeredOptions分层指纹预筛机制与DepickleFP反序列化逻辑,并结合 Projects/DbCLI/CreateDb.py 与 Projects/DbCLI/SearchDb.py 两个 CLI 脚本,还原“建库 → 检索 → 输出”的完整工作流,帮助读者掌握 RDKit 相似度数据库的底层实现细节。

需要特别留意:该模块已被标记为弃用。rdkit/Chem/MolDb/init.py 在导入时即发出DeprecationWarning,提示 "the rdkit.Chem.MolDb module is deprecated";两个 CLI 入口 Projects/DbCLI/CreateDb.py 与 Projects/DbCLI/SearchDb.py 同样带有弃用警告。理解其内部机制对维护既有数据库工具链仍然重要,但新项目应优先考虑rdkit.Chem.Fingerprints等现代接口。

similarityMethods:指纹类型与数据结构类的映射表

模块顶部定义了一张核心映射表 FingerprintUtils.py#L9-L17:

similarityMethods = { 'RDK': DataStructs.ExplicitBitVect, 'AtomPairs': DataStructs.IntSparseIntVect, 'TopologicalTorsions': DataStructs.LongSparseIntVect, 'Pharm2D': DataStructs.SparseBitVect, 'Gobbi2D': DataStructs.SparseBitVect, 'Morgan': DataStructs.UIntSparseIntVect, 'Avalon': DataStructs.ExplicitBitVect, } supportedSimilarityMethods = list(iter(similarityMethods))

这张表把七个“指纹类型名”映射到rdkit.DataStructs中对应的 C++ 封装指纹类,是整个模块的“类型契约”,它同时服务于两个方向:

  1. 写入方向:CreateDb用BuildXxxFP函数生成指纹后,调用 C++ 层的ToBinary()序列化成二进制文本存入 SQLite 的blob列;
  2. 读取方向:DepickleFP(见后文)根据列中数据所属的指纹类型,查表取出正确的类进行反序列化。

各类型与其数据结构的对应关系可以总结为:

指纹类型数据结构类特性默认相似度度量(SearchDb 中)
RDKExplicitBitVect定长位向量(2048 位)FingerprintSimilarity(Tanimoto)
AtomPairsIntSparseIntVect32 位整型稀疏计数向量DiceSimilarity
TopologicalTorsionsLongSparseIntVect64 位整型稀疏计数向量DiceSimilarity
Pharm2DSparseBitVect稀疏位向量DiceSimilarity
Gobbi2DSparseBitVect稀疏位向量TanimotoSimilarity
MorganUIntSparseIntVect无符号整型稀疏计数向量DiceSimilarity
AvalonExplicitBitVect定长位向量—(SearchDb 未实现 Avalon 分支,见后文)

supportedSimilarityMethods正是由该映射表的键推导而来,Projects/DbCLI/SearchDb.py 的--similarityType命令行参数的choices就取自它,因此用户可选值被严格限定为上表所列名称。

各指纹构建函数逐一解析

BuildRDKitFP:经典 ECFP 风格拓扑指纹

def BuildRDKitFP(mol): return Chem.RDKFingerprint(mol, nBitsPerHash=1)

见 FingerprintUtils.py#L85-L86。这里nBitsPerHash=1意味着每个 hash 槽只映射 1 个比特,即采用“无碰撞计数降级为 0/1”的设定,得到的指纹语义上等价于只保留命中与否的 ECFP 风格指纹。在 Projects/DbCLI/CreateDb.py#L350-L354 中,该函数生成的指纹经ToBinary()后写入rdkitfps表的rdkfp列。

BuildAtomPairFP / BuildTorsionsFP:基于距离计数的指纹

def BuildAtomPairFP(mol): from rdkit.Chem.AtomPairs import Pairs fp = Pairs.GetAtomPairFingerprintAsIntVect(mol) fp._sumCache = fp.GetTotalVal() return fp def BuildTorsionsFP(mol): from rdkit.Chem.AtomPairs import Torsions fp = Torsions.GetTopologicalTorsionFingerprintAsIntVect(mol) fp._sumCache = fp.GetTotalVal() return fp

见 FingerprintUtils.py#L71-L82。值得注意的是两个函数都手动预置了fp._sumCache = fp.GetTotalVal()——这是稀疏整型向量在计算 Dice 相似度时需要用到的分量(两个向量的值之和)。预计算并缓存这个值可以省去后续每次比较时的重复求和,属于典型的性能优化。两类指纹在CreateDb中会一起写入同一个atompairs表的atompairfp与torsionfp两个 blob 列(见 CreateDb.py#L237-L239)。

BuildPharm2DFP 与 BuildSigFactory:药效团指纹及其分箱工厂

def BuildSigFactory(options=None, fdefFile=None, bins=[(2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 100)], skipFeats=('LumpedHydrophobe', 'ZnBinder')): if options: fdefFile = options.fdefFile if not fdefFile: raise ValueError('bad fdef file') from rdkit.Chem import ChemicalFeatures from rdkit.Chem.Pharm2D import SigFactory featFactory = ChemicalFeatures.BuildFeatureFactory(fdefFile) sigFactory = SigFactory.SigFactory(featFactory, skipFeats=skipFeats, trianglePruneBins=False) sigFactory.SetBins(bins) return sigFactory

见 FingerprintUtils.py#L56-L68。该函数构建 Pharm2D 药效团签名工厂,关键参数为:

  • fdefFile:特征定义文件,可为绝对路径,也可由命令行选项options.fdefFile提供;缺失时抛出ValueError('bad fdef file')。SearchDb的--fdefFile参数默认指向RDDataDir/Novartis1.fdef(见 SearchDb.py#L603-L605);
  • bins:距离分箱边界列表,默认从 2 Å 到 100 Å 共 7 个区间。分箱决定特征对之间的距离如何被离散化,SetBins的接口定义见 rdkit/Chem/Pharm2D/SigFactory.py;
  • skipFeats:默认跳过LumpedHydrophobe与ZnBinder两类特征。
def BuildPharm2DFP(mol): global sigFactory from rdkit.Chem.Pharm2D import Generate try: fp = Generate.Gen2DFingerprint(mol, sigFactory) except IndexError: print('FAIL:', Chem.MolToSmiles(mol, True)) raise return fp

见 FingerprintUtils.py#L89-L97。此函数依赖模块级全局变量sigFactory,调用者必须先在外部把它赋好值。这一点在 CLI 中得到印证:CreateDb在--doPharm2D分支中执行FingerprintUtils.sigFactory = BuildSigFactory(options)(见 CreateDb.py#L364-L365),SearchDb在 Pharm2D 分支执行同样的赋值(见 SearchDb.py#L188),而 Gobbi2D 分支则改为注入Gobbi_Pharm2D.factory(见 SearchDb.py#L198),从而复用同一个BuildPharm2DFP生成不同特征集下的指纹。IndexError分支会把导致失败的分子以 SMILES 打印出来再原样抛出,便于定位坏结构。

BuildMorganFP:二阶圆形指纹

def BuildMorganFP(mol): from rdkit.Chem import rdMolDescriptors fp = rdMolDescriptors.GetMorganFingerprint(mol, 2) fp._sumCache = fp.GetTotalVal() return fp

见 FingerprintUtils.py#L100-L104。这里radius=2的 Morgan 指纹以UIntSparseIntVect返回(保留了环上原子出现的计数值而非单纯 0/1),因此同样需要预置_sumCache,并在检索时与DiceSimilarity搭配使用。

BuildAvalonFP:可选的 Avalon 指纹

def BuildAvalonFP(mol, smiles=None): from rdkit.Avalon import pyAvalonTools if smiles is None: return pyAvalonTools.GetAvalonFP(mol) return pyAvalonTools.GetAvalonFP(smiles, True)

见 FingerprintUtils.py#L107-L111。它支持从Mol对象或字符串 SMILES(第二参数True表示输入为 SMILES)两种途径生成 Avalon 指纹。从源码结构看,similarityMethods表中包含'Avalon',但 SearchDb.py 的RunSearch并未实现对应的elif options.similarityType == 'Avalon'分支——即 CLI 层面实际可用的检索类型是 RDK、AtomPairs、TopologicalTorsions、Pharm2D、Gobbi2D、Morgan 六种,Avalon 仅作为库函数可用。

LayeredOptions:分层指纹预筛的完整实现

LayeredOptions(FingerprintUtils.py#L21-L53)是本模块最具工程价值的设计,它把Chem.LayeredFingerprint(分层拓扑指纹)用作子结构检索前的数据库级预筛:

class LayeredOptions: loadLayerFlags = 0xFFFFFFFF searchLayerFlags = 0x7 minPath = 1 maxPath = 6 fpSize = 1024 wordSize = 32 nWords = fpSize // wordSize @staticmethod def GetFingerprint(mol, query=True): if query: flags = LayeredOptions.searchLayerFlags else: flags = LayeredOptions.loadLayerFlags return Chem.LayeredFingerprint(mol, layerFlags=flags, minPath=LayeredOptions.minPath, maxPath=LayeredOptions.maxPath, fpSize=LayeredOptions.fpSize)

各常量的含义:

  • loadLayerFlags = 0xFFFFFFFF:建库时为分子启用的全部指纹层,保证信息完整;
  • searchLayerFlags = 0x7:查询时只取前 3 层(二进制0b111),层数越少生成的比特越少、越保守——只要查询分子含有子结构的骨架路径,这些低层比特在库分子上大概率同样置位,因此适合做“宁滥勿缺”的预筛;
  • minPath / maxPath = 1 / 6:参与指纹生成的路径长度范围;
  • fpSize = 1024、wordSize = 32:指纹共 1024 位,恰好拆成nWords = 32个 32 位字。

建库侧,CreateDb.py#L265-L270 按nWords建出layeredfps表,每行 32 个整型列Col_1~Col_32,每个分子用LayeredOptions.GetWords(mol)得到 32 个十进制整数逐列插入。GetWords的实现是把指纹转成比特字符串后每 32 位切段再按二进制转 int:

@staticmethod def GetWords(mol, query=True): txt = LayeredOptions.GetFingerprint(mol, query=query).ToBitString() return [int(txt[x:x + 32], 2) for x in range(0, len(txt), 32)]

查询侧,GetQueryText 把查询分子指纹(用searchLayerFlags生成)的非零字拼接为一条 SQLite 谓词:

@staticmethod def GetQueryText(mol, query=True): words = LayeredOptions.GetWords(mol, query=query) colqs = [] for idx, word in enumerate(words): if not word: continue colqs.append(f'{word}&Col_{idx + 1}={word}') return ' and '.join(colqs)

生成的 SQL 形如321&Col_2=321 and 15&Col_9=15,语义是“查询指纹中每个非零位所在的字,库分子对应列必须按位包含全部这些位”(&位与运算)。SearchDb.py#L316-L331 中,若指纹数据库里存在layeredfps表且非否定查询,就attach指纹库并join该表,把GetQueryText的结果追加进WHERE子句,从而在数据库层面先筛掉一批不可能匹配的分子;随后仍对剩余候选逐一执行m.HasSubstructMatch(options.queryMol)精确验证(SearchDb.py#L344-L346)。搜索完成时还会打印指纹预筛的淘汰率:Fingerprint screenout rate: N of M (%.2f)(SearchDb.py#L357-L360)。这套“粗筛 + 精确验证”的分级检索是子结构大规模数据库查询的标准做法。

DepickleFP:指纹反序列化与回退策略

def DepickleFP(pkl, similarityMethod): if not isinstance(pkl, (bytes, str)): pkl = str(pkl) try: klass = similarityMethods[similarityMethod] fp = klass(pkl) except Exception: import traceback traceback.print_exc() fp = pickle.loads(pkl) return fp

见 FingerprintUtils.py#L114-L124。其工作机制:

  1. 输入pkl是 SQLite blob 列中取出的二进制文本(ToBinary()的产物)。注意函数把非二进制输入(如旧版数据库中直接存的 pickle 字节串)统一转成字符串处理;
  2. 优先路径:查similarityMethods表得到类,调用该类的字符串构造函数直接重建指纹。以稀疏位向量为例,C++ 端存在专门的文本构造器SparseBitVect::SparseBitVect(const std::string &s),内部走initFromText解析(见 Code/DataStructs/SparseBitVect.cpp#L29-L33);ExplicitBitVect同样提供ExplicitBitVect(const std::string &pkl)构造(见 Code/DataStructs/ExplicitBitVect.h#L42)。这类“二进制文本 → 指纹对象”的直接构造比通用 pickle 反序列化更快、更安全;
  3. 回退路径:若构造失败(如旧版库里存的是标准 pickle 对象),打印堆栈后改用pickle.loads恢复。

在SearchDb中,DepickleFP由poolFromCurs生成器逐行调用(SearchDb.py#L399-L405),把游标产出的(id, pkl)行流变成(id, fp)指纹流,再交给GetNeighborLists做批量相似度计算。

建库与检索的完整工作流

建库:CreateDb 中的指纹列生产

Projects/DbCLI/CreateDb.py 是数据库生产端。默认表结构为:

  • 分子主库Compounds.sqlt的molecules表(--molDbName/--regName),主键guid列与用户自定义键列compound_id(--molIdName);
  • AtomPairs.sqlt的atompairs表:atompairfp、torsionfp两个 blob 列(--noPairs默认开启,即默认跳过,需显式关闭才计算——参数写法为store_false的--noPairs);
  • Fingerprints.sqlt中:rdkitfps(RDK 指纹)、layeredfps(32 个整数列)、pharm2dfps、gobbi2dfps、morganfps(--noMorganFps/--noCircularFps控制)。

逐行生产逻辑集中在 CreateDb.py#L343-L380:每 500 行批量executemany插入并提交一次,各 blob 列统一用DbModule.binaryHolder(fp.ToBinary())包裹存储。典型建库命令:

python Projects/DbCLI/CreateDb.py \ --outDir mydb --noPairs --noMorganFps \ --fdefFile $(python -c 'from rdkit import RDConfig; print(RDConfig.RDDataDir)')/Novartis1.fdef \ doPharm2D.sdf

(注意各--noXxx开关默认即为“跳过”,--noExtras可一次性关闭全部附属数据库,见 CreateDb.py#L181-L188。)

检索:SearchDb 的邻居搜索

Projects/DbCLI/SearchDb.py 是检索端,支持四类输入:查询分子文件(--molFormat smiles|sdf)、--smilesQuery/--smartsQuery子结构查询、--propQuery属性查询,且可组合(先子结构/属性筛选缩小 id 集,再在指纹库中做 topN 邻居搜索,通过临时表_tmpTbljoin 实现,见 SearchDb.py#L379-L397)。关键参数:

  • --similarityType:默认RDK,可选值来自supportedSimilarityMethods;
  • --similarityMetric:tanimoto/dice/tversky(附--tverskyA、--tverskyB,默认 0.5/0.5),不指定时按指纹类型取内置默认(见前文表格,逻辑在 SearchDb.py#L160-L214);
  • --topN(默认 20)与--simThresh(默认 -1):二者互斥使用——simThresh <= 0时每个探针保留 topN 邻居,否则按阈值无限量收集(SearchDb.py#L84-L87);
  • 相似度计算优先走批量接口BulkDiceSimilarity/BulkTanimotoSimilarity/BulkTverskySimilarity(SearchDb.py#L94-L117),非内置度量则回退到逐对计算;
  • 输出:CSV 风格文本(--outputDelim分隔,--transpose转置为“邻居为行、探针为列”的矩阵)、--sdfOut/--smilesOut导出命中分子。

一个典型检索命令:

python Projects/DbCLI/SearchDb.py \ --dbDir mydb --similarityType AtomPairs \ --similarityMetric dice --topN 10 \ probes.sdf

小结

FingerprintUtils虽然只有百余行 Python 代码,却定义了 RDKit 指纹数据库工具链的三组核心契约:similarityMethods映射表(指纹类型 ↔ 数据结构类)、各BuildXxxFP构建函数(含_sumCache预置与全局sigFactory注入两个易错点)、以及LayeredOptions+DepickleFP支撑的“分层位列粗筛 + 精确子结构验证 + 文本二进制反序列化”检索管线。Projects/DbCLI 下的 CreateDb/SearchDb 展示了这些契约在真实 SQLite 数据库上的落地方式。由于整个MolDb子系统已发出弃用警告,本文更适合作为理解 RDKit 指纹数据库设计思想的参考;对新系统而言,可直接复用其中的思想——用rdkit.Chem.Fingerprints建指纹、用低层指纹做预筛、用 blob 存ToBinary()文本——而不必依赖这套遗留接口。

  • 科学计算
  • 科研
  • 机器学习

【免费下载链接】rdkit

The official sources for the RDKit library

项目地址:https://gitcode.com/gh_mirrors/rd/rdkit
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询