化学信息学的工具很多,但一个项目实际需要的核心工具并不多。这篇给出一个务实的最小工具栈,以及各工具的分工与配合方式。
核心三件套的分工
| 工具 | 定位 | 最擅长 |
|---|---|---|
| RDKit | 事实标准 | 分子处理、指纹、描述符、子结构、构象 |
| OpenBabel | 格式转换器 | 罕见格式的支持(CIF、CML 等) |
| Datamol | RDKit 的便利封装 | 并行处理、常用流程的简化 |
基本原则:能用 RDKit 就用 RDKit。它的化学正确性最有保障、社区最大、文档最全。OpenBabel 只在需要罕见格式时用(见 037《ECFP 指纹详解》 的格式转换讨论)。
Datamol:值得了解的封装
pip install datamol
import datamol as dm
# ---- 简化的常用操作 ----
mol = dm.to_mol("CC(=O)Nc1ccc(O)cc1")
# 标准化(一行完成 RDKit 需要几步的操作)
mol = dm.sanitize_mol(mol)
mol = dm.standardize_mol(mol, disconnect_metals=True,
normalize=True, reionize=True,
uncharge=True)
smiles = dm.to_smiles(mol)
# ---- 【并行处理:Datamol 最有价值的功能】 ----
def process(smi):
m = dm.to_mol(smi)
if m is None:
return None
m = dm.standardize_mol(m)
return dm.to_smiles(m)
results = dm.parallelized(
process, smiles_list,
n_jobs=8,
progress=True, # 【自带进度条】
scheduler="processes",
)
# ---- 描述符批量计算 ----
df = dm.descriptors.batch_compute_many_descriptors(mols, n_jobs=8)
# ---- 便利的 IO ----
df = dm.read_sdf("molecules.sdf", as_df=True)
dm.to_sdf(mols, "output.sdf")
df = dm.read_csv("data.csv", smiles_column="smiles")
# ---- 可视化 ----
dm.to_image(mols[:12], n_cols=4, legends=names[:12])
# ---- 骨架与片段 ----
scaffold = dm.to_scaffold_murcko(mol)
frags = dm.fragment.brics(mol)
# 【Datamol 的价值】:
# 1) 【并行 + 进度条】—— 处理大数据时很实用
# 2) 常用流程的合理默认值
# 3) 与 pandas 的良好集成
#
# 【要注意的】:
# 它封装了 RDKit,出问题时可能需要
# 深入到 RDKit 层面排查
# → 【理解底层的 RDKit 仍然必要】
一个务实的最小工具栈
# 【核心(几乎每个项目都需要)】
#
# rdkit 化学信息学基础(见 013)
# pandas, numpy 数据处理
# scikit-learn 传统机器学习
# lightgbm 【梯度提升——最实用的基线】
# matplotlib/seaborn 可视化
#
# 【常用(按需)】
#
# datamol 并行与流程简化
# mols2grid 【交互式分子表格】(见 217)
# chembl_webresource_client ChEMBL 数据获取(见 226)
# openbabel 罕见格式转换
#
# 【深度学习(如果需要)】
#
# torch
# torch_geometric GNN(见 176)
# chemprop 【分子图模型的成熟实现】(见 131)
# transformers 预训练模型(见 025)
#
# 【结构相关(如果做结构基工作)】
#
# pdbfixer + meeko 结构准备(见 105、106)
# vina / gnina 对接(见 017、016)
# openmm MD(见 015)
# mdanalysis 轨迹分析(见 129)
# prolif / plip 相互作用(见 109、108)
# pymol-open-source 可视化(见 110)
# py3Dmol Notebook 中的三维展示(见 111)
#
# 【工程(团队协作时)】
#
# conda/mamba 环境管理
# mlflow 实验跟踪
# dvc 数据版本管理
#
# 【这个栈能覆盖 80% 以上的常见需求】
# → 【不要一开始就装太多】
环境管理:容易被忽略但很重要
# environment.yml
#
# name: chem
# channels:
# - conda-forge
# dependencies:
# - python=3.11
# - rdkit=2024.03.5 # 【锁定版本】
# - pandas=2.2.*
# - numpy=1.26.*
# - scikit-learn=1.5.*
# - lightgbm=4.5.*
# - jupyterlab
# - pip
# - pip:
# - datamol==0.12.*
# - mols2grid==2.0.*
# 【为什么要锁定版本】:
# 1) 【RDKit 不同版本的行为可能不同】
# 如:芳香性感知、标准化的默认选项
# → 结果不可复现
# 2) 依赖冲突
# 3) 【团队成员的环境一致】
#
# 【推荐用 mamba 而非 conda】:
# 解析速度快得多
# mamba env create -f environment.yml
#
# 【记录环境】:
# conda env export --no-builds > environment.lock.yml
# → 【与代码一起版本管理】
工具选择的常见判断
| 任务 | 推荐 | 不推荐 |
|---|---|---|
| SMILES → 三维构象 | RDKit ETKDG(见 049《构象生成入门》) | OpenBabel --gen3d |
| 分子标准化 | RDKit MolStandardize(见 046《分子标准化》) | — |
| 质子化态 | Dimorphite-DL | OpenBabel -p |
| 格式转换(常见格式) | RDKit | — |
| 格式转换(罕见格式) | OpenBabel | — |
| 转 PDBQT | Meeko(见 106《Meeko》) | OpenBabel |
| PDB 中恢复配体键级 | RDKit + 模板 | 直接推断 |
| 大批量并行处理 | Datamol 或 multiprocessing | 单线程循环 |
| 分子性质预测基线 | ECFP + LightGBM(见 131《Chemprop / D-MPNN 论文精读》) | 直接上深度模型 |
一个可复用的项目模板
# 【推荐的项目结构】
#
# project/
# environment.yml # 环境定义
# data/
# raw/ # 【原始数据,只读】
# processed/ # 处理后的数据
# src/
# data.py # 数据加载与清洗
# features.py # 特征计算
# models.py # 模型定义
# evaluate.py # 【评测(含划分逻辑)】
# notebooks/ # 探索性分析
# scripts/ # 可复现的流程脚本
# results/
# README.md
#
# 【几个关键的工程实践】:
#
# 1) 【原始数据只读】
# 所有处理都生成新文件
# → 出问题能回溯
#
# 2) 【清洗流程写成脚本,不要在 Notebook 里手工做】
# → 可复现
#
# 3) 【固定随机种子并记录】
# 数据划分、模型训练、构象生成
#
# 4) 【评测逻辑单独成模块】
# → 保证所有模型用同样的划分与指标
# → 【避免「不小心用了不同的划分」这类错误】
#
# 5) 【记录每次实验的配置与结果】
# 最简单的做法:一个 CSV 追加记录
# 正式一点:MLflow / Weights & Biases
#
# 6) 【缓存昂贵的计算】
# 指纹、描述符、构象算一次存起来
import functools
import hashlib
import pickle
import os
def disk_cache(cache_dir="cache"):
"""简单的磁盘缓存装饰器"""
os.makedirs(cache_dir, exist_ok=True)
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
key = hashlib.md5(
repr((func.__name__, args, sorted(kwargs.items()))
).encode()).hexdigest()
path = os.path.join(cache_dir, f"{key}.pkl")
if os.path.exists(path):
with open(path, "rb") as f:
return pickle.load(f)
result = func(*args, **kwargs)
with open(path, "wb") as f:
pickle.dump(result, f)
return result
return wrapper
return decorator
@disk_cache()
def compute_fingerprints(smiles_tuple):
...
关键要点
- 能用 RDKit 就用 RDKit——化学正确性最有保障;OpenBabel 只用于罕见格式;
- Datamol 的核心价值是并行处理与进度条,但理解底层 RDKit 仍然必要;
- 必须锁定版本——RDKit 不同版本的芳香性感知与标准化默认值可能不同;
- 评测逻辑单独成模块,保证所有模型用同样的划分与指标。
延伸资源
- RDKit Cookbook:013《RDKit Cookbook》;RDKit 工具:171《RDKit》;格式转换:107《OpenBabel 转格式》;
- 分子标准化:046《分子标准化》;构象生成:049《构象生成入门》;Chemprop:131《Chemprop / D-MPNN 论文精读》。