Compétence Cheminformatique Datamol
Vue d'ensemble
Datamol est une bibliothèque Python qui fournit une couche d'abstraction légère et pythonique au-dessus de RDKit pour la cheminformatique moléculaire. Simplifiez les opérations moléculaires complexes avec des valeurs par défaut sensées, une parallélisation efficace et des capacités I/O modernes. Tous les objets moléculaires sont des instances natives rdkit.Chem.Mol, garantissant une compatibilité complète avec l'écosystème RDKit.
Capacités clés :
- Conversion de formats moléculaires (SMILES, SELFIES, InChI)
- Standardisation et assainissement de structures
- Descripteurs moléculaires et empreintes digitales
- Génération et analyse de conformères 3D
- Clustering et sélection de diversité
- Analyse de squelettes et de fragments
- Application de réactions chimiques
- Visualisation et alignement
- Traitement par lots avec parallélisation
- Support du stockage cloud via fsspec
Installation et configuration
Guide pour installer datamol :
uv pip install datamol
Convention d'importation :
import datamol as dm
Workflows principaux
1. Manipulation basique de molécules
Créer des molécules à partir de SMILES :
import datamol as dm
# Molécule unique
mol = dm.to_mol("CCO") # Ethanol
# À partir d'une liste de SMILES
smiles_list = ["CCO", "c1ccccc1", "CC(=O)O"]
mols = [dm.to_mol(smi) for smi in smiles_list]
# Gestion des erreurs
mol = dm.to_mol("invalid_smiles") # Retourne None
if mol is None:
print("Failed to parse SMILES")
Convertir des molécules en SMILES :
# SMILES canonique
smiles = dm.to_smiles(mol)
# SMILES isomérique (inclut la stéréochimie)
smiles = dm.to_smiles(mol, isomeric=True)
# Autres formats
inchi = dm.to_inchi(mol)
inchikey = dm.to_inchikey(mol)
selfies = dm.to_selfies(mol)
Standardisation et assainissement (toujours recommandé pour les molécules fournies par l'utilisateur) :
# Assainir la molécule
mol = dm.sanitize_mol(mol)
# Standardisation complète (recommandée pour les ensembles de données)
mol = dm.standardize_mol(
mol,
disconnect_metals=True,
normalize=True,
reionize=True
)
# Pour les chaînes SMILES directement
clean_smiles = dm.standardize_smiles(smiles)
2. Lecture et écriture de fichiers moléculaires
Consultez references/io_module.md pour la documentation complète de l'I/O.
Lecture de fichiers :
# Fichiers SDF (les plus courants en chimie)
df = dm.read_sdf("compounds.sdf", mol_column='mol')
# Fichiers SMILES
df = dm.read_smi("molecules.smi", smiles_column='smiles', mol_column='mol')
# CSV avec colonne SMILES
df = dm.read_csv("data.csv", smiles_column="SMILES", mol_column="mol")
# Fichiers Excel
df = dm.read_excel("compounds.xlsx", sheet_name=0, mol_column="mol")
# Lecteur universel (détection automatique du format)
df = dm.open_df("file.sdf") # Fonctionne avec .sdf, .csv, .xlsx, .parquet, .json
Écriture de fichiers :
# Enregistrer en SDF
dm.to_sdf(mols, "output.sdf")
# Ou à partir d'un DataFrame
dm.to_sdf(df, "output.sdf", mol_column="mol")
# Enregistrer en fichier SMILES
dm.to_smi(mols, "output.smi")
# Excel avec images de molécules rendues
dm.to_xlsx(df, "output.xlsx", mol_columns=["mol"])
Support des fichiers distants (S3, GCS, HTTP) :
# Lire depuis le stockage cloud
df = dm.read_sdf("s3://bucket/compounds.sdf")
df = dm.read_csv("https://example.com/data.csv")
# Écrire vers le stockage cloud
dm.to_sdf(mols, "s3://bucket/output.sdf")
3. Descripteurs et propriétés moléculaires
Consultez references/descriptors_viz.md pour la documentation détaillée des descripteurs.
Calcul de descripteurs pour une molécule unique :
# Obtenir l'ensemble standard de descripteurs
descriptors = dm.descriptors.compute_many_descriptors(mol)
# Retourne : {'mw': 46.07, 'logp': -0.03, 'hbd': 1, 'hba': 1,
# 'tpsa': 20.23, 'n_aromatic_atoms': 0, ...}
Calcul de descripteurs par lot (recommandé pour les ensembles de données) :
# Calculer pour toutes les molécules en parallèle
desc_df = dm.descriptors.batch_compute_many_descriptors(
mols,
n_jobs=-1, # Utiliser tous les cœurs CPU
progress=True # Afficher la barre de progression
)
Descripteurs spécifiques :
# Aromaticité
n_aromatic = dm.descriptors.n_aromatic_atoms(mol)
aromatic_ratio = dm.descriptors.n_aromatic_atoms_proportion(mol)
# Stéréochimie
n_stereo = dm.descriptors.n_stereo_centers(mol)
n_unspec = dm.descriptors.n_stereo_centers_unspecified(mol)
# Flexibilité
n_rigid = dm.descriptors.n_rigid_bonds(mol)
Filtrage de ressemblance aux médicaments (Règle de Lipinski des Cinq) :
# Filtrer les composés
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_mols = [mol for mol in mols if is_druglike(mol)]
4. Empreintes digitales moléculaires et similarité
Génération d'empreintes digitales :
# ECFP (Extended Connectivity Fingerprint, par défaut)
fp = dm.to_fp(mol, fp_type='ecfp', radius=2, n_bits=2048)
# Autres types d'empreintes
fp_maccs = dm.to_fp(mol, fp_type='maccs')
fp_topological = dm.to_fp(mol, fp_type='topological')
fp_atompair = dm.to_fp(mol, fp_type='atompair')
Calculs de similarité :
# Distances par paires dans un ensemble
distance_matrix = dm.pdist(mols, n_jobs=-1)
# Distances entre deux ensembles
distances = dm.cdist(query_mols, library_mols, n_jobs=-1)
# Trouver les molécules les plus similaires
from scipy.spatial.distance import squareform
dist_matrix = squareform(dm.pdist(mols))
# Distance inférieure = similarité supérieure (distance Tanimoto = 1 - similarité Tanimoto)
5. Clustering et sélection de diversité
Consultez references/core_api.md pour les détails du clustering.
Clustering Butina :
# Grouper les molécules par similarité structurale
clusters = dm.cluster_mols(
mols,
cutoff=0.2, # Seuil de distance Tanimoto (0=identique, 1=complètement différent)
n_jobs=-1 # Traitement parallèle
)
# Chaque cluster est une liste d'indices de molécules
for i, cluster in enumerate(clusters):
print(f"Cluster {i}: {len(cluster)} molecules")
cluster_mols = [mols[idx] for idx in cluster]
Important : Le clustering Butina construit une matrice de distance complète - adapté pour ~1 000 molécules, pas pour 10 000+.
Sélection de diversité :
# Sélectionner un sous-ensemble diversifié
diverse_mols = dm.pick_diverse(
mols,
npick=100 # Sélectionner 100 molécules diversifiées
)
# Sélectionner les centroïdes des clusters
centroids = dm.pick_centroids(
mols,
npick=50 # Sélectionner 50 molécules représentatives
)
6. Analyse de squelettes
Consultez references/fragments_scaffolds.md pour la documentation complète des squelettes.
Extraction de squelettes Murcko :
# Obtenir le squelette Bemis-Murcko (structure de base)
scaffold = dm.to_scaffold_murcko(mol)
scaffold_smiles = dm.to_smiles(scaffold)
Analyse basée sur les squelettes :
# Grouper les composés par squelette
from collections import Counter
scaffolds = [dm.to_scaffold_murcko(mol) for mol in mols]
scaffold_smiles = [dm.to_smiles(s) for s in scaffolds]
# Compter la fréquence des squelettes
scaffold_counts = Counter(scaffold_smiles)
most_common = scaffold_counts.most_common(10)
# Créer un mappage squelette-vers-molécules
scaffold_groups = {}
for mol, scaf_smi in zip(mols, scaffold_smiles):
if scaf_smi not in scaffold_groups:
scaffold_groups[scaf_smi] = []
scaffold_groups[scaf_smi].append(mol)
Partage train/test basé sur les squelettes (pour le ML) :
# Assurer que les ensembles train et test ont des squelettes différents
scaffold_to_mols = {}
for mol, scaf in zip(mols, scaffold_smiles):
if scaf not in scaffold_to_mols:
scaffold_to_mols[scaf] = []
scaffold_to_mols[scaf].append(mol)
# Partager les squelettes en train/test
import random
scaffolds = list(scaffold_to_mols.keys())
random.shuffle(scaffolds)
split_idx = int(0.8 * len(scaffolds))
train_scaffolds = scaffolds[:split_idx]
test_scaffolds = scaffolds[split_idx:]
# Obtenir les molécules pour chaque partition
train_mols = [mol for scaf in train_scaffolds for mol in scaffold_to_mols[scaf]]
test_mols = [mol for scaf in test_scaffolds for mol in scaffold_to_mols[scaf]]
7. Fragmentation moléculaire
Consultez references/fragments_scaffolds.md pour les détails de fragmentation.
Fragmentation BRICS (16 types de liaisons) :
# Fragmenter la molécule
fragments = dm.fragment.brics(mol)
# Retourne : ensemble de SMILES de fragments avec points d'attachement comme '[1*]CCN'
Fragmentation RECAP (11 types de liaisons) :
fragments = dm.fragment.recap(mol)
Analyse de fragments :
# Trouver les fragments courants dans la bibliothèque de composés
from collections import Counter
all_fragments = []
for mol in mols:
frags = dm.fragment.brics(mol)
all_fragments.extend(frags)
fragment_counts = Counter(all_fragments)
common_frags = fragment_counts.most_common(20)
# Score basé sur les fragments
def fragment_score(mol, reference_fragments):
mol_frags = dm.fragment.brics(mol)
overlap = mol_frags.intersection(reference_fragments)
return len(overlap) / len(mol_frags) if mol_frags else 0
8. Génération de conformères 3D
Consultez references/conformers_module.md pour la documentation détaillée des conformères.
Génération de conformères :
# Générer des conformères 3D
mol_3d = dm.conformers.generate(
mol,
n_confs=50, # Nombre à générer (auto si None)
rms_cutoff=0.5, # Filtrer les conformères similaires (Ångströms)
minimize_energy=True, # Minimiser avec le champ de force UFF
method='ETKDGv3' # Méthode d'incorporation (recommandée)
)
# Accéder aux conformères
n_conformers = mol_3d.GetNumConformers()
conf = mol_3d.GetConformer(0) # Obtenir le premier conformère
positions = conf.GetPositions() # Tableau Nx3 des coordonnées des atomes
Clustering de conformères :
# Grouper les conformères par RMSD
clusters = dm.conformers.cluster(
mol_3d,
rms_cutoff=1.0,
centroids=False
)
# Obtenir les conformères représentatifs
centroids = dm.conformers.return_centroids(mol_3d, clusters)
Calcul SASA :
# Calculer la surface accessible au solvant
sasa_values = dm.conformers.sasa(mol_3d, n_jobs=-1)
# Accéder à SASA à partir des propriétés du conformère
conf = mol_3d.GetConformer(0)
sasa = conf.GetDoubleProp('rdkit_free_sasa')
9. Visualisation
Consultez references/descriptors_viz.md pour la documentation de visualisation.
Grille de molécules basique :
# Visualiser les molécules
dm.viz.to_image(
mols[:20],
legends=[dm.to_smiles(m) for m in mols[:20]],
n_cols=5,
mol_size=(300, 300)
)
# Enregistrer dans un fichier
dm.viz.to_image(mols, outfile="molecules.png")
# SVG pour les publications
dm.viz.to_image(mols, outfile="molecules.svg", use_svg=True)
Visualisation alignée (pour l'analyse SAR) :
# Aligner les molécules par sous-structure commune
dm.viz.to_image(
similar_mols,
align=True, # Activer l'alignement MCS
legends=activity_labels,
n_cols=4
)
Mise en évidence de sous-structures :
# Mettre en évidence des atomes et liaisons spécifiques
dm.viz.to_image(
mol,
highlight_atom=[0, 1, 2, 3], # Indices des atomes
highlight_bond=[0, 1, 2] # Indices des liaisons
)
Visualisation de conformères :
# Afficher plusieurs conformères
dm.viz.conformers(
mol_3d,
n_confs=10,
align_conf=True,
n_cols=3
)
10. Réactions chimiques
Consultez references/reactions_data.md pour la documentation des réactions.
Application de réactions :
from rdkit.Chem import rdChemReactions
# Définir la réaction à partir de SMARTS
rxn_smarts = '[C:1](=[O:2])[OH:3]>>[C:1](=[O:2])[Cl:3]'
rxn = rdChemReactions.ReactionFromSmarts(rxn_smarts)
# Appliquer à la molécule
reactant = dm.to_mol("CC(=O)O") # Acide acétique
product = dm.reactions.apply_reaction(
rxn,
(reactant,),
sanitize=True
)
# Convertir en SMILES
product_smiles = dm.to_smiles(product)
Application de réaction par lot :
# Appliquer la réaction à la bibliothèque
products = []
for mol in reactant_mols:
try:
prod = dm.reactions.apply_reaction(rxn, (mol,))
if prod is not None:
products.append(prod)
except Exception as e:
print(f"Reaction failed: {e}")
Parallélisation
Datamol inclut la parallélisation intégrée pour de nombreuses opérations. Utilisez le paramètre n_jobs :
n_jobs=1: Séquentiel (pas de parallélisation)n_jobs=-1: Utiliser tous les cœurs CPU disponiblesn_jobs=4: Utiliser 4 cœurs
Fonctions supportant la parallélisation :
dm.read_sdf(..., n_jobs=-1)dm.descriptors.batch_compute_many_descriptors(..., n_jobs=-1)dm.cluster_mols(..., n_jobs=-1)dm.pdist(..., n_jobs=-1)dm.conformers.sasa(..., n_jobs=-1)
Barres de progression : De nombreuses opérations par lot supportent le paramètre progress=True.
Workflows courants et motifs
Pipeline complet : Chargement de données → Filtrage → Analyse
import datamol as dm
import pandas as pd
# 1. Charger les molécules
df = dm.read_sdf("compounds.sdf")
# 2. Standardiser
df['mol'] = df['mol'].apply(lambda m: dm.standardize_mol(m) if m else None)
df = df[df['mol'].notna()] # Supprimer les molécules non traitées
# 3. Calculer les descripteurs
desc_df = dm.descriptors.batch_compute_many_descriptors(
df['mol'].tolist(),
n_jobs=-1,
progress=True
)
# 4. Filtrer par ressemblance aux médicaments
druglike = (
(desc_df['mw'] <= 500) &
(desc_df['logp'] <= 5) &
(desc_df['hbd'] <= 5) &
(desc_df['hba'] <= 10)
)
filtered_df = df[druglike]
# 5. Grouper et sélectionner un sous-ensemble diversifié
diverse_mols = dm.pick_diverse(
filtered_df['mol'].tolist(),
npick=100
)
# 6. Visualiser les résultats
dm.viz.to_image(
diverse_mols,
legends=[dm.to_smiles(m) for m in diverse_mols],
outfile="diverse_compounds.png",
n_cols=10
)
Analyse de relation structure-activité (SAR)
# Grouper par squelette
scaffolds = [dm.to_scaffold_murcko(mol) for mol in mols]
scaffold_smiles = [dm.to_smiles(s) for s in scaffolds]
# Créer un DataFrame avec les activités
sar_df = pd.DataFrame({
'mol': mols,
'scaffold': scaffold_smiles,
'activity': activities # Données d'activité fournies par l'utilisateur
})
# Analyser chaque série de squelettes
for scaffold, group in sar_df.groupby('scaffold'):
if len(group) >= 3: # Besoin de plusieurs exemples
print(f"\nScaffold: {scaffold}")
print(f"Count: {len(group)}")
print(f"Activity range: {group['activity'].min():.2f} - {group['activity'].max():.2f}")
# Visualiser avec les activités comme légendes
dm.viz.to_image(
group['mol'].tolist(),
legends=[f"Activity: {act:.2f}" for act in group['activity']],
align=True # Aligner par sous-structure commune
)
Pipeline de criblage virtuel
# 1. Générer les empreintes pour la requête et la bibliothèque
query_fps = [dm.to_fp(mol) for mol in query_actives]
library_fps = [dm.to_fp(mol) for mol in library_mols]
# 2. Calculer les similarités
from scipy.spatial.distance import cdist
import numpy as np
distances = dm.cdist(query_actives, library_mols, n_jobs=-1)
# 3. Trouver les correspondances les plus proches (distance min à n'importe quelle requête)
min_distances = distances.min(axis=0)
similarities = 1 - min_distances # Convertir la distance en similarité
# 4. Classer et sélectionner les meilleures correspondances
top_indices = np.argsort(similarities)[::-1][:100] # Top 100
top_hits = [library_mols[i] for i in top_indices]
top_scores = [similarities[i] for i in top_indices]
# 5. Visualiser les correspondances
dm.viz.to_image(
top_hits[:20],
legends=[f"Sim: {score:.3f}" for score in top_scores[:20]],
outfile="screening_hits.png"
)
Documentation de référence
Pour la documentation complète de l'API, consultez ces fichiers de référence :
references/core_api.md: Fonctions de l'espace de noms principal (conversions, standardisation, empreintes, clustering)references/io_module.md: Opérations d'I/O de fichiers (lecture/écriture SDF, CSV, Excel, fichiers distants)references/conformers_module.md: Génération de conformères 3D, clustering, calculs SASAreferences/descriptors_viz.md: Descripteurs moléculaires et fonctions de visualisationreferences/fragments_scaffolds.md: Extraction de squelettes, fragmentation BRICS/RECAPreferences/reactions_data.md: Réactions chimiques et ensembles de données jouets
Bonnes pratiques
-
Toujours standardiser les molécules provenant de sources externes :
mol = dm.standardize_mol(mol, disconnect_metals=True, normalize=True, reionize=True) -
Vérifier les valeurs None après l'analyse de molécules :
mol = dm.to_mol(smiles) if mol is None: # Gérer les SMILES invalides -
Utiliser le traitement parallèle pour les grands ensembles de données :
result = dm.operation(..., n_jobs=-1, progress=True) -
Exploiter fsspec pour le stockage cloud :
df = dm.read_sdf("s3://bucket/compounds.sdf") -
Utiliser les empreintes appropriées pour la similarité :
- ECFP (Morgan) : Usage général, similarité structurale
- MACCS : Rapide, espace de caractéristiques plus petit
- Paires d'atomes : Considère les paires d'atomes et les distances
-
Considérer les limitations d'échelle :
- Clustering Butina : ~1 000 molécules (matrice de distance complète)
- Pour les ensembles plus grands : Utiliser la sélection de diversité ou des méthodes hiérarchiques
-
Partage par squelette pour le ML : Assurer une séparation correcte train/test par squelette
-
Aligner les molécules lors de la visualisation des séries SAR
Gestion des erreurs
# Création sûre de molécules
def safe_to_mol(smiles):
try:
mol = dm.to_mol(smiles)
if mol is not None:
mol = dm.standardize_mol(mol)
return mol
except Exception as e:
print(f"Failed to process {smiles}: {e}")
return None
# Traitement par lot sûr
valid_mols = []
for smiles in smiles_list:
mol = safe_to_mol(smiles)
if mol is not None:
valid_mols.append(mol)
Intégration avec l'apprentissage automatique
# Génération de caractéristiques
X = np.array([dm.to_fp(mol) for mol in mols])
# Ou descripteurs
desc_df = dm.descriptors.batch_compute_many_descriptors(mols, n_jobs=-1)
X = desc_df.values
# Entraîner le modèle
from sklearn.ensemble import RandomForestRegressor
model = RandomForestRegressor()
model.fit(X, y_target)
# Prédire
predictions = model.predict(X_test)
Dépannage
Problème : L'analyse de molécules échoue
- Solution : Utiliser d'abord
dm.standardize_smiles()ou essayerdm.fix_mol()
Problème : Erreurs de mémoire avec le clustering
- Solution : Utiliser
dm.pick_diverse()au lieu du clustering complet pour les grands ensembles
Problème : Génération de conformères lente
- Solution : Réduire
n_confsou augmenterrms_cutoffpour générer moins de conformères
Problème : L'accès aux fichiers distants échoue
- Solution : Assurer que fsspec et les bibliothèques appropriées du fournisseur cloud sont installées (s3fs, gcsfs, etc.)
Ressources supplémentaires
- Documentation Datamol : https://docs.datamol.io/
- Documentation RDKit : https://www.rdkit.org/docs/
- Référentiel GitHub : https://github.com/datamol-io/datamol