datamol-cheminformatics について
datamol-cheminformaticsは、化学情報学や創薬でDatamolを使うためのスキルです。Pythonから一般的な分子解析を行え、RDKitのネイティブ分子オブジェクトとの互換性も保ちます。
主な機能
- 01分子構造の解析と標準化
- 02記述子とフィンガープリントの計算
- 03化合物のクラスタリングと多様性選択
- 04骨格抽出と分子フラグメント化
- 053Dコンフォマーの生成
- 06分子データファイルの読み書き
活用シーン
- 01SMILESや化合物ファイルの検証と整理
- 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、その他の形式から分子構造を解析、検証、標準化する場合
- ML の特徴量化に向けて分子記述子とフィンガープリントを計算する場合
- 化合物ライブラリから類似性検索や多様性に基づく選択を行う場合
- 構造類似性に基づいて化合物をクラスタリングする場合(Butina クラスタリング)
- ML のために骨格解析や骨格ベースの訓練/テスト分割を行う場合
- フラグメントベースの設計に向けて、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)
薬物らしさのフィルタリング(リピンスキーの5つの法則):
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. 骨格とフラグメント
マーカス骨格の抽出:
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列があります - 距離行列にはタンニモト距離を使用します(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 | 必須 | 選択する多様な分子の数 |
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)を出力 |
ベストプラクティス
- 外部ソースから取得した分子は必ず標準化する — あらゆる解析の前に、
disconnect_metals=True, normalize=True, reionize=Trueを指定してdm.standardize_mol()を呼び出します。同じ分子でも SMILES 表現が異なると、フィンガープリントも異なります - パース後に None かどうかを確認する —
dm.to_mol()は無効な SMILES に対して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()または階層的手法を使用します - ML にはスキャフォールド分割を使用する — ランダム分割では、類似した構造が訓練データとテストデータの両方に混入します。分子物性予測モデルには、必ずスキャフォールドに基づく分割を使用します
- クラウドデータには 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、または正規形でない SMILES | まず dm.standardize_smiles() を試し、ケクレ化の問題がないか確認します |
| クラスタリング中に MemoryError が発生する | 大規模なデータセットに対する距離行列全体の作成 | 分子が 1000 個を超える場合は、dm.cluster_mols の代わりに dm.pick_diverse() を使用します |
| コンフォーマー生成が遅い | コンフォーマーが多すぎる、または分子が大きい | 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 骨格には少なくとも 1 つの環が必要です。非環式分子の場合は分子そのものが返されます |
| 反応生成物が None になる | 反応物が SMARTS パターンに一致しない | 反応物が反応テンプレートに一致するか確認し、原子マッピングを確認します |
dm.viz のインポートエラー | 可視化の依存関係がない | uv pip install Pillow cairosvg |
関連スキル
- rdkit-cheminformatics — datamol の簡易インターフェースでは扱われない高度な操作向けの RDKit API 全体
- pubchem-compound-search — PubChem から化合物の名前、CID、または構造で化合物データを取得します
- 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