化学信息学工具初探:从安装到第一个分子

好了,咱们正式开始动手吧。
这一章,我会带你搭建 RDKit 环境,并搞懂两种最常用的分子表示法——SMILES 和 InChI。

为什么会先讲这个?
因为分子图构建的第一步,不是画图,是读数据。

一句话总结:RDKit 是 Python 生态里最成熟的化学信息学工具包,没有之一。我把话放这儿——你后面所有的工作,都离不开它。

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
避坑提醒:我曾经用 pip 装 RDKit,结果在某个版本上碰到了 OpenMP 链接问题,跑了三天才发现是 conda 环境混用的锅。所以听我的——conda + conda-forge,最稳。

装完怎么验证?
跑一行代码就行。

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
个人经验:在项目中,我通常用 SMILES 做快速原型和可视化,用 InChI 做去重和数据库主键。为什么?因为 InChI 不会因为括号写法不同而出现不同字符串——这在建图数据集时太重要了。

来看看 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
========================================
一个小技巧:如果你的 .sdf 文件很大(比如几万条记录),不要用 SDMolSupplier 一次全部读完——用 ForwardSDMolSupplier 做流式读取,内存占用会从几个 G 降到几十 M。

2.4 分子图的第一步:从 SMILES 到图结构

好了,到这里你手上已经有了一个 RDKit 分子对象。
接下来就是把分子变成图。

我画了一张流程示意图,帮你快速建立直观理解:

从 SMILES 到分子图构建流程 SMILES 字符串 RDKit Mol 对象 分子图 (Graph) 节点 & 边特征 GNN 模型输入 节点:原子类型、电荷、价态 边:键序、芳环、立体构型

你心里可能会想:这张图我大概能看懂,但实际代码怎么写?
嗯,别急,下一章就会手把手教你如何从 RDKit 对象中提取节点特征和边的邻接矩阵。

现在,先确保你完成了以下三件事:

  1. 用 conda 装好 RDKit 并通过验证
  2. 能从一个 SMILES 字符串生成分子对象,并转换到 InChI
  3. 能读取并解析一个简单的 .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 这套基础工具流,后面构建分子图就会顺滑很多。

嗯,这一章的内容就到这里。
该装的环境装了,该试的代码试了,接下来我们要真正走进分子图的世界了。