化学信息学工具初探:从安装到第一个分子
好了,咱们正式开始动手吧。
这一章,我会带你搭建 RDKit 环境,并搞懂两种最常用的分子表示法——SMILES 和 InChI。
为什么会先讲这个?
因为分子图构建的第一步,不是画图,是读数据。
2.1 RDKit:为什么选它?怎么装?
RDKit 是什么?
简单说,它是一个 C++ 内核 + Python 接口的开源化学信息学库。
它能做的事太多了:读取分子、计算指纹、生成 2D/3D 构象、做子结构搜索……
我个人习惯在 conda 环境里安装 RDKit。为什么?
因为依赖管理最干净,不会跟系统 Python 打架。
# 创建一个新的 conda 环境(Python 3.10 或 3.11)
conda create -n mol_graph python=3.10 -y
# 激活环境
conda activate mol_graph
# 安装 RDKit
conda install -c conda-forge rdkit -y
装完怎么验证?
跑一行代码就行。
from rdkit import Chem
print(Chem.__version__)
如果你看到类似 2024.03.5 的版本号,就说明装好了。
嗯,就是这么简单。
2.2 SMILES 与 InChI:两种表示法,两种思维
搞化学信息学,你绕不开这两个东西。
| 表示法 | 全称 | 核心特征 | 典型例子 |
|---|---|---|---|
| SMILES | Simplified Molecular Input Line Entry System | 面向人读,紧凑,有规范形式 | CCO(乙醇) |
| InChI | International Chemical Identifier | 面向机器,分层严格,适合数据库索引 | InChI=1S/C2H6O/c1-2-3/h3H,2H2,1H3 |
来看看 RDKit 实际怎么处理它们。
from rdkit import Chem
# 从 SMILES 构建分子
mol = Chem.MolFromSmiles("CCO")
print("SMILES:", Chem.MolToSmiles(mol))
# 从 InChI 构建分子
inchi = "InChI=1S/C2H6O/c1-2-3/h3H,2H2,1H3"
mol2 = Chem.MolFromInchi(inchi)
print("InChI:", Chem.MolToInchi(mol2))
# 检查两个分子是否相同
print("Same molecule?", mol.HasSubstructMatch(mol2))
# 输出示例
SMILES: CCO
InChI: InChI=1S/C2H6O/c1-2-3/h3H,2H2,1H3
Same molecule? True
2.3 简单分子读取与输出:打开你的第一个 .sdf
实际项目中,数据很少是孤立的 SMILES 字符串。
更常见的是 .sdf 文件(Structure-Data File),里面存着分子结构 + 属性字段。
我建议你准备一个小文件来练手。比如这个 ethanol.sdf:
ethanol
RDKit 2D
9 8 0 0 0 0 0 0 0 0999 V2000
0.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1.2090 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
3.6271 0.0000 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
-0.6045 -1.0469 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
-0.6045 1.0469 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
1.8135 -1.0469 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
1.8135 1.0469 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
2.4181 -0.0000 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
4.2316 1.0469 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
1 3 1 0 0 0 0
1 4 1 0 0 0 0
1 5 1 0 0 0 0
2 6 1 0 0 0 0
2 7 1 0 0 0 0
2 8 1 0 0 0 0
3 9 1 0 0 0 0
M END
>
1
>
CCO
$$$$
读取它,然后输出成你需要的形式:
from rdkit import Chem
# 从 sdf 文件中读取分子
supplier = Chem.SDMolSupplier("ethanol.sdf")
for mol in supplier:
if mol is not None:
# 获取属性
mol_id = mol.GetProp("ID")
smiles = mol.GetProp("SMILES")
# 输出多种格式
print(f"ID: {mol_id}")
print(f"SMILES: {smiles}")
print(f"InChI: {Chem.MolToInchi(mol)}")
print(f"Canonical SMILES: {Chem.MolToSmiles(mol)}")
print(f"分子式: {Chem.rdMolDescriptors.CalcMolFormula(mol)}")
print("=" * 40)
ID: 1
SMILES: CCO
InChI: InChI=1S/C2H6O/c1-2-3/h3H,2H2,1H3
Canonical SMILES: CCO
分子式: C2H6O
========================================
SDMolSupplier 一次全部读完——用 ForwardSDMolSupplier 做流式读取,内存占用会从几个 G 降到几十 M。
2.4 分子图的第一步:从 SMILES 到图结构
好了,到这里你手上已经有了一个 RDKit 分子对象。
接下来就是把分子变成图。
我画了一张流程示意图,帮你快速建立直观理解:
你心里可能会想:这张图我大概能看懂,但实际代码怎么写?
嗯,别急,下一章就会手把手教你如何从 RDKit 对象中提取节点特征和边的邻接矩阵。
现在,先确保你完成了以下三件事:
- 用 conda 装好 RDKit 并通过验证
- 能从一个 SMILES 字符串生成分子对象,并转换到 InChI
- 能读取并解析一个简单的 .sdf 文件
如果你在做第三步时碰到了编码问题(比如中文属性乱码),别慌——
我曾经在某个项目中碰到的 .sdf 文件是用 GBK 编码的,RDKit 默认用 UTF-8 读取,结果属性全是乱码。
解决办法是:先用 open() 指定编码读入,再传给 SDMolSupplier。
from rdkit import Chem
with open("data_gbk.sdf", encoding="gbk") as f:
content = f.read()
supplier = Chem.SDMolSupplier()
supplier.SetData(content)
for mol in supplier:
if mol:
print(mol.GetProp("名称"))
看见了没?
很多坑其实就藏在文件的编码里。
但只要你掌握了 RDKit 这套基础工具流,后面构建分子图就会顺滑很多。
嗯,这一章的内容就到这里。
该装的环境装了,该试的代码试了,接下来我们要真正走进分子图的世界了。