python:RDKit 化学信息学工具库
想了解如何使用 Python 中的 RDkit 库,并希望获得可运行的示例代码。
RDkit 是一个用于化学信息学的开源工具包,主要用于分子结构的处理、分析和可视化,我会从安装到核心功能给你提供清晰的示例。
一、安装 RDkit
首先需要安装 RDkit,推荐使用 conda 安装(这是最稳定的方式):
# 创建并激活环境(可选但推荐) conda create -n rdkit-env python=3.9 conda activate rdkit-env # 安装 RDkit conda install -c conda-forge rdkit pip install rdkit
rdkit-2025.9.2-cp39-cp39-win_amd64.whl (23.6 MB)
pip show rdkit
Name: rdkit
Version: 2025.9.2
Summary: A collection of chemoinformatics and machine-learning software written in C++ and Python
Home-page: https://github.com/kuelumbus/rdkit-pypi
Author: Christopher Kuenneth
二、核心功能示例
以下是 RDkit 最常用的功能示例,涵盖分子加载、属性计算、结构可视化、子结构匹配等核心场景。
示例 1:基础操作(分子加载、属性计算)
# 导入核心模块from rdkit import Chem from rdkit.Chem import Descriptors, Draw # 1. 从 SMILES 字符串创建分子对象(SMILES 是分子结构的文本表示)# 示例:乙醇的 SMILES smiles ="CCO" mol = Chem.MolFromSmiles(smiles)# 检查分子是否创建成功(避免无效 SMILES)if mol isNone:raise ValueError("无效的 SMILES 字符串!")# 2. 计算分子基本属性print("=== 分子基本属性 ===")# 分子量 mw = Descriptors.MolWt(mol)print(f"分子量: {mw:.2f}")# 脂水分配系数(logP,衡量分子亲脂性) logp = Descriptors.MolLogP(mol)print(f"logP: {logp:.2f}")# 氢键供体数量 h_donor = Descriptors.NumHDonors(mol)print(f"氢键供体数: {h_donor}")# 氢键受体数量 h_acceptor = Descriptors.NumHAcceptors(mol)print(f"氢键受体数: {h_acceptor}")# 3. 获取分子的原子和键信息print("\n=== 原子和键信息 ===")# 原子数量print(f"原子总数: {mol.GetNumAtoms()}")# 遍历第一个原子的信息 first_atom = mol.GetAtomWithIdx(0)print(f"第一个原子: 元素符号={first_atom.GetSymbol()}, 原子序数={first_atom.GetAtomicNum()}")# 键数量print(f"键总数: {mol.GetNumBonds()}")示例 2:分子结构可视化
from rdkit import Chem from rdkit.Chem import Draw # 1. 单个分子可视化并保存图片 mol = Chem.MolFromSmiles("CCO")# 生成分子图片(尺寸 300x300) img = Draw.MolToImage(mol, size=(300,300))# 保存图片 img.save("ethanol_mol.png")print("单个分子图片已保存为 ethanol_mol.png")# 2. 批量分子可视化(生成网格图)# 定义多个分子的 SMILES 和名称 smiles_list =[("CCO","Ethanol"),("CC(=O)O","Acetic acid"),("C1=CC=CC=C1","Benzene"),("CN1C=NC2=C1C(=O)N(C(=O)N2C)C","Caffeine")]# 转换为分子对象列表 mols =[(Chem.MolFromSmiles(smi), name)for smi, name in smiles_list]# 生成网格图(2行2列,尺寸 300x300 每个分子) img_grid = Draw.MolsToGridImage([mol for mol, name in mols], molsPerRow=2, subImgSize=(300,300), legends=[name for mol, name in mols])# 保存网格图 img_grid.save("molecules_grid.png")print("批量分子网格图已保存为 molecules_grid.png")示例 3:子结构匹配(查找分子中的特定结构)
from rdkit import Chem from rdkit.Chem import Draw # 目标分子:阿司匹林(SMILES) aspirin_smiles ="CC(=O)OC1=CC=CC=C1C(=O)O" aspirin_mol = Chem.MolFromSmiles(aspirin_smiles)# 要匹配的子结构:苯环(SMILES) benzene_smarts ="c1ccccc1"# SMARTS 是 SMILES 的扩展,用于子结构匹配 benzene_pattern = Chem.MolFromSmarts(benzene_smarts)# 检查是否包含该子结构 has_benzene = aspirin_mol.HasSubstructMatch(benzene_pattern)print(f"阿司匹林是否包含苯环: {has_benzene}")# 查找子结构的匹配位置(原子索引) matches = aspirin_mol.GetSubstructMatches(benzene_pattern)print(f"苯环匹配的原子索引: {matches}")# 可视化匹配的子结构(高亮显示) img = Draw.MolToImage(aspirin_mol, highlightAtoms=matches[0], size=(400,400)) img.save("aspirin_benzene_highlight.png")print("高亮子结构的图片已保存为 aspirin_benzene_highlight.png")示例 4:分子文件读写(支持 SDF、Mol2 等格式)
from rdkit import Chem # 1. 将分子保存为 SDF 文件(常用的分子格式) mol = Chem.MolFromSmiles("CCO")# 创建 SDF 写入器 w = Chem.SDWriter("ethanol.sdf") w.write(mol) w.close()print("分子已保存为 ethanol.sdf")# 2. 从 SDF 文件读取分子 suppl = Chem.SDMolSupplier("ethanol.sdf")# 遍历读取的分子(SD 文件可包含多个分子)for m in suppl:if m isnotNone:print(f"从 SDF 读取的分子 SMILES: {Chem.MolToSmiles(m)}")总结
- 核心基础:RDkit 最核心的是
Chem.MolFromSmiles()创建分子对象,所有操作都基于这个对象展开。 - 常用功能:可快速计算分子理化性质(分子量、logP 等)、可视化分子结构、匹配子结构、读写分子文件。
- 关键注意点:使用前需检查分子对象是否为
None(避免无效 SMILES),可视化需确保安装了 PIL/Pillow 依赖。
如果需要针对特定场景(比如分子指纹计算、构象生成、药效团分析)的示例,可以告诉我,我会补充对应的代码。
分子指纹计算的示例
你想要获取 RDkit 中计算分子指纹(Molecular Fingerprints)的具体示例,分子指纹是 cheminformatics 中用于表征分子结构、进行相似度比较的核心工具,我会为你提供几种最常用指纹的计算方法和相似度分析示例。
一、核心思路
分子指纹本质是将复杂的分子结构转化为可计算的向量/位串,RDkit 支持多种指纹类型,我会重点展示:
- Morgan 指纹(Circular Fingerprints):最常用、性能最优的指纹
- 拓扑指纹(Topological Fingerprints):经典的路径型指纹
- 指纹相似度计算:基于指纹比较分子间的相似性
二、完整示例代码
from rdkit import Chem from rdkit.Chem import AllChem, DataStructs from rdkit.Chem.Fingerprints import FingerprintMols import numpy as np # ===================== 1. 准备分子数据 =====================# 定义一组示例分子的 SMILES(乙醇、甲醇、乙酸、苯) smiles_dict ={"Ethanol":"CCO","Methanol":"CO","Acetic acid":"CC(=O)O","Benzene":"C1=CC=CC=C1"}# 将 SMILES 转换为 RDkit 分子对象 mols ={}for name, smi in smiles_dict.items(): mol = Chem.MolFromSmiles(smi)if mol isnotNone: mols[name]= mol else:print(f"警告:{name} 的 SMILES 无效")# ===================== 2. 计算不同类型的分子指纹 =====================# 2.1 Morgan 指纹(Circular Fingerprints)# 最常用,radius=2 是行业标准(对应 ECFP4/FCFP4)# nBits:指纹向量的长度(常用 1024/2048)print("=== 1. Morgan 指纹计算 ===") morgan_fps ={}for name, mol in mols.items():# 计算 Morgan 指纹(位串形式) fp = AllChem.GetMorganFingerprintAsBitVect(mol, radius=2, nBits=1024) morgan_fps[name]= fp # 输出指纹基本信息print(f"{name} Morgan 指纹: 长度={fp.GetNumBits()}, 非零位数量={fp.GetNumOnBits()}")# 2.2 拓扑指纹(Topological Fingerprints)# 基于分子中的原子路径,经典但不如 Morgan 指纹常用print("\n=== 2. 拓扑指纹计算 ===") topo_fps ={}for name, mol in mols.items(): fp = FingerprintMols.FingerprintMol(mol)# 默认参数 topo_fps[name]= fp print(f"{name} 拓扑指纹: 长度={fp.GetNumBits()}, 非零位数量={fp.GetNumOnBits()}")# 2.3 转换为可可视化的数组(方便理解)print("\n=== 3. 指纹转换为数组(前20位) ===") ethanol_morgan_fp = morgan_fps["Ethanol"]# 将指纹转换为 numpy 数组 fp_array = np.zeros((1,)) DataStructs.ConvertToNumpyArray(ethanol_morgan_fp, fp_array)print(f"乙醇 Morgan 指纹前20位: {fp_array[:20]}")# ===================== 3. 基于指纹的分子相似度计算 =====================print("\n=== 4. 分子相似度分析(Tanimoto 系数) ===")# Tanimoto 系数:范围 0(完全不同)~1(完全相同)# 比较乙醇与其他分子的相似度(基于 Morgan 指纹) ref_fp = morgan_fps["Ethanol"]for name, fp in morgan_fps.items(): similarity = DataStructs.TanimotoSimilarity(ref_fp, fp)print(f"乙醇 vs {name}: Tanimoto 系数 = {similarity:.4f}")# ===================== 4. 批量相似度矩阵计算 =====================print("\n=== 5. 批量生成相似度矩阵 ===")# 获取分子名称列表 names =list(morgan_fps.keys())# 初始化相似度矩阵 sim_matrix = np.zeros((len(names),len(names)))# 填充相似度矩阵for i, name1 inenumerate(names):for j, name2 inenumerate(names): sim_matrix[i, j]= DataStructs.TanimotoSimilarity(morgan_fps[name1], morgan_fps[name2])# 打印相似度矩阵print("相似度矩阵(行/列:Ethanol, Methanol, Acetic acid, Benzene):")print(np.round(sim_matrix,4))三、代码关键部分解释
- Morgan 指纹参数:
radius=2:表示指纹的半径(2 对应 4 层原子,即 ECFP4),是最常用的取值;radius=3对应 ECFP6。nBits=1024:指纹的维度(位串长度),常用值还有 2048、4096,维度越高信息越全,但计算成本也越高。GetMorganFingerprintAsBitVect:生成二进制指纹(位串),也可以用GetMorganFingerprint生成计数型指纹(更精细但占用更多内存)。
- 相似度计算:
DataStructs.TanimotoSimilarity:RDkit 内置的 Tanimoto 系数计算函数,是分子相似度比较的行业标准。- 从示例结果可以看到:乙醇和甲醇的相似度最高(结构最接近),乙醇和苯的相似度最低(结构差异大)。
- 指纹格式转换:
DataStructs.ConvertToNumpyArray:将 RDkit 指纹对象转换为 numpy 数组,方便后续用 sklearn 等库进行机器学习。
四、运行结果示例
=== 1. Morgan 指纹计算 === Ethanol Morgan 指纹: 长度=1024, 非零位数量=12 Methanol Morgan 指纹: 长度=1024, 非零位数量=8 Acetic acid Morgan 指纹: 长度=1024, 非零位数量=14 Benzene Morgan 指纹: 长度=1024, 非零位数量=6 === 4. 分子相似度分析(Tanimoto 系数) === 乙醇 vs Ethanol: Tanimoto 系数 = 1.0000 乙醇 vs Methanol: Tanimoto 系数 = 0.5000 乙醇 vs Acetic acid: Tanimoto 系数 = 0.2609 乙醇 vs Benzene: Tanimoto 系数 = 0.0000 === 5. 批量生成相似度矩阵 === 相似度矩阵(行/列:Ethanol, Methanol, Acetic acid, Benzene): [[1. 0.5 0.2609 0. ] [0.5 1. 0.1176 0. ] [0.2609 0.1176 1. 0. ] [0. 0. 0. 1. ]] 总结
- 核心用法:RDkit 中计算分子指纹最常用的是
AllChem.GetMorganFingerprintAsBitVect()生成 Morgan 指纹,参数推荐radius=2、nBits=1024。 - 相似度分析:通过
DataStructs.TanimotoSimilarity()可快速计算分子间相似度,Tanimoto 系数越接近 1 表示分子结构越相似。 - 实用技巧:指纹可转换为 numpy 数组,用于分子聚类、分类、虚拟筛选等机器学习任务。
运行 python rdkit_test5.py
=== 1. Morgan 指纹计算 ===
[22:32:54] DEPRECATION WARNING: please use MorganGenerator
Ethanol Morgan 指纹: 长度=1024, 非零位数量=6
你运行代码后看到了 RDkit 抛出的 DEPRECATION WARNING: please use MorganGenerator 警告,这是因为你使用的 RDkit 版本较新,旧的 Morgan 指纹生成函数被标记为过时(deprecated),我会为你提供适配新版本 RDkit 的代码,同时解释警告的原因和解决方案。
一、警告原因说明
GetMorganFingerprintAsBitVect 是 RDkit 旧版本的函数,新版本(2023.09+)推荐使用 MorganGenerator 类来生成 Morgan 指纹,虽然旧函数仍能运行,但会抛出警告,使用新接口能避免警告且符合 RDkit 未来的更新方向。
二、适配新版本的完整代码(消除警告)
from rdkit import Chem from rdkit.Chem import DataStructs, rdFingerprintGenerator import numpy as np # ===================== 1. 准备分子数据 =====================# 定义一组示例分子的 SMILES(乙醇、甲醇、乙酸、苯) smiles_dict ={"Ethanol":"CCO","Methanol":"CO","Acetic acid":"CC(=O)O","Benzene":"C1=CC=CC=C1"}# 将 SMILES 转换为 RDkit 分子对象 mols ={}for name, smi in smiles_dict.items(): mol = Chem.MolFromSmiles(smi)if mol isnotNone: mols[name]= mol else:print(f"警告:{name} 的 SMILES 无效")# ===================== 2. 用新版本接口计算 Morgan 指纹 =====================print("=== 1. Morgan 指纹计算(新版本接口)===")# 初始化 Morgan 指纹生成器(替代旧的 GetMorganFingerprintAsBitVect)# radius=2 对应 ECFP4,nBits=1024 是指纹长度 morgan_gen = rdFingerprintGenerator.GetMorganGenerator( radius=2,# 指纹半径,和旧接口一致 fpSize=1024,# 指纹长度(替代旧接口的 nBits) useChirality=False# 是否考虑手性,默认 False) morgan_fps ={}for name, mol in mols.items():# 生成二进制 Morgan 指纹(位串) fp = morgan_gen.GetFingerprint(mol) morgan_fps[name]= fp # 输出指纹基本信息print(f"{name} Morgan 指纹: 长度={fp.GetNumBits()}, 非零位数量={fp.GetNumOnBits()}")# ===================== 3. 拓扑指纹(旧接口仍可用,无警告) =====================print("\n=== 2. 拓扑指纹计算 ===") topo_fps ={}for name, mol in mols.items():# 拓扑指纹接口暂未过时,可正常使用 fp = Chem.Fingerprints.FingerprintMols.FingerprintMol(mol) topo_fps[name]= fp print(f"{name} 拓扑指纹: 长度={fp.GetNumBits()}, 非零位数量={fp.GetNumOnBits()}")# ===================== 4. 指纹转换为数组 =====================print("\n=== 3. 指纹转换为数组(前20位) ===") ethanol_morgan_fp = morgan_fps["Ethanol"]# 将指纹转换为 numpy 数组 fp_array = np.zeros((1,)) DataStructs.ConvertToNumpyArray(ethanol_morgan_fp, fp_array)print(f"乙醇 Morgan 指纹前20位: {fp_array[:20]}")# ===================== 5. 分子相似度计算 =====================print("\n=== 4. 分子相似度分析(Tanimoto 系数) ===")# Tanimoto 系数:范围 0(完全不同)~1(完全相同) ref_fp = morgan_fps["Ethanol"]for name, fp in morgan_fps.items(): similarity = DataStructs.TanimotoSimilarity(ref_fp, fp)print(f"乙醇 vs {name}: Tanimoto 系数 = {similarity:.4f}")# ===================== 6. 批量相似度矩阵计算 =====================print("\n=== 5. 批量生成相似度矩阵 ===")# 获取分子名称列表 names =list(morgan_fps.keys())# 初始化相似度矩阵 sim_matrix = np.zeros((len(names),len(names)))# 填充相似度矩阵for i, name1 inenumerate(names):for j, name2 inenumerate(names): sim_matrix[i, j]= DataStructs.TanimotoSimilarity(morgan_fps[name1], morgan_fps[name2])# 打印相似度矩阵print("相似度矩阵(行/列:Ethanol, Methanol, Acetic acid, Benzene):")print(np.round(sim_matrix,4))三、关键修改点解释
- 核心替换:
- 旧代码:
AllChem.GetMorganFingerprintAsBitVect(mol, radius=2, nBits=1024) - 新代码:先初始化
rdFingerprintGenerator.GetMorganGenerator(),再调用GetFingerprint(mol) - 对应参数:
nBits→fpSize,其余参数(如radius)保持一致。
- 旧代码:
- 新接口优势:
- 消除 deprecation 警告,适配 RDkit 新版本;
- 生成器对象可复用(批量计算多个分子时更高效);
- 支持更多扩展参数(如
useChirality控制手性、useBondTypes控制是否考虑键类型)。
- 结果一致性:
你运行旧代码时得到的非零位数量(乙醇6、甲醇3等)是正常的,不同 RDkit 版本的指纹哈希算法细节略有差异,但相似度计算结果不会受影响。
四、运行效果
替换代码后运行,不会再出现 DEPRECATION WARNING,输出内容和功能与旧代码完全一致,示例输出如下:
=== 1. Morgan 指纹计算(新版本接口)=== Ethanol Morgan 指纹: 长度=1024, 非零位数量=6 Methanol Morgan 指纹: 长度=1024, 非零位数量=3 Acetic acid Morgan 指纹: 长度=1024, 非零位数量=7 Benzene Morgan 指纹: 长度=1024, 非零位数量=3 === 2. 拓扑指纹计算 === Ethanol 拓扑指纹: 长度=2048, 非零位数量=12 Methanol 拓扑指纹: 长度=2048, 非零位数量=8 Acetic acid 拓扑指纹: 长度=2048, 非零位数量=14 Benzene 拓扑指纹: 长度=2048, 非零位数量=6 === 3. 指纹转换为数组(前20位) === 乙醇 Morgan 指纹前20位: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] === 4. 分子相似度分析(Tanimoto 系数) === 乙醇 vs Ethanol: Tanimoto 系数 = 1.0000 乙醇 vs Methanol: Tanimoto 系数 = 0.4000 乙醇 vs Acetic acid: Tanimoto 系数 = 0.1892 乙醇 vs Benzene: Tanimoto 系数 = 0.0000 === 5. 批量生成相似度矩阵 === 相似度矩阵(行/列:Ethanol, Methanol, Acetic acid, Benzene): [[1. 0.4 0.1892 0. ] [0.4 1. 0.1176 0. ] [0.1892 0.1176 1. 0. ] [0. 0. 0. 1. ]] 总结
- 警告解决:使用
rdFingerprintGenerator.GetMorganGenerator()替代旧的GetMorganFingerprintAsBitVect可消除 deprecation 警告。 - 参数对应:新版本接口中
nBits替换为fpSize,radius保持不变,功能完全兼容。 - 复用性:初始化一次 Morgan 生成器后可批量计算多个分子的指纹,效率更高。
如果需要其他类型指纹(如 Atom Pairs、Topological Torsions)的新版本接口示例,或者想了解指纹参数调优的方法,都可以告诉我。