3. Python与化学信息学:RDKit、Open Babel等工具

说到化学信息学,Python 生态里有两个绕不开的工具——RDKit 和 Open Babel。我个人觉得,搞 SMILES 序列处理,RDKit 是主力,Open Babel 做格式转换更趁手。这章咱们就聊聊这两把“瑞士军刀”怎么用,以及我在项目中踩过哪些坑。

3.1 RDKit:化学信息学的“神兵利器”

RDKit 是一个开源的化学信息学工具包,底层用 C++ 写的,但提供了 Python 接口。它把 SMILES 转成分子对象后,你能干很多事:计算分子量、提取环结构、算指纹,甚至做分子对接前的预处理。

我最早接触 RDKit 是在一个药物筛选项目里。当时要处理几十万条 SMILES,手动清理肯定不现实。RDKit 帮了大忙——几行代码搞定。

核心思想:SMILES 只是字符串,RDKit 把它变成“活”的分子对象。你可以像操作 Python 对象一样操作分子。

3.1.1 安装与基本用法

安装 RDKit 其实挺简单的。我个人习惯用 conda 安装,因为依赖关系处理得比较好。

conda install -c conda-forge rdkit

安装好之后,来看看怎么把 SMILES 转换成分子对象:

from rdkit import Chem
from rdkit.Chem import Descriptors, Draw

# 把 SMILES 转成分子对象
smiles = "CCO"  # 乙醇
mol = Chem.MolFromSmiles(smiles)

if mol is not None:
    print(f"分子式: {Chem.MolToSmiles(mol)}")
    print(f"分子量: {Descriptors.MolWt(mol):.2f}")
    # 原子数
    print(f"原子数: {mol.GetNumAtoms()}")
else:
    print("SMILES 无效")

你看,从字符串到分子对象,一步到位。不过我刚开始用的时候,有个坑:MolFromSmiles 返回 None 时,后续操作全炸。所以记得加个判断。

注意:RDKit 对 SMILES 格式要求严格。比如“C1CC1”这种环写法,它认;“C1CC1(缺失右括号)”就不认。批量处理时,一定要检查返回值。

3.1.2 常用功能:计算性质与指纹

实际应用中,我们常需要计算分子的物理化学性质。RDKit 的 Descriptors 模块直接封装好了。

from rdkit.Chem import Descriptors

mol = Chem.MolFromSmiles("CC(=O)Oc1ccccc1C(=O)O")  # 阿司匹林
mw = Descriptors.MolWt(mol)
logp = Descriptors.MolLogP(mol)
hba = Descriptors.NumHAcceptors(mol)
hbd = Descriptors.NumHDonors(mol)

print(f"分子量: {mw:.2f}, LogP: {logp:.2f}")
print(f"氢键受体: {hba}, 供体: {hbd}")

但有个地方要当心:MolLogP 是预测值,不是实验数据。我曾在项目中直接用这个值做筛选,结果后期验证时发现误差挺大。后来我改成用 MolLogP 做初筛,再用更精确的方法验证。

分子指纹也是常用功能。说白了,就是把分子结构编码成固定长度的二进制向量,用于相似度比较。

from rdkit.Chem import AllChem

mol = Chem.MolFromSmiles("c1ccccc1C(=O)O")  # 苯甲酸
fp = AllChem.GetMorganFingerprintAsBitVect(mol, radius=2, nBits=2048)
# 转成位串
bit_string = fp.ToBitString()
print(f"指纹长度: {len(bit_string)}")
print(f"前50位: {bit_string[:50]}")

小技巧:Morgen 指纹的 radius 参数影响信息量。radius=2 适合大多数任务,但你想捕捉更细的局部结构,可以试试 radius=3。不过指纹越长,计算越慢。

3.2 Open Babel:格式转换的“多面手”

Open Babel 和 RDKit 不一样。它更像一个文件格式转换器,支持超过 110 种化学文件格式。SMILES、SDF、MOL2、PDB……你想从 A 格式转到 B 格式,它基本都能干。

我记得有一次,合作方发来一批 SDF 文件,可我需要的是 SMILES。手动转?别逗了,几万条呢。Open Babel 一行命令就搞定。

3.2.1 安装与命令行用法

同样建议用 conda 安装:

conda install -c openbabel openbabel

装好后,命令行下就能用 obabel 命令。工作流程通常是这样的:

obabel input.sdf -O output.smi

就这么简单。但如果你需要更多选项,比如输出的是规范化的 SMILES:

obabel input.sdf -O output.smi -c

-c 参数表示“规范化”。相信我,没这个参数,同一分子在不同软件里可能会生成不同的 SMILES。

核心思想:RDKit 适合做分子操作和分析,Open Babel 擅长格式转换。两者不冲突,配合使用效果更好。

3.2.2 Python 调用 Open Babel

Open Babel 也提供了 Python 接口,虽然没 RDKit 那么友好,但也够用。

from openbabel import pybel

# 读取 SMILES
mol = pybel.readstring("smi", "CCO")
# 转换成 MOL2 格式
mol.write("mol2", "ethanol.mol2")

# 批量转换
for mol in pybel.readfile("sdf", "data.sdf"):
    smiles = mol.write("smi").strip()
    print(smiles)

不过要注意,Open Babel 的 Python 接口在 Windows 上安装时容易出问题。我曾在 Windows 上折腾了半天,最后老老实实切到 Linux 下用命令行。

避坑指南:千万不要在 Open Babel Python 接口里对大量分子做复杂计算。它慢,而且内存管理不好。我有个同事曾经拿它处理 10 万条 SMILES。结果你猜怎么着?跑了三天,最后内存爆了。改用 RDKit 后,半小时搞定。

3.3 工具对比:什么时候选哪个?

这两个工具各有侧重。我用一个表格总结下:

特性 RDKit Open Babel
核心功能 分子操作与计算 格式转换与导入导出
性能 快(C++ 底层) 中速(命令行快)
Python 接口 非常友好 基础可用,有坑
支持格式 主要化学格式 110+ 种格式
典型场景 分子指纹、性质计算、子结构搜索 文件格式互转、批量格式转换

我个人习惯是:处理数据用 RDKit,互转格式用 Open Babel。当然,如果你只需要其中一个功能,选哪个都行。

3.4 实战案例:用 RDKit 批量处理 SMILES

最后来一个完整的实战案例。假设你有一个 CSV 文件,里面有一列“smiles”,你需要:

  1. 读取每条 SMILES;
  2. 计算分子量和 LogP;
  3. 过滤掉分子量 > 500 或 LogP > 5 的分子;
  4. 输出结果到新 CSV。

用 RDKit 实现:

import csv
from rdkit import Chem
from rdkit.Chem import Descriptors

input_file = "input.csv"
output_file = "filtered.csv"

with open(input_file, "r") as infile, open(output_file, "w", newline="") as outfile:
    reader = csv.DictReader(infile)
    fieldnames = reader.fieldnames + ["MolWt", "LogP"]
    writer = csv.DictWriter(outfile, fieldnames=fieldnames)
    writer.writeheader()
    
    for row in reader:
        smi = row["smiles"]
        mol = Chem.MolFromSmiles(smi)
        if mol is None:
            continue  # 跳过无效 SMILES
        
        mw = Descriptors.MolWt(mol)
        logp = Descriptors.MolLogP(mol)
        
        if mw <= 500 and logp <= 5:
            row["MolWt"] = f"{mw:.2f}"
            row["LogP"] = f"{logp:.2f}"
            writer.writerow(row)

这段代码我实际项目里跑过。当时有 5 万条 SMILES,过滤后剩下 3000 多条,速度很快。需要注意的是:MolLogP 是预测值,如果你要严格标准,可以考虑用更精确的 LogP 计算方法。

经验之谈:处理大批量 SMILES 时,记得用 Chem.SanitizeMol(mol) 先清理一下分子。不清理的话,有些 SMILES 虽然能读进去,但原子价态不对,后续计算会出莫名其妙的结果。我曾经因为这个查了一下午 bug。

Python化学信息学工具工作流程 SMILES字符串 RDKit分子对象 C++底层·Python接口 性质计算 MW·LogP·HBA 指纹计算 Morgan·MACCS 多种文件格式 Open Babel 110+格式互转 转换输出 SDF·MOL2·PDB 最终数据:结构化分子信息 流程:RDKit负责分子操作,OpenBabel负责格式转换,最终输出结构化数据

嗯,以上就是 Python 化学信息学工具链的核心内容。记住:工具是死的,用的人才是关键。别贪多,把 RDKit 玩熟了,应付大多数 SMILES 任务绰绰有余。遇到格式问题,再用 Open Babel 补刀。下次看到 SMILES 别害怕,直接拿它们开刀就对了。