4. RDKit 入门:环境搭建、分子对象创建、原子与键操作、分子可视化
进入这一章,咱们终于要开始实操了。RDKit 是化学信息学领域绕不开的核心库,几乎所有分子表示学习项目都会用到它。
我个人习惯把它当作「分子瑞士军刀」——从解析 SMILES 到画结构图,从原子遍历到指纹计算,一把刀全搞定。
今天我们先打好基础,把环境配好、对象建好、原子键玩转、最后把分子画出来。
4.1 环境搭建
先说说安装。RDKit 支持 pip 和 conda 两种方式,我强烈推荐 conda,尤其 Windows 用户。
为什么呢?因为 pip 安装的 RDKit 在 Windows 下有时候会和底层库冲突,我以前踩过这个坑——pip install rdkit-pypi 之后,分子可视化死活打不开。
后来换成 conda,一行命令搞定,再也没出过问题。
最简单的安装方式:
conda create -n rdkit_env python=3.10
conda activate rdkit_env
conda install -c conda-forge rdkit
如果你非要用 pip,记得确认你的 Python 版本和系统架构:
pip install rdkit-pypi
注意: pip 版 RDKit 在某些 Linux 发行版上可能缺少图形后端,导致 Draw 模块崩溃。我曾经在生产环境上遇到类似问题,最后乖乖切回 conda。
安装好之后,验证一下:
import rdkit
print(rdkit.__version__)
输出版本号,比如 2024.09.1,就说明环境搭好了。
4.2 分子对象创建
RDKit 里最核心的概念就是 Mol 对象。说白了,一个 Mol 对象就是分子在内存中的完整表示——包含原子、键、立体化学、电荷等等。
4.2.1 从 SMILES 创建
最常用的方法:
from rdkit import Chem
smiles = "CCO" # 乙醇
mol = Chem.MolFromSmiles(smiles)
print(mol.GetNumAtoms()) # 输出 3
你看,一行就把字符串变成分子了。但要注意,Chem.MolFromSmiles 在遇到非法 SMILES 时会返回 None,所以要加个判断:
mol = Chem.MolFromSmiles("CCZ") # 非法字符串
if mol is None:
print("无效 SMILES,请检查")
小经验: 我在做数据清洗时,习惯用 try-except 包一层,因为有些 SMILES 虽然合法但 RDKit 解析会抛出异常(比如超长分子)。
4.2.2 从文件创建
如果手里有 mol 或 sdf 文件:
mol = Chem.MolFromMolFile("ethanol.mol")
if mol:
print("文件读取成功")
# 读取多个分子的 SDF
suppl = Chem.SDMolSupplier("compounds.sdf")
for mol in suppl:
if mol is not None:
print(mol.GetNumAtoms())
这里有个坑:SDMolSupplier 是惰性加载的,遍历时有可能某个分子解析失败返回 None。我刚学的时候没注意,直接用了 mol.GetNumAtoms() 就报错了……
4.2.3 多分子批量读取
实际项目里经常要处理成千上万个分子。你想想看,一个个读太慢了,RDKit 提供了高效方式:
smiles_list = ["CCO", "CCCO", "C1CCCCC1"]
mols = [Chem.MolFromSmiles(smi) for smi in smiles_list]
mols = [m for m in mols if m is not None] # 过滤无效
或者用 MolFromSmarts 解析 SMARTS 模式(用于子结构匹配),用法类似:
pattern = Chem.MolFromSmarts("[#6]=O") # 羰基碳
4.3 原子与键操作
拿到 Mol 对象后,你最想干的事就是「拆」它——遍历每个原子、每条键,提取信息。这部分在分子表示学习中非常常用。
4.3.1 原子属性
遍历原子,获取元素符号、原子序数、形式电荷、杂化方式等:
mol = Chem.MolFromSmiles("CCO")
for atom in mol.GetAtoms():
print(f"原子索引: {atom.GetIdx()}, 元素: {atom.GetSymbol()}, "
f"原子序数: {atom.GetAtomicNum()}, 电荷: {atom.GetFormalCharge()}, "
f"度: {atom.GetDegree()}")
输出示例:
原子索引: 0, 元素: C, 原子序数: 6, 电荷: 0, 度: 2
原子索引: 1, 元素: C, 原子序数: 6, 电荷: 0, 度: 3
原子索引: 2, 元素: O, 原子序数: 8, 电荷: 0, 度: 1
还有一个我经常用的属性:GetIsAromatic() 判断是否是芳香原子。
4.3.2 键属性
键的操作类似:
for bond in mol.GetBonds():
print(f"键索引: {bond.GetIdx()}, 起始原子: {bond.GetBeginAtomIdx()}, "
f"结束原子: {bond.GetEndAtomIdx()}, 键型: {bond.GetBondTypeAsDouble()}, "
f"是否芳香: {bond.GetIsAromatic()}")
键型用浮点数表示:1.0 单键,2.0 双键,1.5 芳香键……
| 属性方法 | 返回值 | 说明 |
|---|---|---|
GetIdx() |
int | 原子或键的索引(从0开始) |
GetSymbol() |
str | 元素符号(仅原子) |
GetAtomicNum() |
int | 原子序数 |
GetFormalCharge() |
int | 形式电荷 |
GetDegree() |
int | 连接的键数(包括氢?默认不包含) |
GetIsAromatic() |
bool | 是否芳香 |
GetBondTypeAsDouble() |
float | 键级(仅键) |
核心要点: 当你需要将分子结构转化为特征时,原子和键的迭代是基础操作。我在做图神经网络(GNN)数据预处理时,就是用这种方式构建分子图的节点和边特征。
4.3.3 修改分子
RDKit 也支持修改分子,比如加氢、删除氢:
mol_h = Chem.AddHs(mol) # 加显式氢
print(mol_h.GetNumAtoms()) # 原来3个原子,加氢后变9个
mol_noH = Chem.RemoveHs(mol_h) # 去掉氢
print(mol_noH.GetNumAtoms()) # 回到3
注意:加氢后原子序数会变,迭代时要小心索引错乱。
4.4 分子可视化
你可能想亲眼看看分子长什么样。RDKit 的 Draw 模块提供了非常方便的绘图工具。
4.4.1 2D 结构图
最简单的:
from rdkit.Chem import Draw
from rdkit import Chem
mol = Chem.MolFromSmiles("C1CCCCC1C(=O)O") # 环己甲酸
img = Draw.MolToImage(mol, size=(300, 300))
img.show() # Jupyter 里直接显示
如果你在 Jupyter 里,也可以直接用 IPython 的 display:
from IPython.display import display
display(img)
多个分子一起画:
smiles = ["CCO", "CCCO", "C1CCCCC1"]
mols = [Chem.MolFromSmiles(s) for s in smiles]
legends = ["乙醇", "丙醇", "环己烷"]
img_grid = Draw.MolsToGridImage(mols, molsPerRow=3, subImgSize=(200,200), legends=legends)
display(img_grid)
4.4.2 SVG 导出
如果你要把分子图嵌入网页或生成矢量图,用 SVG 格式更合适:
svg_text = Draw.MolToSVG(mol, size=(300, 300))
with open("molecule.svg", "w") as f:
f.write(svg_text)
SVG 可以直接在浏览器或 Markdown 里显示。
踩坑提醒: 我在 Jupyter Notebook 中直接显示 SVG 时,有时会因为单元格输出过长而卡死。建议用 IPython.display.SVG 包装一下:
from IPython.display import SVG
display(SVG(svg_text))
4.4.3 3D 可视化(了解即可)
RDKit 本身不带 3D 渲染引擎,但可以通过 py3Dmol 或 nglview 配合使用。这里简单提一下:
from rdkit.Chem import AllChem
mol_3d = Chem.MolFromSmiles("CCO")
mol_3d = Chem.AddHs(mol_3d)
AllChem.EmbedMolecule(mol_3d, AllChem.ETKDG()) # 生成3D构象
# 然后用 py3Dmol 显示,这里不展开
4.5 本章知识体系
下面这张图概括了 RDKit 入门操作的核心流程,从字符串到可视化的完整链条:
图中展示了本章覆盖的核心路径:SMILES → Mol → 原子/键遍历 → 属性提取 → 修饰 → 可视化。每一步都对应实际代码,形成闭环。
4.6 一些实用技巧
- 缓存分子对象: 如果你多次用到同一个分子,最好把它存下来,而不是每次从 SMILES 解析。我有个项目解析了10万次同一个 SMILES,后来改成缓存,速度提升了几十倍。
- 处理大分子: 对于超过1000个原子的分子(比如蛋白质片段),遍历原子键时要小心性能。可以用
mol.GetNumAtoms(onlyExplicit=True)限制只获取显式原子(默认会包含隐式氢)。 - 检查芳香性: 很多性质计算(如 logP)需要分子预先进行芳香性感知。推荐统一用
Chem.SanitizeMol(mol)对分子进行标准化。
个人经验: 做分子图神经网络时,我通常会先 Chem.AddHs(mol) 加氢,再把所有显式原子和键作为图节点和边。这样能更好地捕捉氢键信息,模型效果有明显提升。