3、Python 化学信息学工具:RDKit 安装与基础使用
做化学信息学的人,手里没个 RDKit 总觉得缺了点什么。我记得刚入行那会,整天跟 SMILES 字符串打交道,手动解析碎片简直要疯掉。后来师兄扔过来一句话:“装个 RDKit,一条命令搞定。”嗯,从那天起,我的工作效率才算真正上了个台阶。
这节咱们就聊聊这个核心工具怎么装、怎么用。说白了,RDKit 就是把化学结构信息变成 Python 能理解的数据对象,再从中榨出各种性质描述符。你想想看,一个几百字符的 SMILES,背后藏着分子量、LogP、氢键供体/受体数量……RDKit 能让这些东西唾手可得。
3.1 为什么非得是 RDKit
市面上做化学信息学的库不少,Open Babel、CDK、ChemDes 各有各的活法。但我个人习惯用 RDKit,原因有三:
- 社区最活跃——GitHub 上 star 过万,遇到问题基本都能搜到答案
- 接口设计顺手——函数命名直白,参数不绕弯子
- 和 SMILES 配合完美——解析、校验、标准化的细节做得最到位
我在项目中遇到过用其他库读 SMILES 结果残留芳香性标志对不上的情况,换成 RDKit 之后直接一步到位。所以这章咱们就拿它当主力。
3.2 安装 RDKit:三种姿势,选你最舒服的
安装这事不难,但坑也不少。我曾经在旧版 Python 下硬装源码,浪费了大半天 —— 后来发现 conda 两分钟搞定。下面我把三种主流方式列出来,你根据自己情况选。
| 安装方式 | 推荐场景 | 命令示例 | 备注 |
|---|---|---|---|
| Conda | 多数用户(强烈推荐) | | 自动处理依赖,不会搞乱系统 Python |
| pip | 已有虚拟环境,想快速尝试 | | 某些旧平台可能导致二进制不兼容 |
| 源码编译 | 需要自定义编译选项或调试 | | 耗时较长,新手建议跳过 |
我的小建议:用 conda 建一个干净的虚拟环境,只装 RDKit 和常用科学计算库。比如这样:
conda create -n chem_env python=3.9
conda activate chem_env
conda install -c conda-forge rdkit matplotlib pandas
这样你的项目环境清爽,以后换机器也能快速复现。
注意:RDKit 对 Python 版本有要求。目前(2025 年)推荐 Python 3.8–3.11,太新的版本 conda 可能还没打包好。我上次用 Python 3.12 试 pip 安装,结果 smi2mol 函数直接报缺失符号错误 —— 折腾了一下午才想起回退版本。
装完之后,验证一下:
python -c "from rdkit import Chem; print(Chem.__version__)"
如果没报错,说明成功了。看到版本号就知道大功告成。
3.3 基础操作:从字符串到分子对象
安装好了,咱们来点实操。RDKit 最核心的模块就是 Chem。它能把 SMILES 字符串变成 Mol 对象 —— 之后几乎所有操作都围绕这个对象展开。
from rdkit import Chem
smi = "CCO" # 乙醇的简化表示
mol = Chem.MolFromSmiles(smi)
if mol is not None:
print("分子已读取成功")
print("原子数:", mol.GetNumAtoms())
print("重原子数:", mol.GetNumHeavyAtoms())
else:
print("SMILES 无效")
输出:
分子已读取成功
原子数: 3
重原子数: 3
你看,三行代码就把乙醇介绍给了 Python。这里是乙醇的骨架:C(碳)、C(碳)、O(氧),没有氢显示是因为 SMILES 默认隐含氢原子。
关键点: 检查 mol is not None 一定要做。我在项目中遇到最大的坑就是用户手滑打错了 SMILES(比如 CL 写成 C1),结果后续计算全部崩掉。加一句判断能节省很多调试时间。
SMILES 里还有不少门道。比如芳香性表示、手性标记、异构体写法。RDKit 的 MolFromSmiles 会自动做标准化,但你如果想看最原生的字符串,可以用 Chem.MolToSmiles(mol) 把它变回来,这时你会看到 RDKit 重排后的标准 SMILES:
print(Chem.MolToSmiles(mol))
# 输出: CCO
同一种分子可能有多种写法(比如乙醇可以写成 OCC),但标准输出总是统一的。这在去重比较时特别有用。
3.4 常用分子描述符计算
拿到 Mol 对象以后,下一步就是提取描述符。RDKit 自带了上百种属性,你不需要自己计算。下面是我项目里最常用的几个:
| 描述符 | 函数 | 物理意义 |
|---|---|---|
| 分子量(精确) | Descriptors.ExactMolWt(mol) | 根据同位素精确质量计算 |
| LogP(辛醇/水分配系数) | Descriptors.MolLogP(mol) | 脂溶性,药物化学常用 |
| 氢键供体数 | Descriptors.NumHDonors(mol) | Lipinski 五规则之一 |
| 氢键受体数 | Descriptors.NumHAcceptors(mol) | Lipinski 五规则之一 |
| 可旋转键数 | Descriptors.NumRotatableBonds(mol) | 分子柔韧性指标 |
| 拓扑极性表面积 (TPSA) | Descriptors.TPSA(mol) | 与透膜能力相关 |
写个完整例子:
from rdkit import Chem
from rdkit.Chem import Descriptors
smi = "CC(=O)OC1=CC=CC=C1C(=O)O" # 阿司匹林
mol = Chem.MolFromSmiles(smi)
if mol:
print("分子量:", round(Descriptors.ExactMolWt(mol), 2))
print("LogP:", round(Descriptors.MolLogP(mol), 2))
print("氢键供体:", Descriptors.NumHDonors(mol))
print("氢键受体:", Descriptors.NumHAcceptors(mol))
print("可旋转键:", Descriptors.NumRotatableBonds(mol))
print("TPSA:", round(Descriptors.TPSA(mol), 1))
输出:
分子量: 180.04
LogP: 1.19
氢键供体: 1
氢键受体: 3
可旋转键: 3
TPSA: 63.6
这些数值可以直接用于机器学习特征或过滤筛选。举个例子,我在做虚拟筛选时,经常先算 LogP 和 TPSA,把不在合理范围的分子直接剔除,节省后面对接的计算量。
3.5 简易可视化:看一眼分子长啥样
光有数字不够,有时候还是想看分子结构。RDKit 提供了 Draw 模块,可以生成分子图片。不过注意,它画出来的是 2D 结构式,不是 3D 构象。
from rdkit import Chem
from rdkit.Chem import Draw
mol = Chem.MolFromSmiles("C1=CC=C(C=C1)C=O") # 苯甲醛
img = Draw.MolToImage(mol, size=(300, 300))
img.show() # 在 Jupyter 中会自动显示
如果你需要批量画图,用 Draw.MolsToGridImage 可以排成网格,方便对比。我的习惯是做报告时用它生成一组分子的缩略图,一眼就能看出结构相似性。
到现在为止,你已经能:
- 安装 RDKit
- 读取/写出 SMILES
- 计算关键描述符
- 画分子结构
下图的 R 工作流把这一套串起来了:
这张图把咱们刚才讲的内容串起来了。核心就是:SMILES 进来,Mol 对象出去,然后分两支——一条走数字特征,一条走结构图像。你想想看,以后学复杂操作(指纹、子结构匹配、反应模板)也都是在这个框架里加新节点。
3.6 避坑指南与我的经验
- SMILES 校验不能省。 我曾经从外部数据库导入十万个 SMILES,结果大约 2% 因为格式问题读成
None。后来我在管道里加了Chem.SanitizeMol(mol)做一遍严格清理,稳定多了。 - 注意立体化学标记。 如果 SMILES 里有 @ 或 @@,RDKit 会保留手性信息。但如果你不关心立体构型,可以用
Chem.RemoveStereochemistry(mol)清掉。 - 大分子别逞强。 超过几百个原子的分子,用 RDKit 计算某些描述符(比如 3D 构象分析)会慢。我一般先用量子化学软件算好,再用 RDKit 做后处理。
如果你在 Jupyter Notebook 里运行,推荐装一个 rdkit.Chem.Draw.IPythonConsole 包,这样分子图片可以直接渲染,不用手动调 show()。
好,到现在你已经掌握了 RDKit 的安装和基本功。咱们这章的内容足够你开始处理大部分常见分子数据了。记住:先把 SMILES 转成 Mol,再任意折腾。下一步我们会深入分子指纹与相似性搜索,但那是后面的故事了。