关于 datamol-cheminformatics
datamol-cheminformatics 是一项使用 Datamol 进行化学信息学和药物发现的技能。它以 Python 接口简化常见分子分析,同时保留与 RDKit 原生分子对象的兼容性。
主要功能
- 01解析并标准化分子结构
- 02计算描述符和指纹
- 03聚类化合物并筛选多样分子
- 04提取骨架并进行分子片段化
- 05生成 3D 构象
- 06读写分子数据文件
适用场景
- 01验证并清理 SMILES 或化合物文件
- 02为机器学习准备分子特征
- 03比较并聚类化合物库
- 04生成构象用于分子分析
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ jaechang-hits/ sciagent-skills --skill datamol-cheminformatics安装后在 Claude Code 中输入/datamol-cheminformatics确认已加载。
详细介绍
Datamol 化学信息学工具包
概述
Datamol 为 RDKit 提供轻量级、符合 Python 风格的抽象层,用于分子化学信息学。它简化了常见的药物发现操作——SMILES 解析、标准化、描述符、指纹、聚类、骨架、构象生成和可视化,并提供合理的默认设置、内置并行处理,以及通过 fsspec 支持云存储。所有分子对象都是原生的 rdkit.Chem.Mol 实例,确保与 RDKit 完全兼容。
适用场景
- 从 SMILES、SDF 或其他格式解析、验证和标准化分子结构
- 计算分子描述符和指纹,用于机器学习特征工程
- 在化合物库中进行相似性搜索和多样性筛选
- 按结构相似性对化合物进行聚类(Butina 聚类)
- 进行骨架分析,以及基于骨架划分机器学习训练集和测试集
- 使用 BRICS/RECAP 进行分子片段化,以支持基于片段的设计
- 生成和分析 3D 构象
- 将分子可视化为网格,并进行对齐和高亮显示
- 并行处理分子数据集
- 如需快速查询基因,请改用 gget;如需高级子结构查询或自定义指纹,请直接使用 RDKit
先决条件
uv pip install datamol
import datamol as dm
import numpy as np
import pandas as pd
快速开始
import datamol as dm
# Parse and standardize
mol = dm.to_mol("CC(=O)Oc1ccccc1C(=O)O") # Aspirin
mol = dm.standardize_mol(mol)
print(dm.to_smiles(mol)) # Canonical SMILES
# Compute descriptors
desc = dm.descriptors.compute_many_descriptors(mol)
print(f"MW: {desc['mw']:.1f}, LogP: {desc['logp']:.2f}, TPSA: {desc['tpsa']:.1f}")
# Generate fingerprint
fp = dm.to_fp(mol, fp_type='ecfp', radius=2, n_bits=2048)
print(f"Fingerprint shape: {fp.shape}") # (2048,)
核心 API
1. 分子输入/输出与标准化
解析分子:
import datamol as dm
# From SMILES (returns None on failure)
mol = dm.to_mol("CCO")
if mol is None:
print("Invalid SMILES")
# Format conversions
smiles = dm.to_smiles(mol, isomeric=True) # Canonical SMILES
inchi = dm.to_inchi(mol)
inchikey = dm.to_inchikey(mol)
selfies = dm.to_selfies(mol)
标准化(强烈建议用于外部数据):
mol = dm.standardize_mol(
mol,
disconnect_metals=True,
normalize=True,
reionize=True
)
clean_smiles = dm.standardize_smiles("C(C)O") # From SMILES directly
文件输入/输出:
# Reading (supports local, S3, GCS, HTTP via fsspec)
df = dm.read_sdf("compounds.sdf", mol_column='mol')
df = dm.read_csv("data.csv", smiles_column="SMILES", mol_column="mol")
df = dm.read_excel("compounds.xlsx", sheet_name=0, mol_column="mol")
df = dm.open_df("file.sdf") # Auto-detect format
# Writing
dm.to_sdf(df, "output.sdf", mol_column="mol")
dm.to_smi(mols, "output.smi")
dm.to_xlsx(df, "output.xlsx", mol_columns=["mol"]) # Renders molecule images
# Remote files
df = dm.read_sdf("s3://bucket/compounds.sdf")
dm.to_sdf(mols, "s3://bucket/output.sdf")
2. 描述符与属性
import datamol as dm
mol = dm.to_mol("c1ccc(cc1)CCN")
# Standard descriptor set (single molecule)
desc = dm.descriptors.compute_many_descriptors(mol)
# Returns dict: {'mw': 121.18, 'logp': 1.41, 'hbd': 1, 'hba': 1,
# 'tpsa': 26.02, 'n_aromatic_atoms': 6, ...}
# Batch computation (parallel)
mols = [dm.to_mol(s) for s in ["CCO", "c1ccccc1", "CC(=O)O"]]
desc_df = dm.descriptors.batch_compute_many_descriptors(
mols, n_jobs=-1, progress=True
)
print(desc_df.head())
# Specific descriptors
n_stereo = dm.descriptors.n_stereo_centers(mol)
n_aromatic = dm.descriptors.n_aromatic_atoms(mol)
aromatic_ratio = dm.descriptors.n_aromatic_atoms_proportion(mol)
n_rigid = dm.descriptors.n_rigid_bonds(mol)
类药性筛选(Lipinski 五法则):
def is_druglike(mol):
desc = dm.descriptors.compute_many_descriptors(mol)
return (desc['mw'] <= 500 and desc['logp'] <= 5
and desc['hbd'] <= 5 and desc['hba'] <= 10)
druglike = [m for m in mols if is_druglike(m)]
print(f"Drug-like: {len(druglike)}/{len(mols)}")
3. 指纹与相似性
import datamol as dm
mol = dm.to_mol("c1ccc(cc1)CCN")
# Fingerprint types
fp_ecfp = dm.to_fp(mol, fp_type='ecfp', radius=2, n_bits=2048) # Morgan/ECFP
fp_maccs = dm.to_fp(mol, fp_type='maccs') # MACCS keys (167 bits)
fp_topo = dm.to_fp(mol, fp_type='topological') # Topological
fp_ap = dm.to_fp(mol, fp_type='atompair') # Atom pairs
# Pairwise distances (Tanimoto distance = 1 - similarity)
mols = [dm.to_mol(s) for s in ["CCO", "CCCO", "c1ccccc1"]]
dist_matrix = dm.pdist(mols, n_jobs=-1)
print(f"Distance vector shape: {dist_matrix.shape}")
# Distances between two sets
query = [dm.to_mol("CCO")]
library = [dm.to_mol(s) for s in ["CCCO", "c1ccccc1", "CC(=O)O"]]
distances = dm.cdist(query, library, n_jobs=-1)
print(f"Query-library distances: {distances.shape}")
4. 聚类与多样性筛选
import datamol as dm
mols = [dm.to_mol(s) for s in smiles_list] # Assume smiles_list defined
# Butina clustering (suitable for ~1000 molecules, builds full distance matrix)
clusters = dm.cluster_mols(mols, cutoff=0.2, n_jobs=-1)
for i, cluster in enumerate(clusters[:5]):
print(f"Cluster {i}: {len(cluster)} molecules")
# Diversity selection (works for larger libraries)
diverse_mols = dm.pick_diverse(mols, npick=100)
print(f"Selected {len(diverse_mols)} diverse molecules")
# Cluster centroids
centroids = dm.pick_centroids(mols, npick=50)
print(f"Selected {len(centroids)} centroids")
5. 骨架与片段
Murcko 骨架提取:
import datamol as dm
from collections import Counter
mol = dm.to_mol("c1ccc(cc1)CCN")
scaffold = dm.to_scaffold_murcko(mol)
print(f"Scaffold: {dm.to_smiles(scaffold)}")
# Scaffold frequency analysis
scaffolds = [dm.to_scaffold_murcko(m) for m in mols]
scaffold_smiles = [dm.to_smiles(s) for s in scaffolds]
counts = Counter(scaffold_smiles)
print(f"Top scaffolds: {counts.most_common(5)}")
# Scaffold-based train/test split (for ML)
scaffold_to_mols = {}
for mol, scaf in zip(mols, scaffold_smiles):
scaffold_to_mols.setdefault(scaf, []).append(mol)
scaffolds_list = list(scaffold_to_mols.keys())
split_idx = int(0.8 * len(scaffolds_list))
train_mols = [m for s in scaffolds_list[:split_idx] for m in scaffold_to_mols[s]]
test_mols = [m for s in scaffolds_list[split_idx:] for m in scaffold_to_mols[s]]
片段化:
mol = dm.to_mol("CC(=O)Oc1ccccc1C(=O)O") # Aspirin
# BRICS (16 bond types, retrosynthetic)
brics_frags = dm.fragment.brics(mol)
print(f"BRICS fragments: {brics_frags}") # Set of fragment SMILES with [1*] attachment points
# RECAP (11 bond types, combinatorial)
recap_frags = dm.fragment.recap(mol)
# MMPA (matched molecular pair analysis)
mmpa_frags = dm.fragment.mmpa_frag(mol)
6. 3D 构象
import datamol as dm
mol = dm.to_mol("c1ccc(cc1)CCN")
# Generate conformers
mol_3d = dm.conformers.generate(
mol,
n_confs=50, # Number to generate
rms_cutoff=0.5, # Filter similar (Angstroms)
minimize_energy=True, # UFF minimization
method='ETKDGv3' # Embedding method
)
print(f"Generated {mol_3d.GetNumConformers()} conformers")
# Access coordinates
conf = mol_3d.GetConformer(0)
positions = conf.GetPositions() # Nx3 array
print(f"Atom positions shape: {positions.shape}")
# Cluster conformers by RMSD
clusters = dm.conformers.cluster(mol_3d, rms_cutoff=1.0)
centroids = dm.conformers.return_centroids(mol_3d, clusters)
# Solvent accessible surface area
sasa = dm.conformers.sasa(mol_3d, n_jobs=-1)
print(f"SASA values: {sasa[:3]}")
关键概念
Datamol 与 RDKit 选择指南
| 使用 Datamol 的场景…… | 直接使用 RDKit 的场景…… |
|---|---|
| 标准 SMILES ↔ Mol 转换 | 自定义指纹定义 |
| 并行处理批量数据 | 底层原子/键操作 |
| 快速计算描述符 | 子结构查询优化 |
| 文件输入/输出(SDF、CSV、Excel、云端) | 大规模反应枚举 |
| 聚类与多样性筛选 | 自定义力场参数 |
| 骨架分析 | 高级立体化学处理 |
关键数据类型
- 所有分子都是原生的
rdkit.Chem.Mol对象,可与 RDKit 函数完全兼容 - 指纹是 numpy 数组(稠密位向量)
- DataFrame 使用 pandas,其中
mol列包含 Mol 对象 - 距离矩阵使用 Tanimoto 距离(0 = 完全相同,1 = 完全不同)
并行处理
支持 n_jobs 参数的函数:dm.read_sdf、dm.descriptors.batch_compute_many_descriptors、dm.cluster_mols、dm.pdist、dm.cdist、dm.conformers.sasa。使用 n_jobs=-1 可利用所有核心,使用 progress=True 可显示进度条。
常见工作流
1. 药物发现流程:加载 → 筛选 → 聚类 → 可视化
import datamol as dm
# 1. Load and standardize
df = dm.read_sdf("compounds.sdf")
df['mol'] = df['mol'].apply(lambda m: dm.standardize_mol(m) if m else None)
df = df[df['mol'].notna()]
print(f"Loaded {len(df)} valid molecules")
# 2. Compute descriptors and filter by drug-likeness
desc_df = dm.descriptors.batch_compute_many_descriptors(
df['mol'].tolist(), n_jobs=-1, progress=True
)
druglike = (desc_df['mw'] <= 500) & (desc_df['logp'] <= 5) & (desc_df['hbd'] <= 5) & (desc_df['hba'] <= 10)
filtered_df = df[druglike.values].reset_index(drop=True)
print(f"Drug-like compounds: {len(filtered_df)}")
# 3. Select diverse subset
diverse = dm.pick_diverse(filtered_df['mol'].tolist(), npick=100)
# 4. Visualize
dm.viz.to_image(diverse[:20], legends=[dm.to_smiles(m) for m in diverse[:20]],
n_cols=5, mol_size=(300, 300), outfile="diverse_hits.png")
2. 虚拟筛选:查询 → 相似性计算 → 排序
import datamol as dm
import numpy as np
# Query actives and screening library
actives = [dm.to_mol(s) for s in active_smiles] # Known actives
library = [dm.to_mol(s) for s in library_smiles] # Screening library
# Calculate distances (Tanimoto)
distances = dm.cdist(actives, library, n_jobs=-1)
min_distances = distances.min(axis=0) # Best match to any active
similarities = 1 - min_distances
# Rank and select top hits
top_idx = np.argsort(similarities)[::-1][:100]
top_hits = [library[i] for i in top_idx]
top_scores = [similarities[i] for i in top_idx]
print(f"Top hit similarity: {top_scores[0]:.3f}")
# Visualize top hits
dm.viz.to_image(top_hits[:20],
legends=[f"Sim: {s:.3f}" for s in top_scores[:20]],
outfile="screening_hits.png")
3. SAR 分析:按骨架分组 → 比较活性
import datamol as dm
# Group compounds by scaffold
scaffolds = [dm.to_scaffold_murcko(m) for m in mols]
scaffold_smiles = [dm.to_smiles(s) for s in scaffolds]
sar_df = pd.DataFrame({
'mol': mols, 'scaffold': scaffold_smiles, 'activity': activities
})
# Analyze each scaffold series
for scaffold, group in sar_df.groupby('scaffold'):
if len(group) >= 3:
print(f"Scaffold: {scaffold} | N={len(group)} | "
f"Activity: {group['activity'].min():.2f}–{group['activity'].max():.2f}")
dm.viz.to_image(group['mol'].tolist(), align=True,
legends=[f"Act: {a:.2f}" for a in group['activity']])
关键参数
| 函数 | 参数 | 默认值 | 说明 |
|---|---|---|---|
dm.to_fp | fp_type | 'ecfp' | 指纹类型:ecfp、maccs、topological、atompair |
dm.to_fp | radius | 2 | Morgan 半径(仅适用于 ecfp);radius=2 ≈ ECFP4 |
dm.to_fp | n_bits | 2048 | 指纹长度(ecfp、topological) |
dm.cluster_mols | cutoff | 0.2 | Tanimoto 距离阈值(0=相同,1=不同) |
dm.pick_diverse | npick | required | 要选择的多样化分子数量 |
dm.conformers.generate | n_confs | None | 构象数量(None = 自动) |
dm.conformers.generate | rms_cutoff | None | RMSD 筛选阈值(埃) |
dm.conformers.generate | method | 'ETKDGv3' | 嵌入方法:ETKDGv3、ETKDGv2、ETKDG |
dm.standardize_mol | disconnect_metals | False | 移除金属-配体键 |
dm.read_sdf | sanitize | True | 对分子进行清理 |
dm.read_sdf | remove_hs | True | 移除显式氢原子 |
dm.viz.to_image | align | False | 按 MCS 对齐分子 |
dm.viz.to_image | use_svg | False | 输出 SVG(True)或 PNG(False) |
最佳实践
- 始终标准化来自外部来源的分子 — 在任何分析之前,调用
dm.standardize_mol()并设置disconnect_metals=True, normalize=True, reionize=True。同一分子的不同 SMILES 表示会产生不同的指纹 - 解析后检查是否为 None — 对于无效的 SMILES,
dm.to_mol()会返回None。在批量操作前过滤这些值,以避免崩溃 - 对数据集使用并行处理 — 将
n_jobs=-1, progress=True传递给批量操作。对 10,000 个以上的分子进行顺序处理会不必要地拖慢速度 - 根据用途选择指纹 — ECFP(Morgan):适用于通用结构相似性;MACCS:速度快、空间较小;Atom pairs:对距离敏感。radius=2、n_bits=2048 的 ECFP 是最常见的默认设置
- 注意聚类规模限制 — Butina 聚类(
dm.cluster_mols)会构建完整的距离矩阵,适用于 ≤~1,000 个分子。对于更大的集合,请使用dm.pick_diverse()或层次聚类方法 - 机器学习使用骨架拆分 — 随机拆分会导致相似结构泄漏到训练集和测试集中。分子性质预测模型应始终使用基于骨架的拆分
- 利用 fsspec 处理云端数据 — 所有 I/O 函数都直接接受 S3、GCS 和 HTTP 路径。安装
s3fs或gcsfs即可支持云端数据
常见配方
配方:批量验证和标准化 SMILES
适用场景:在后续分析之前清理一组 SMILES 字符串。
import datamol as dm
smiles_list = ["CC(=O)Oc1ccccc1C(=O)O", "c1ccccc1", "invalid_smiles", "CC(N)C(=O)O"]
mols = [dm.to_mol(s) for s in smiles_list]
valid = [(s, m) for s, m in zip(smiles_list, mols) if m is not None]
standardized = [(s, dm.standardize_mol(m)) for s, m in valid]
print(f"Valid: {len(valid)}/{len(smiles_list)}")
for orig, mol in standardized:
print(f" {orig} → {dm.to_smiles(mol)}")
配方:成对相似度矩阵
适用场景:比较一小组化合物之间的相似度,或与参考库进行比较。
import datamol as dm
import numpy as np
smiles = ["CC(=O)Oc1ccccc1C(=O)O", "c1ccc(cc1)C(=O)O", "CC(N)C(=O)O", "c1ccccc1"]
mols = [dm.to_mol(s) for s in smiles]
fps = [dm.to_fp(m) for m in mols]
# Pairwise Tanimoto similarity
n = len(fps)
sim_matrix = np.zeros((n, n))
for i in range(n):
for j in range(n):
sim_matrix[i, j] = dm.similarity.tanimoto(fps[i], fps[j])
print(f"Similarity matrix shape: {sim_matrix.shape}")
print(f"Most similar pair: {np.unravel_index(np.argsort(sim_matrix.ravel())[-3], (n, n))}")
故障排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
dm.to_mol() 返回 None | SMILES 无效或非规范 | 先尝试 dm.standardize_smiles();检查是否存在 Kekulé 化问题 |
| 聚类时出现 MemoryError | 大型数据集需要完整距离矩阵 | 对于超过 1000 个分子,请使用 dm.pick_diverse(),而非 dm.cluster_mols |
| 构象生成缓慢 | 构象数量过多或分子过大 | 减少 n_confs,增大 rms_cutoff,或限制分子大小 |
| 远程文件访问失败 | 缺少 fsspec 后端 | 安装 s3fs(AWS)、gcsfs(GCP)或 adlfs(Azure) |
| 描述符计算失败 | 分子没有构象 | 先进行标准化;某些 3D 描述符需要调用 dm.conformers.generate() |
dm.to_xlsx 缺少图像 | 未安装 openpyxl | uv pip install openpyxl |
| 指纹不一致 | 同一分子使用了不同的 SMILES | 计算指纹前先对所有分子进行标准化 |
| 骨架提取返回完整分子 | 分子中没有环系 | Murcko 骨架至少需要一个环;无环分子会返回其自身 |
| 反应产物为 None | 反应物与 SMARTS 模式不匹配 | 确认反应物与反应模板匹配;检查原子映射 |
导入 dm.viz 时出错 | 缺少可视化依赖项 | uv pip install Pillow cairosvg |
相关技能
- rdkit-cheminformatics — 提供完整的 RDKit API,用于执行 datamol 简化接口未涵盖的高级操作
- pubchem-compound-search — 按名称、CID 或结构从 PubChem 获取化合物数据
- scikit-learn-machine-learning — 使用 datamol 生成的特征训练 ML 模型
- matplotlib-scientific-plotting — 自定义适合发表的分子属性图
参考资料
- Datamol 文档:https://docs.datamol.io/
- RDKit 文档:https://www.rdkit.org/docs/
- GitHub 仓库:https://github.com/datamol-io/datamol
- Bemis, G. W. & Murcko, M. A. (1996). The Properties of Known Drugs. J. Med. Chem. 39(15), 2887–2893
评论
支持 Markdown