PyDESeq2
Présentation générale
PyDESeq2 est une implémentation Python de DESeq2 pour l'analyse d'expression différentielle avec des données RNA-seq en vrac. Concevez et exécutez des flux de travail complets allant du chargement des données à l'interprétation des résultats, incluant les designs à un seul facteur et multi-facteurs, les tests de Wald avec correction des tests multiples, le rétrécissement optionnel apeGLM et l'intégration avec pandas et AnnData.
Quand utiliser cette compétence
Cette compétence doit être utilisée quand :
- Analyser des données de comptage RNA-seq en vrac pour l'expression différentielle
- Comparer l'expression génique entre conditions expérimentales (p. ex., traité vs contrôle)
- Effectuer des designs multi-facteurs tenant compte des effets de lot ou des covariables
- Convertir des flux de travail DESeq2 basés sur R en Python
- Intégrer l'analyse d'expression différentielle dans des pipelines Python
- Les utilisateurs mentionnent « DESeq2 », « expression différentielle », « analyse RNA-seq » ou « PyDESeq2 »
Flux de travail de démarrage rapide
Pour les utilisateurs qui souhaitent effectuer une analyse d'expression différentielle standard :
import pandas as pd
from pydeseq2.dds import DeseqDataSet
from pydeseq2.ds import DeseqStats
# 1. Charger les données
counts_df = pd.read_csv("counts.csv", index_col=0).T # Transposer en échantillons × gènes
metadata = pd.read_csv("metadata.csv", index_col=0)
# 2. Filtrer les gènes à faible comptage
genes_to_keep = counts_df.columns[counts_df.sum(axis=0) >= 10]
counts_df = counts_df[genes_to_keep]
# 3. Initialiser et ajuster DESeq2
dds = DeseqDataSet(
counts=counts_df,
metadata=metadata,
design="~condition",
refit_cooks=True
)
dds.deseq2()
# 4. Effectuer des tests statistiques
ds = DeseqStats(dds, contrast=["condition", "treated", "control"])
ds.summary()
# 5. Accéder aux résultats
results = ds.results_df
significant = results[results.padj < 0.05]
print(f"Found {len(significant)} significant genes")
Étapes principales du flux de travail
Étape 1 : Préparation des données
Exigences d'entrée :
- Matrice de comptage : DataFrame Échantillons × gènes avec des comptages de lectures entiers non-négatifs
- Métadonnées : DataFrame Échantillons × variables avec des facteurs expérimentaux
Modèles courants de chargement de données :
# À partir d'un CSV (format typique : gènes × échantillons, nécessite une transposition)
counts_df = pd.read_csv("counts.csv", index_col=0).T
metadata = pd.read_csv("metadata.csv", index_col=0)
# À partir d'un TSV
counts_df = pd.read_csv("counts.tsv", sep="\t", index_col=0).T
# À partir d'AnnData
import anndata as ad
adata = ad.read_h5ad("data.h5ad")
counts_df = pd.DataFrame(adata.X, index=adata.obs_names, columns=adata.var_names)
metadata = adata.obs
Filtrage des données :
# Supprimer les gènes à faible comptage
genes_to_keep = counts_df.columns[counts_df.sum(axis=0) >= 10]
counts_df = counts_df[genes_to_keep]
# Supprimer les échantillons avec métadonnées manquantes
samples_to_keep = ~metadata.condition.isna()
counts_df = counts_df.loc[samples_to_keep]
metadata = metadata.loc[samples_to_keep]
Étape 2 : Spécification du design
La formule de design spécifie comment l'expression génique est modélisée.
Designs à un seul facteur :
design = "~condition" # Simple comparaison entre deux groupes
Designs multi-facteurs :
design = "~batch + condition" # Contrôler les effets de lot
design = "~age + condition" # Inclure une covariable continue
design = "~group + condition + group:condition" # Effets d'interaction
Directives pour la formule de design :
- Utiliser la notation de formule Wilkinson (style R)
- Mettre les variables d'ajustement (p. ex., lot) avant la variable d'intérêt principal
- S'assurer que les variables existent en tant que colonnes dans le DataFrame de métadonnées
- Utiliser les types de données appropriés (catégorique pour les variables discrètes)
Étape 3 : Ajustement DESeq2
Initialiser le DeseqDataSet et exécuter le pipeline complet :
from pydeseq2.dds import DeseqDataSet
dds = DeseqDataSet(
counts=counts_df,
metadata=metadata,
design="~condition",
refit_cooks=True, # Réajuster après suppression des valeurs aberrantes
n_cpus=1 # Traitement parallèle (ajuster selon les besoins)
)
# Exécuter le pipeline DESeq2 complet
dds.deseq2()
Ce que fait deseq2() :
- Calcule les facteurs de taille (normalisation)
- Ajuste les dispersions géniques
- Ajuste la courbe de tendance de dispersion
- Calcule les a priori de dispersion
- Ajuste les dispersions MAP (rétrécissement)
- Ajuste les changements de repli logarithmiques
- Calcule les distances de Cook (détection de valeurs aberrantes)
- Réajuste si des valeurs aberrantes sont détectées (optionnel)
Étape 4 : Tests statistiques
Effectuer des tests de Wald pour identifier les gènes exprimés différentiellement :
from pydeseq2.ds import DeseqStats
ds = DeseqStats(
dds,
contrast=["condition", "treated", "control"], # Tester traité vs contrôle
alpha=0.05, # Seuil de significativité
cooks_filter=True, # Filtrer les valeurs aberrantes
independent_filter=True # Filtrer les tests à faible puissance
)
ds.summary()
Spécification du contraste :
- Format :
[variable, test_level, reference_level] - Exemple :
["condition", "treated", "control"]teste traité vs contrôle - Si
None, utilise le dernier coefficient du design
Colonnes du DataFrame de résultats :
baseMean: Comptage normalisé moyen entre les échantillonslog2FoldChange: Changement de repli Log2 entre les conditionslfcSE: Erreur standard du LFCstat: Statistique du test de Waldpvalue: P-valeur brutepadj: P-valeur ajustée (FDR-corrigée via Benjamini-Hochberg)
Étape 5 : Rétrécissement LFC optionnel
Appliquer le rétrécissement pour réduire le bruit dans les estimations de changement de repli :
ds.lfc_shrink() # Applique le rétrécissement apeGLM
Quand utiliser le rétrécissement LFC :
- Pour la visualisation (graphiques de volcan, cartes thermiques)
- Pour classer les gènes par taille d'effet
- Lors de la priorisation de gènes pour des expériences de suivi
Important : Le rétrécissement affecte uniquement les valeurs log2FoldChange, pas les résultats des tests statistiques (les p-valeurs restent inchangées). Utilisez les valeurs rétrécies pour la visualisation mais signalez les p-valeurs non rétrécies pour la significativité.
Étape 6 : Export des résultats
Enregistrer les résultats et les objets intermédiaires :
import pickle
# Exporter les résultats en CSV
ds.results_df.to_csv("deseq2_results.csv")
# Enregistrer uniquement les gènes significatifs
significant = ds.results_df[ds.results_df.padj < 0.05]
significant.to_csv("significant_genes.csv")
# Enregistrer DeseqDataSet pour une utilisation ultérieure
with open("dds_result.pkl", "wb") as f:
pickle.dump(dds.to_picklable_anndata(), f)
Modèles d'analyse courants
Comparaison entre deux groupes
Comparaison cas-contrôle standard :
dds = DeseqDataSet(counts=counts_df, metadata=metadata, design="~condition")
dds.deseq2()
ds = DeseqStats(dds, contrast=["condition", "treated", "control"])
ds.summary()
results = ds.results_df
significant = results[results.padj < 0.05]
Comparaisons multiples
Tester plusieurs groupes de traitement par rapport au contrôle :
dds = DeseqDataSet(counts=counts_df, metadata=metadata, design="~condition")
dds.deseq2()
treatments = ["treatment_A", "treatment_B", "treatment_C"]
all_results = {}
for treatment in treatments:
ds = DeseqStats(dds, contrast=["condition", treatment, "control"])
ds.summary()
all_results[treatment] = ds.results_df
sig_count = len(ds.results_df[ds.results_df.padj < 0.05])
print(f"{treatment}: {sig_count} significant genes")
Tenir compte des effets de lot
Contrôler la variation technique :
# Inclure le lot dans le design
dds = DeseqDataSet(counts=counts_df, metadata=metadata, design="~batch + condition")
dds.deseq2()
# Tester la condition tout en contrôlant le lot
ds = DeseqStats(dds, contrast=["condition", "treated", "control"])
ds.summary()
Covariables continues
Inclure des variables continues comme l'âge ou la dose :
# S'assurer que la variable continue est numérique
metadata["age"] = pd.to_numeric(metadata["age"])
dds = DeseqDataSet(counts=counts_df, metadata=metadata, design="~age + condition")
dds.deseq2()
ds = DeseqStats(dds, contrast=["condition", "treated", "control"])
ds.summary()
Utilisation du script d'analyse
Cette compétence inclut un script en ligne de commande complet pour les analyses standard :
# Utilisation basique
python scripts/run_deseq2_analysis.py \
--counts counts.csv \
--metadata metadata.csv \
--design "~condition" \
--contrast condition treated control \
--output results/
# Avec des options supplémentaires
python scripts/run_deseq2_analysis.py \
--counts counts.csv \
--metadata metadata.csv \
--design "~batch + condition" \
--contrast condition treated control \
--output results/ \
--min-counts 10 \
--alpha 0.05 \
--n-cpus 4 \
--plots
Caractéristiques du script :
- Chargement et validation automatiques des données
- Filtrage des gènes et des échantillons
- Exécution complète du pipeline DESeq2
- Tests statistiques avec paramètres personnalisables
- Export des résultats (CSV, pickle)
- Visualisation optionnelle (graphiques de volcan et MA)
Orienter les utilisateurs vers scripts/run_deseq2_analysis.py quand ils ont besoin d'un outil d'analyse autonome ou souhaitent traiter par lot plusieurs ensembles de données.
Interprétation des résultats
Identification des gènes significatifs
# Filtrer par p-valeur ajustée
significant = ds.results_df[ds.results_df.padj < 0.05]
# Filtrer par significativité et taille d'effet
sig_and_large = ds.results_df[
(ds.results_df.padj < 0.05) &
(abs(ds.results_df.log2FoldChange) > 1)
]
# Séparer les gènes surexprimés et sous-exprimés
upregulated = significant[significant.log2FoldChange > 0]
downregulated = significant[significant.log2FoldChange < 0]
print(f"Upregulated: {len(upregulated)}")
print(f"Downregulated: {len(downregulated)}")
Classement et tri
# Trier par p-valeur ajustée
top_by_padj = ds.results_df.sort_values("padj").head(20)
# Trier par changement de repli absolu (utiliser les valeurs rétrécies)
ds.lfc_shrink()
ds.results_df["abs_lfc"] = abs(ds.results_df.log2FoldChange)
top_by_lfc = ds.results_df.sort_values("abs_lfc", ascending=False).head(20)
# Trier par une métrique combinée
ds.results_df["score"] = -np.log10(ds.results_df.padj) * abs(ds.results_df.log2FoldChange)
top_combined = ds.results_df.sort_values("score", ascending=False).head(20)
Métriques de qualité
# Vérifier la normalisation (les facteurs de taille doivent être proches de 1)
print("Size factors:", dds.obsm["size_factors"])
# Examiner les estimations de dispersion
import matplotlib.pyplot as plt
plt.hist(dds.varm["dispersions"], bins=50)
plt.xlabel("Dispersion")
plt.ylabel("Frequency")
plt.title("Dispersion Distribution")
plt.show()
# Vérifier la distribution des p-valeurs (doit être principalement plate avec un pic près de 0)
plt.hist(ds.results_df.pvalue.dropna(), bins=50)
plt.xlabel("P-value")
plt.ylabel("Frequency")
plt.title("P-value Distribution")
plt.show()
Directives de visualisation
Graphique de volcan
Visualiser la significativité par rapport à la taille d'effet :
import matplotlib.pyplot as plt
import numpy as np
results = ds.results_df.copy()
results["-log10(padj)"] = -np.log10(results.padj)
plt.figure(figsize=(10, 6))
significant = results.padj < 0.05
plt.scatter(
results.loc[~significant, "log2FoldChange"],
results.loc[~significant, "-log10(padj)"],
alpha=0.3, s=10, c='gray', label='Not significant'
)
plt.scatter(
results.loc[significant, "log2FoldChange"],
results.loc[significant, "-log10(padj)"],
alpha=0.6, s=10, c='red', label='padj < 0.05'
)
plt.axhline(-np.log10(0.05), color='blue', linestyle='--', alpha=0.5)
plt.xlabel("Log2 Fold Change")
plt.ylabel("-Log10(Adjusted P-value)")
plt.title("Volcano Plot")
plt.legend()
plt.savefig("volcano_plot.png", dpi=300)
Graphique MA
Afficher le changement de repli par rapport à l'expression moyenne :
plt.figure(figsize=(10, 6))
plt.scatter(
np.log10(results.loc[~significant, "baseMean"] + 1),
results.loc[~significant, "log2FoldChange"],
alpha=0.3, s=10, c='gray'
)
plt.scatter(
np.log10(results.loc[significant, "baseMean"] + 1),
results.loc[significant, "log2FoldChange"],
alpha=0.6, s=10, c='red'
)
plt.axhline(0, color='blue', linestyle='--', alpha=0.5)
plt.xlabel("Log10(Base Mean + 1)")
plt.ylabel("Log2 Fold Change")
plt.title("MA Plot")
plt.savefig("ma_plot.png", dpi=300)
Résolution des problèmes courants
Problèmes de format de données
Problème : « Index mismatch between counts and metadata »
Solution : S'assurer que les noms des échantillons correspondent exactement
print("Counts samples:", counts_df.index.tolist())
print("Metadata samples:", metadata.index.tolist())
# Prendre l'intersection si nécessaire
common = counts_df.index.intersection(metadata.index)
counts_df = counts_df.loc[common]
metadata = metadata.loc[common]
Problème : « All genes have zero counts »
Solution : Vérifier si les données doivent être transposées
print(f"Counts shape: {counts_df.shape}")
# Si gènes > échantillons, la transposition est nécessaire
if counts_df.shape[1] < counts_df.shape[0]:
counts_df = counts_df.T
Problèmes de matrice de design
Problème : « Design matrix is not full rank »
Cause : Variables confondues (p. ex., tous les échantillons traités dans un seul lot)
Solution : Supprimer la variable confondante ou ajouter un terme d'interaction
# Vérifier la confusion
print(pd.crosstab(metadata.condition, metadata.batch))
# Soit simplifier le design, soit ajouter une interaction
design = "~condition" # Supprimer le lot
# OU
design = "~condition + batch + condition:batch" # Modéliser l'interaction
Aucun gène significatif
Diagnostics :
# Vérifier la distribution de dispersion
plt.hist(dds.varm["dispersions"], bins=50)
plt.show()
# Vérifier les facteurs de taille
print(dds.obsm["size_factors"])
# Regarder les gènes principaux par p-valeur brute
print(ds.results_df.nsmallest(20, "pvalue"))
Causes possibles :
- Petites tailles d'effet
- Variabilité biologique élevée
- Taille d'échantillon insuffisante
- Problèmes techniques (effets de lot, valeurs aberrantes)
Documentation de référence
Pour des détails complets au-delà de ce guide orienté flux de travail :
-
Référence API (
references/api_reference.md) : Documentation complète des classes, méthodes et structures de données de PyDESeq2. À utiliser pour obtenir des informations détaillées sur les paramètres ou pour comprendre les attributs d'objets. -
Guide de flux de travail (
references/workflow_guide.md) : Guide détaillé couvrant les flux de travail d'analyse complets, les modèles de chargement de données, les designs multi-facteurs, la résolution de problèmes et les meilleures pratiques. À utiliser pour gérer les designs expérimentaux complexes ou rencontrer des problèmes.
Charger ces références dans le contexte quand les utilisateurs ont besoin de :
- Documentation API détaillée :
Read references/api_reference.md - Exemples de flux de travail complets :
Read references/workflow_guide.md - Directives de résolution de problèmes :
Read references/workflow_guide.md(voir section Troubleshooting)
Points clés à retenir
-
L'orientation des données compte : Les matrices de comptage se chargent généralement sous la forme gènes × échantillons mais doivent être échantillons × gènes. Toujours transposer avec
.Tsi nécessaire. -
Filtrage des échantillons : Supprimer les échantillons avec métadonnées manquantes avant l'analyse pour éviter les erreurs.
-
Filtrage des gènes : Filtrer les gènes à faible comptage (p. ex., < 10 lectures totales) pour améliorer la puissance et réduire le temps de calcul.
-
Ordre de la formule de design : Mettre les variables d'ajustement avant la variable d'intérêt (p. ex.,
"~batch + condition"et non"~condition + batch"). -
Timing du rétrécissement LFC : Appliquer le rétrécissement après les tests statistiques et uniquement pour la visualisation/classement. Les p-valeurs restent basées sur les estimations non rétrécies.
-
Interprétation des résultats : Utiliser
padj < 0.05pour la significativité, pas les p-valeurs brutes. La procédure Benjamini-Hochberg contrôle le taux de fausses découvertes. -
Spécification du contraste : Le format est
[variable, test_level, reference_level]où test_level est comparé à reference_level. -
Enregistrer les objets intermédiaires : Utiliser pickle pour enregistrer les objets DeseqDataSet pour une utilisation ultérieure ou d'analyses supplémentaires sans réexécuter l'étape d'ajustement coûteuse.
Installation et exigences
uv pip install pydeseq2
Exigences système :
- Python 3.10-3.11
- pandas 1.4.3+
- numpy 1.23.0+
- scipy 1.11.0+
- scikit-learn 1.1.1+
- anndata 0.8.0+
Optionnel pour la visualisation :
- matplotlib
- seaborn
Ressources supplémentaires
- Documentation officielle : https://pydeseq2.readthedocs.io
- Référentiel GitHub : https://github.com/owkin/PyDESeq2
- Publication : Muzellec et al. (2023) Bioinformatics, DOI: 10.1093/bioinformatics/btad547
- DESeq2 original (R) : Love et al. (2014) Genome Biology, DOI: 10.1186/s13059-014-0550-8