Activité des voies de signalisation par cellule en R avec decoupleR & PROGENy

Allez au-delà de l’appartenance à un ensemble de gènes : inférez quelles voies de signalisation sont actives dans chaque cellule à partir de leurs gènes cibles en aval, grâce au modèle d’empreinte de PROGENy et à decoupleR, validé par rapport à une réponse interféron connue

Un guide pratique de l’activité des voies de signalisation par cellule pour le RNA-seq single-cell en R. Utilisez le modèle d’empreinte PROGENy avec le modèle linéaire multivarié de decoupleR pour inférer l’activité de 14 voies de signalisation dans chaque cellule, contrastez-les à travers une stimulation à l’interféron-bêta, et validez le résultat par rapport à la vérité terrain intégrée — l’IFN-bêta signale via JAK-STAT, donc l’activité JAK-STAT doit exploser dans les cellules stimulées. Inclut en quoi les modèles d’empreinte diffèrent de la notation de signatures géniques.

Date de publication

4 juillet 2026

Modifié

7 juillet 2026

AstucePoints clés
  • Les modèles d’empreinte d’activité de voie posent une question différente de celle de la notation d’ensembles de gènes. La notation de signatures mesure avec quelle intensité une cellule exprime les gènes d’un ensemble. Un modèle d’empreinte infère si une voie de signalisation est active — à partir de l’expression des gènes cibles en aval de la voie, qui bougent même lorsque l’ARNm du récepteur ou de la kinase de la voie paraît plat. L’empreinte est la trace que la voie laisse derrière elle.
  • PROGENy fournit le modèle d’empreinte ; decoupleR l’applique par cellule. PROGENy (Pathway RespOnsive GENes) livre un recueil de 14 voies de signalisation, chacune avec un ensemble signé de gènes cibles réactifs appris à partir de centaines d’expériences de perturbation (Schubert et al., 2018). decoupleR exécute ce modèle sur le profil d’expression de chaque cellule pour renvoyer un score d’activité par cellule pour chaque voie (Badia-i-Mompel et al., 2022).
  • run_mlm est le moteur recommandé — un modèle linéaire multivarié. Il régresse l’expression de chaque cellule sur les poids cibles des 14 voies en une seule fois, de sorte que le score d’une voie est ajusté pour les cibles qu’elle chevauche avec les autres. decoupleR offre aussi run_ulm (univarié), run_wmean et un consensus ; run_mlm est le choix par défaut sensé pour PROGENy.
  • Validez par rapport à un contraste connu, au niveau des voies. Les données ont une vérité terrain intégrée : la moitié des cellules ont été stimulées à l’interféron-bêta (IFN-β), qui signale via la voie JAK-STAT. L’activité JAK-STAT moyenne est de 2.2 dans les contrôles et de 22.0 dans les cellules stimulées — un bond d’un facteur dix qui retrouve la biologie à partir des seuls gènes cibles. NF-κB, la voie inflammatoire, monte aussi.
  • Utilisez les modèles d’empreinte pour la signalisation ; utilisez la notation de signatures pour les programmes arbitraires. Ayez recours à PROGENy + decoupleR lorsque la question est quelle voie de signalisation est active. Ayez recours à la notation de signatures par cellule lorsque vous disposez d’un ensemble de gènes soigneusement choisi — un lignage, un état cellulaire, un module personnalisé — dont vous voulez quantifier l’appartenance.

Introduction

Vous avez exécuté le workflow standard de RNA-seq single-cell (scRNA-seq) — contrôle qualité, regroupement, annotation des types cellulaires — et vous avez commencé à quantifier des programmes fonctionnels par cellule. Peut-être avez-vous déjà noté quelques signatures géniques. La question suivante est souvent plus pointue : quelles voies de signalisation sont réellement actives dans ces cellules ? Non pas « cette cellule exprime-t-elle mon ensemble de gènes interféron » mais « la voie interféron est-elle active ? »

Cette distinction compte parce qu’une voie peut être fortement active alors que ses propres gènes paraissent banals. Un récepteur est activé par phosphorylation, pas par transcription ; une cascade de kinases s’exécute sans aucun changement de l’ARNm de la kinase. Ce qui change, en revanche, de façon fiable, c’est l’ensemble des gènes que la voie active en aval — son empreinte. Un modèle d’empreinte lit cette empreinte : il infère l’activité de la voie à partir de l’expression des gènes cibles transcriptionnels de la voie, les gènes qui répondent lorsque la voie signale.

Cette leçon construit l’activité des voies par cellule avec deux outils du laboratoire Saez-Rodriguez : PROGENy (Pathway RespOnsive GENes), qui fournit le modèle d’empreinte pour 14 voies de signalisation, et decoupleR, qui applique ce modèle à chaque cellule. Nous travaillons sur le classique benchmark immunitaire PBMC IFN-β : des cellules mononucléées du sang périphérique (PBMC — les cellules immunitaires du sang) séparées en un groupe contrôle et un groupe stimulé à l’interféron-bêta (IFN-β) (Kang et al., 2018). L’IFN-β signale via la voie JAK-STAT, donc ce plan expérimental nous donne une vérité terrain intégrée : l’activité JAK-STAT doit être bien plus élevée dans les cellules stimulées. Si un modèle d’empreinte ne peut pas retrouver un signal aussi fort, nous ne devrions pas lui faire confiance sur un signal subtil.

Modèles d’empreinte vs notation de signatures : deux questions différentes

Si vous avez lu la leçon sur la notation de signatures par cellule, il vaut la peine d’être précis sur la façon dont les modèles d’empreinte d’activité de voie diffèrent — parce que les deux sont faciles à confondre et répondent à des questions véritablement différentes.

Notation de signatures géniques Modèle d’empreinte d’activité de voie
Question Avec quelle intensité cette cellule exprime-t-elle cet ensemble de gènes ? Cette voie de signalisation est-elle active ?
Gènes en entrée Les membres de l’ensemble (les gènes interféron eux-mêmes) Les cibles en aval de la voie — les gènes qu’elle régule
Poids Généralement une appartenance non pondérée Poids signés (une cible est induite ou réprimée)
Capte L’expression du programme sélectionné L’activité même quand les propres gènes de la voie sont plats
Outils AUCell, UCell, GSVA PROGENy + decoupleR (cette leçon) ; aussi pour les facteurs de transcription
À utiliser quand Vous avez un ensemble choisi — un lignage, un état, un module Vous voulez une inférence de signalisation — quelle voie est active

L’idée clé : un score de signature interroge l’appartenance — à quel point une cellule est enrichie pour les gènes de l’ensemble. Un modèle d’empreinte interroge la conséquence — si l’ombre transcriptionnelle d’une voie active est visible dans la cellule. Les gènes cibles d’une empreinte ne sont généralement pas les propres composants de la voie. C’est ce qui permet à un modèle d’empreinte de rapporter que JAK-STAT signale à partir de l’induction des gènes stimulés par l’interféron, sans jamais mesurer directement l’activité des kinases JAK ou des facteurs de transcription STAT.

Les deux appartiennent à la boîte à outils de l’analyse fonctionnelle ; ni l’un ni l’autre ne remplace le second. La même mécanique d’empreinte s’étend à l’activité des facteurs de transcription (TF — une protéine qui active ou désactive des gènes), où les cibles sont les gènes régulés par un TF.

Les données : des PBMC stimulés à l’interféron avec une vérité terrain intégrée

Le fichier commité ifnb_subset.rds est une tranche équilibrée du benchmark IFN-β de Kang : une matrice de comptage brute de 13 565 gènes répartis sur 3 000 cellules, plus une table de métadonnées. La colonne stim enregistre si chaque cellule était une cellule CTRL (contrôle) ou STIM (stimulée à l’IFN-β) — 1 500 de chaque — et seurat_annotations contient les 13 types cellulaires déjà appelés pour nous. Nous gardons ces étiquettes en réserve et n’utilisons que le contraste stim pour valider l’activité de voie que nous inférons.

library(Seurat)

d <- readRDS("_data/ifnb_subset.rds")
obj <- CreateSeuratObject(counts = d$counts, meta.data = d$meta)
obj <- NormalizeData(obj, verbose = FALSE)

dim(obj)              # genes x cells
[1] 13565  3000
table(obj$stim)       # the control / IFN-beta contrast: our ground truth

CTRL STIM 
1500 1500 

La log-normalisation (NormalizeData) est l’unique étape de prétraitement que suppose le modèle d’empreinte : l’activité est inférée à partir de l’expression normalisée, pas des comptages bruts. Chaque bloc ci-dessous reconstruit à partir exactement de ce point, de sorte que vous pouvez copier n’importe lequel d’entre eux et l’exécuter de façon autonome.

PROGENy : le modèle d’empreinte

PROGENy a été construit en fouillant un vaste recueil d’expériences de perturbation — des centaines de cas où une voie a été délibérément activée ou inhibée — et en enregistrant quels gènes répondaient de façon cohérente (Schubert et al., 2018). Le résultat est, pour chacune des 14 voies de signalisation, un ensemble de gènes cibles réactifs ayant chacun un poids signé : un poids positif signifie que le gène monte quand la voie est active, un poids négatif qu’il baisse. Ces poids sont l’empreinte.

Le modèle est livré à l’intérieur du package progeny, on le lit donc directement — aucun téléchargement. getModel() renvoie une matrice de gènes × voies, dont nous conservons les cibles aux poids les plus élevés par voie.

library(progeny)

m <- progeny::getModel(organism = "Human", top = 500)   # top 500 responsive genes per pathway
dim(m)                                                   # genes x 14 pathways
[1] 5782   14
colnames(m)                                              # the 14 signaling pathways
 [1] "Androgen" "EGFR"     "Estrogen" "Hypoxia"  "JAK-STAT" "MAPK"    
 [7] "NFkB"     "p53"      "PI3K"     "TGFb"     "TNFa"     "Trail"   
[13] "VEGF"     "WNT"     

Le modèle couvre 5 782 gènes à travers 14 voies — Androgen, EGFR, Estrogen, Hypoxia, JAK-STAT, MAPK, NFkB, p53, PI3K, TGFb, TNFa, Trail, VEGF et WNT. Chaque colonne est l’empreinte signée d’une voie sur ces gènes.

decoupleR attend le modèle sous forme d’une table network longue — une ligne par arête (voie, gène cible, poids) — on remodèle donc la matrice et on écarte les entrées à poids nul (les gènes hors de l’ensemble de tête d’une voie donnée).

library(progeny)

m <- progeny::getModel(organism = "Human", top = 500)
net <- data.frame(
  source = rep(colnames(m), each = nrow(m)),   # the pathway
  target = rep(rownames(m), times = ncol(m)),  # the target gene
  weight = as.vector(as.matrix(m)))            # signed footprint weight
net <- net[net$weight != 0, ]                  # keep only real edges

nrow(net)          # 14 pathways x 500 targets = 7000 edges
[1] 7000
head(net)
     source target    weight
8  Androgen  ABCA1 -2.176598
9  Androgen ABCA12 -3.344896
15 Androgen  ABCC1  3.449725
16 Androgen  ABCC4  9.374285
23 Androgen  ABCG1 -2.792402
24 Androgen  ABCG2 -4.016547

Cela donne 7 000 arêtes — 500 cibles pour chacune des 14 voies — le réseau d’empreinte que decoupleR va noter.

NoteUtilisez le modèle intégré, pas la récupération réseau

decoupleR livre une fonction de commodité, get_progeny(), qui tire le même modèle par le réseau depuis le service web OmnipathR. Cet appel nécessite une connexion internet, peut bloquer derrière un pare-feu et — parce que la ressource distante peut changer — n’est pas reproductible. Lire le modèle directement depuis le progeny::getModel() empaqueté est hors ligne et déterministe : les nombres de cette page sont stables au bit près d’un rendu à l’autre. Préférez le modèle empaqueté sauf si vous avez spécifiquement besoin d’une version en ligne plus récente.

decoupleR : inférer l’activité de voie par cellule

decoupleR est un ensemble de méthodes qui infèrent des activités biologiques à partir de données omiques au sein d’un même cadre (Badia-i-Mompel et al., 2022). Étant donné une matrice d’expression et un réseau de sources (ici, des voies) et de leurs cibles pondérées, il renvoie un score d’activité pour chaque source dans chaque cellule.

La méthode recommandée pour PROGENy est run_mlm — un modèle linéaire multivarié (MLM). Pour chaque cellule, elle ajuste une régression linéaire de l’expression génique de la cellule sur les poids cibles des 14 voies en une seule fois ; le coefficient ajusté de chaque voie (sa valeur t) devient le score d’activité de cette voie. Ajuster toutes les voies conjointement importe : certains gènes cibles appartiennent à plus d’une voie, et l’ajustement multivarié corrige le score de chaque voie pour les autres avec lesquelles elle partage des cibles, plutôt que de créditer deux fois le même gène.

library(Seurat)
library(decoupleR)
library(progeny)

d <- readRDS("_data/ifnb_subset.rds")
obj <- CreateSeuratObject(counts = d$counts, meta.data = d$meta)
obj <- NormalizeData(obj, verbose = FALSE)
mat <- as.matrix(GetAssayData(obj, layer = "data"))   # genes x cells, normalized

m <- progeny::getModel(organism = "Human", top = 500)
net <- data.frame(source = rep(colnames(m), each = nrow(m)),
                  target = rep(rownames(m), times = ncol(m)),
                  weight = as.vector(as.matrix(m)))
net <- net[net$weight != 0, ]

set.seed(42)
acts <- run_mlm(mat, net, .source = "source", .target = "target",
                .mor = "weight", minsize = 5)
acts <- acts[acts$statistic == "mlm", ]   # keep the MLM score

head(acts)          # long: one row per pathway (source) x cell (condition)
# A tibble: 6 × 5
  statistic source   condition        score p_value
  <chr>     <chr>    <chr>            <dbl>   <dbl>
1 mlm       Androgen AAACATACCAGAAA.1 -1.29 0.198  
2 mlm       EGFR     AAACATACCAGAAA.1  3.27 0.00110
3 mlm       Estrogen AAACATACCAGAAA.1  2.06 0.0397 
4 mlm       Hypoxia  AAACATACCAGAAA.1  2.47 0.0134 
5 mlm       JAK-STAT AAACATACCAGAAA.1 -2.47 0.0133 
6 mlm       MAPK     AAACATACCAGAAA.1 -1.78 0.0752 

La sortie est une table longue : pour chaque cellule (la colonne condition contient le code-barres de la cellule) et chaque voie (la colonne source), un score — l’activité de la voie dans cette cellule. L’argument minsize = 5 écarte toute voie dont moins de cinq cibles sont présentes dans les données, de sorte qu’un score n’est jamais construit sur une poignée de gènes. À partir de là, toute l’analyse consiste à agréger et tracer ce seul score.

Validation : JAK-STAT explose dans les cellules stimulées

Le test de toute l’approche, c’est la vérité terrain. L’IFN-β signale via JAK-STAT, donc l’activité JAK-STAT doit séparer les conditions. Moyennez l’activité de chaque voie au sein des cellules contrôle et stimulées et tracez les 14 voies côte à côte.

library(Seurat)
library(decoupleR)
library(progeny)
library(ggplot2)

d <- readRDS("_data/ifnb_subset.rds")
obj <- CreateSeuratObject(counts = d$counts, meta.data = d$meta)
obj <- NormalizeData(obj, verbose = FALSE)
mat <- as.matrix(GetAssayData(obj, layer = "data"))
m <- progeny::getModel(organism = "Human", top = 500)
net <- data.frame(source = rep(colnames(m), each = nrow(m)),
                  target = rep(rownames(m), times = ncol(m)),
                  weight = as.vector(as.matrix(m)))
net <- net[net$weight != 0, ]

set.seed(42)
acts <- run_mlm(mat, net, .source = "source", .target = "target",
                .mor = "weight", minsize = 5)
acts <- acts[acts$statistic == "mlm", ]
acts$stim <- obj$stim[match(acts$condition, colnames(obj))]

# Mean activity per pathway per condition (base R aggregation)
agg <- aggregate(score ~ source + stim, data = acts, FUN = mean)
ord <- agg$source[agg$stim == "STIM"][order(agg$score[agg$stim == "STIM"])]
agg$source <- factor(agg$source, levels = ord)

ggplot(agg, aes(x = source, y = score, fill = stim)) +
  geom_col(position = position_dodge(width = 0.7), width = 0.65) +
  coord_flip() +
  scale_fill_manual(values = c(CTRL = "#3a86d4", STIM = "#d1495b")) +
  labs(x = NULL, y = "Mean pathway activity (MLM score)", fill = NULL,
       title = "PROGENy pathway activity: control vs IFN-β") +
  theme_minimal(base_size = 12) +
  theme(legend.position = "top")

A horizontal barplot of mean PROGENy pathway activity for 14 signaling pathways, control (blue) versus IFN-beta-stimulated (red) cells, pathways ordered by their stimulated activity. The JAK-STAT bar for the stimulated cells towers far above all others at about 22, roughly ten times its control level near 2; NF-kB rises modestly from slightly negative to positive; TNF-alpha and EGFR fall in the stimulated cells. The interferon pathway dominates the stimulated response, exactly as the IFN-beta ground truth predicts.

L’image est sans ambiguïté. L’activité JAK-STAT est en moyenne de 2.2 dans les contrôles et de 22.0 dans les cellules stimulées — un bond d’un facteur dix environ qui éclipse toutes les autres voies. C’est la vérité terrain interféron récupérée au niveau des voies, et — surtout — récupérée à partir des gènes cibles de JAK-STAT, et non en mesurant les propres composants de JAK-STAT. L’empreinte trahit le signal.

Les mouvements plus modestes racontent aussi une histoire cohérente. NF-κB, la voie inflammatoire maîtresse, monte de -0.8 à 1.2 — la stimulation à l’interféron est inflammatoire, donc une hausse de NF-κB est exactement ce qu’on attend. Pendant ce temps, TNF-α (2.7 → 1.2) et EGFR (1.5 → 1.2) baissent. L’événement dominant et incontestable est l’explosion de JAK-STAT, qui est la biologie que l’expérience a été conçue pour produire.

Voir la voie sur la carte

L’activité de voie est une quantité par cellule, elle tombe donc directement sur un UMAP (uniform manifold approximation and projection — la projection en 2-D des cellules). Colorer la carte selon l’activité JAK-STAT montre la réponse à l’interféron comme une région du tissu qui s’illumine, suivant les cellules stimulées où qu’elles siègent.

set.seed(42)
library(Seurat)
library(decoupleR)
library(progeny)
library(patchwork)
library(ggplot2)

d <- readRDS("_data/ifnb_subset.rds")
obj <- CreateSeuratObject(counts = d$counts, meta.data = d$meta)
obj <- NormalizeData(obj, verbose = FALSE)
mat <- as.matrix(GetAssayData(obj, layer = "data"))
m <- progeny::getModel(organism = "Human", top = 500)
net <- data.frame(source = rep(colnames(m), each = nrow(m)),
                  target = rep(rownames(m), times = ncol(m)),
                  weight = as.vector(as.matrix(m)))
net <- net[net$weight != 0, ]

acts <- run_mlm(mat, net, .source = "source", .target = "target",
                .mor = "weight", minsize = 5)
acts <- acts[acts$statistic == "mlm", ]
js <- acts[acts$source == "JAK-STAT", ]
obj$JAK_STAT <- js$score[match(colnames(obj), js$condition)]

# Standard embedding so the score has a map to land on
obj <- FindVariableFeatures(obj, nfeatures = 2000, verbose = FALSE) |>
  ScaleData(verbose = FALSE) |> RunPCA(npcs = 30, verbose = FALSE) |>
  RunUMAP(dims = 1:30, verbose = FALSE)

p1 <- DimPlot(obj, group.by = "stim") + ggtitle("Condition")
p2 <- FeaturePlot(obj, features = "JAK_STAT") +
  scale_color_viridis_c() + ggtitle("JAK-STAT activity")
p1 + p2

Two side-by-side UMAP embeddings of the 3,000 PBMCs. The left panel colours cells by condition, control versus IFN-beta-stimulated, which separate into two offset clouds. The right panel colours the same cells by their JAK-STAT pathway activity on a viridis scale: the stimulated cloud is bright yellow (high JAK-STAT) and the control cloud is dark purple (low), so the pathway-activity map mirrors the condition map almost exactly.

Les deux panneaux sont presque la même image : la région que l’UMAP remplit de cellules stimulées est exactement la région que la carte JAK-STAT peint en clair. Une activité de voie que vous avez inférée à partir de cibles en aval et qui reproduit la condition expérimentale que vous voyez dans la projection — c’est la forme visuelle de la validation.

Où chaque voie est active à travers les types cellulaires

Le diagramme en barres a réduit chaque voie à un seul nombre par condition. L’activité varie aussi entre les types cellulaires, et une heatmap des 14 voies sur les 13 types cellulaires annotés montre le paysage. Pour comparer les profils entre types cellulaires sur une échelle commune malgré l’énorme magnitude de JAK-STAT, on met chaque voie (ligne) à l’échelle en un score z à travers les types cellulaires — de sorte que chaque ligne montre , relativement, cette voie est la plus active.

library(Seurat)
library(decoupleR)
library(progeny)
library(ggplot2)

d <- readRDS("_data/ifnb_subset.rds")
obj <- CreateSeuratObject(counts = d$counts, meta.data = d$meta)
obj <- NormalizeData(obj, verbose = FALSE)
mat <- as.matrix(GetAssayData(obj, layer = "data"))
m <- progeny::getModel(organism = "Human", top = 500)
net <- data.frame(source = rep(colnames(m), each = nrow(m)),
                  target = rep(rownames(m), times = ncol(m)),
                  weight = as.vector(as.matrix(m)))
net <- net[net$weight != 0, ]

acts <- run_mlm(mat, net, .source = "source", .target = "target",
                .mor = "weight", minsize = 5)
acts <- acts[acts$statistic == "mlm", ]
acts$ct <- obj$seurat_annotations[match(acts$condition, colnames(obj))]

# Mean activity per pathway per cell type, then z-score each pathway (row)
mn  <- tapply(acts$score, list(acts$source, acts$ct), mean)
z   <- t(scale(t(mn)))    # row-wise z-score across cell types

df <- data.frame(pathway   = rownames(z)[row(z)],
                 cell_type = colnames(z)[col(z)],
                 z         = as.vector(z))
ggplot(df, aes(cell_type, pathway, fill = z)) +
  geom_tile(color = "white", linewidth = 0.3) +
  scale_fill_gradient2(low = "#3a86d4", mid = "grey95", high = "#d1495b",
                       midpoint = 0, name = "Row z") +
  labs(x = NULL, y = NULL, title = "PROGENy activity across cell types (row-scaled)") +
  theme_minimal(base_size = 11) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

A heatmap of 14 PROGENy signaling pathways (rows) across 13 annotated PBMC cell types (columns), each row z-scored across cell types on a blue-to-red diverging scale. The JAK-STAT and NF-kB rows are reddest (highest relative activity) over the myeloid cell types — CD14 and CD16 monocytes and dendritic cells — showing the interferon and inflammatory pathways are most active in the myeloid compartment; other pathways show their own cell-type patterns.

Le signal interféron n’est pas réparti uniformément. L’activité JAK-STAT et NF-κB culmine dans le compartiment myéloïde — les monocytes CD14 et CD16 et les cellules dendritiques — les répondeurs professionnels qui montent les programmes interféron et inflammatoires les plus forts. Un seul nombre au niveau de la condition aurait masqué cela ; les scores par cellule vous laissent voir quelles cellules pilotent la voie.

Méthodes, honnêteté et reproductibilité

Quelques points à garder clairs pour utiliser ces outils avec exactitude et reproductibilité.

run_mlm est l’une de plusieurs méthodes de decoupleR. decoupleR offre aussi run_ulm (un modèle linéaire univarié, ajustant chaque voie à part), run_wmean (une moyenne pondérée), run_wsum, et decouple() / run_consensus pour en combiner plusieurs. Pour PROGENy, run_mlm est le choix par défaut documenté parce que l’ajustement multivarié gère les cibles partagées entre voies ; run_ulm est une alternative proche et plus légère qui retrouve le même fort signal JAK-STAT mais n’ajuste pas les voies les unes pour les autres. En cas de doute, run_mlm est le choix sensé pour un modèle d’empreinte pondéré.

Le package R decoupleR est désormais l’interface héritée. Depuis 2025, le laboratoire Saez-Rodriguez a unifié le développement sur le decoupler 2.0 de Python, une réimplémentation plus rapide et plus économe en mémoire qui fait partie de l’écosystème single-cell scverse ; le package R est explicitement décrit comme la version dépréciée et est en maintenance. Le package R fonctionne toujours et est enseigné ici parce qu’il s’insère directement dans un workflow R fondé sur Seurat — mais si vous construisez de nouveaux pipelines, surtout en Python/scanpy, c’est la direction que prend le développement. Les concepts — modèles d’empreinte, PROGENy, inférence MLM/ULM — sont identiques dans les deux.

Utilisez le modèle empaqueté pour une sortie reproductible. Comme noté plus haut, progeny::getModel() est hors ligne et déterministe, tandis que le get_progeny() de decoupleR récupère depuis le service web OmnipathR (dépendant du réseau, non reproductible). Les résultats de cette page ont été produits avec le modèle empaqueté et sont stables au bit près d’un rendu à l’autre.

Quand utiliser l’activité de voie vs la notation de signatures

Les deux vivent dans la boîte à outils de l’analyse fonctionnelle ; choisissez selon la question.

  • Ayez recours à PROGENy + decoupleR quand la question est la signalisationquelle voie est active ? Les modèles d’empreinte sont conçus sur mesure pour l’inférence de signalisation : ils lisent l’activité d’une voie à partir de ses conséquences en aval, captant l’activité même quand les propres gènes de la voie sont inchangés. La même mécanique, avec un réseau différent, infère l’activité des facteurs de transcription (à partir des cibles régulées par un TF).
  • Ayez recours à la notation de signatures par cellule quand vous avez un ensemble de gènes soigneusement choisi — une signature de lignage, un module de cycle cellulaire, un programme d’épuisement, toute liste dont vous voulez quantifier l’appartenance par cellule. AUCell et UCell notent à quel point chaque cellule est enrichie pour l’ensemble lui-même.

En pratique, elles sont complémentaires : notez vos signatures choisies pour les programmes dont vous avez des listes de gènes, et exécutez un modèle d’empreinte pour les voies de signalisation dont vous voulez inférer l’activité à partir de leurs cibles.

Problèmes courants

get_progeny() bloque ou renvoie une erreur au sujet d’OmnipathR / d’une connexion réseau. decoupleR::get_progeny() télécharge le modèle depuis le service web OmnipathR, qui nécessite internet et peut se figer derrière un pare-feu — et sa ressource distante peut changer, donc les résultats ne sont pas reproductibles. Lisez plutôt le modèle directement depuis le package : progeny::getModel(organism = "Human", top = 500), puis construisez la data frame net comme montré. C’est hors ligne, déterministe et identique en structure.

run_mlm avertit que trop peu de cibles se recouvrent, ou une voie est écartée. L’argument minsize (par défaut et ici 5) écarte toute voie dont moins de ce nombre de cibles sont présentes dans votre matrice. Si des voies disparaissent, vérifiez que vos noms de features correspondent aux symboles de gènes du modèle (symboles vs identifiants Ensembl, capitalisation d’espèce) — une incohérence de nomenclature affame silencieusement l’empreinte. Ne baissez minsize que si vous comprenez qu’un score construit sur très peu de gènes est bruité.

Les scores d’activité ne sont pas comparables entre voies. Le score MLM est une statistique de régression par voie, pas une quantité normalisée sur une échelle commune — un score JAK-STAT de 22 et un score NF-κB de 1 ne sont pas directement comparables en magnitude entre voies. Comparez une voie à elle-même à travers les conditions ou les types cellulaires (comme le font le diagramme en barres et la heatmap), ou mettez à l’échelle en score z au sein de chaque voie avant de comparer les lignes, plutôt que de lire le nombre absolu d’une voie contre celui d’une autre.

Foire aux questions

La notation d’ensembles de gènes mesure avec quelle intensité une cellule exprime les gènes d’un ensemble — son appartenance. Un modèle d’empreinte d’activité de voie infère si une voie de signalisation est active, à partir de l’expression des gènes cibles en aval de la voie. La distinction compte parce qu’une voie peut être active alors que ses propres gènes de récepteur ou de kinase paraissent plats ; ses cibles la trahissent. Utilisez les modèles d’empreinte (PROGENy + decoupleR) pour l’inférence de signalisation et la notation de signatures (AUCell, UCell) pour les ensembles de gènes choisis.

Un modèle d’empreinte infère l’activité d’un régulateur — une voie de signalisation ou un facteur de transcription — à partir de l’expression des gènes qu’il régule, plutôt que de la propre expression du régulateur. Les gènes régulés sont l’« empreinte » que le régulateur actif laisse dans le transcriptome. PROGENy est un modèle d’empreinte pour 14 voies de signalisation, construit en apprenant quels gènes répondent de façon cohérente à travers des centaines d’expériences de perturbation (Schubert et al., 2018).

run_mlm ajuste un modèle linéaire multivarié, régressant l’expression de chaque cellule sur les poids cibles de toutes les voies en une seule fois, de sorte que le score d’une voie est ajusté pour les cibles qu’elle partage avec d’autres voies. run_ulm ajuste chaque voie univariément, une à la fois. Pour un modèle d’empreinte pondéré comme PROGENy, run_mlm est le choix par défaut documenté ; run_ulm est une alternative plus légère qui retrouve les mêmes signaux forts mais ne tient pas compte des cibles partagées. decoupleR offre aussi run_wmean, run_wsum et un consensus sur les méthodes.

Oui — et pour un nouveau travail, c’est la voie activement développée. Depuis 2025, le laboratoire Saez-Rodriguez a unifié le développement sur le decoupler 2.0 de Python, partie de l’écosystème scverse, qui travaille directement sur des objets AnnData/scanpy ; le decoupleR de R est désormais l’interface héritée. Les concepts — modèles d’empreinte, PROGENy, inférence MLM/ULM — sont identiques. Cette leçon utilise le package R parce qu’il s’insère dans un workflow R fondé sur Seurat.

decoupleR::get_progeny() récupère le modèle depuis le service web OmnipathR par le réseau, il nécessite donc une connexion internet, peut bloquer derrière un pare-feu et peut renvoyer des résultats différents si la ressource distante change — il n’est pas reproductible. progeny::getModel(organism = "Human", top = 500) lit le même modèle depuis le package installé : hors ligne, déterministe et stable au bit près d’un rendu à l’autre. Préférez le modèle empaqueté sauf si vous avez spécifiquement besoin d’une version en ligne plus récente.

Testez votre compréhension

En utilisant ifnb_subset.rds et le réseau PROGENy, inférez l’activité de voie avec run_ulm (le modèle linéaire univarié) au lieu de run_mlm, et comparez le contraste JAK-STAT contrôle-vs-stimulé au résultat de run_mlm dans la leçon (2.2 → 22.0). La méthode univariée retrouve-t-elle aussi la vérité terrain interféron ? Calculez l’activité JAK-STAT moyenne par condition à partir de run_ulm.

run_ulm a la même signature que run_mlm : run_ulm(mat, net, .source = "source", .target = "target", .mor = "weight", minsize = 5). Filtrez sa sortie sur statistic == "ulm", mappez la condition de chaque cellule (le code-barres) vers obj$stim, puis tapply(score, stim, mean) pour les lignes JAK-STAT.

library(Seurat); library(decoupleR); library(progeny)
d <- readRDS("_data/ifnb_subset.rds")
obj <- CreateSeuratObject(counts = d$counts, meta.data = d$meta)
obj <- NormalizeData(obj, verbose = FALSE)
mat <- as.matrix(GetAssayData(obj, layer = "data"))
m <- progeny::getModel(organism = "Human", top = 500)
net <- data.frame(source = rep(colnames(m), each = nrow(m)),
                  target = rep(rownames(m), times = ncol(m)),
                  weight = as.vector(as.matrix(m)))
net <- net[net$weight != 0, ]

set.seed(42)
u <- run_ulm(mat, net, .source = "source", .target = "target",
             .mor = "weight", minsize = 5)
u <- u[u$statistic == "ulm", ]
u$stim <- obj$stim[match(u$condition, colnames(obj))]

# JAK-STAT activity by condition, univariate model
js <- u[u$source == "JAK-STAT", ]
tapply(js$score, js$stim, mean)

run_ulm retrouve la même vérité terrain : l’activité JAK-STAT moyenne est d’environ 2.5 dans les contrôles et 22.9 dans les cellules stimulées — essentiellement le même bond d’un facteur dix que donnait run_mlm. Le signal fort est robuste à la méthode. Là où les deux diffèrent, c’est sur les petites voies : parce que run_ulm note chaque voie indépendamment, il ne dévalue pas les cibles partagées avec d’autres voies, de sorte que des voies comme NF-κB lisent plus haut qu’avec le run_mlm multivarié. Pour un signal propre et dominant comme l’interféron, le choix importe à peine ; pour démêler des voies qui se chevauchent, le run_mlm multivarié est le choix par défaut le plus défendable.

A. Le score doit être faux — une empreinte JAK-STAT devrait contenir les gènes interféron. B. Un modèle d’empreinte infère l’activité à partir des gènes cibles en aval de la voie, pas des propres composants de la voie ; ces cibles répondent à la signalisation JAK-STAT et montent dans les cellules stimulées, donc l’activité inférée est élevée même si les gènes de l’empreinte diffèrent de la signature canonique. C. Le score n’est élevé que parce que les données n’ont pas été normalisées.

B. C’est exactement ce qu’un modèle d’empreinte est conçu pour faire. PROGENy a appris, à partir d’expériences de perturbation, quels gènes répondent de façon cohérente quand JAK-STAT signale — son empreinte. Ces cibles réactives ne sont pas les mêmes qu’une signature de gènes interféron choisie à la main ; elles sont la conséquence transcriptionnelle de l’activité de la voie. Quand l’IFN-β active JAK-STAT, ces gènes cibles bougent, et le modèle lit la voie comme active — sans jamais avoir besoin des gènes de signature canoniques dans l’empreinte. (La réponse A comprend mal les empreintes ; C est fausse — le pipeline normalise avec NormalizeData et le contraste est réel.)

Conclusion

La notation de signatures demande avec quelle intensité une cellule exprime un ensemble de gènes ; les modèles d’empreinte d’activité de voie demandent si une voie de signalisation est active, en l’inférant à partir des gènes cibles en aval de la voie. PROGENy fournit le modèle d’empreinte pour 14 voies de signalisation, et le run_mlm de decoupleR le note dans chaque cellule. Sur le benchmark IFN-β, la méthode a retrouvé la vérité terrain proprement : l’activité JAK-STAT était ~10× plus élevée dans les cellules stimulées — à partir des seuls gènes cibles — avec NF-κB montant aussi, et les cellules myéloïdes pilotant les deux. Lisez la voie à elle-même à travers les conditions et les types cellulaires, validez par rapport à un contraste connu, et préférez le modèle empaqueté hors ligne pour une sortie reproductible. Les modèles d’empreinte et la notation de signatures sont des points d’entrée complémentaires à l’analyse fonctionnelle single-cell — l’un pour l’inférence de signalisation, l’autre pour les programmes choisis.

Leçons associées

🟢 Avec un agent IA

Demandez à Prova « comment inférer l’activité des voies de signalisation par cellule sur mon propre objet Seurat avec PROGENy et decoupleR, et la valider par rapport à un contraste connu ? » — elle répond avec du code R que vous pouvez exécuter sur vos propres données : lire le modèle PROGENy, construire le réseau, appeler run_mlm(), ajouter les scores à votre objet, et les vérifier par rapport à une condition que vous connaissez déjà. The runtime is the judge. Demander à Prova →

Cette page vous a-t-elle été utile ?

Recevez les nouvelles leçons R & Python par e-mail

Pratique, reproductible, sans spam. Désinscription à tout moment.

Double opt-in. Nous ne partageons jamais votre e-mail.

Partager cette pageXLinkedInRedditHN
Note

Cette leçon est reproductible : chaque figure et chaque nombre ont été produits par le code montré, rendu hors ligne dans l’image Docker datanovia/quarto-bioinformatics — copiez n’importe quel bloc et exécutez-le pour les reproduire. The runtime is the judge.

Références

  • Schubert, M., Klinger, B., Klünemann, M., Sieber, A., Uhlitz, F., Sauer, S., Garnett, M. J., Blüthgen, N., & Saez-Rodriguez, J. (2018). Perturbation-response genes reveal signaling footprints in cancer gene expression — introduit PROGENy. Nature Communications, 9, 20. https://doi.org/10.1038/s41467-017-02391-6
  • Badia-i-Mompel, P., Vélez Santiago, J., Braunger, J., Geiss, C., Dimitrov, D., Müller-Dott, S., Taus, P., Dugourd, A., Holland, C. H., Ramirez Flores, R. O., & Saez-Rodriguez, J. (2022). decoupleR: ensemble of computational methods to infer biological activities from omics data. Bioinformatics Advances, 2(1), vbac016. https://doi.org/10.1093/bioadv/vbac016
  • Kang, H. M., et al. (2018). Multiplexed droplet single-cell RNA-sequencing using natural genetic variation — la source du jeu de données PBMC stimulé à l’IFN-β. Nature Biotechnology, 36, 89–94. https://doi.org/10.1038/nbt.4042
  • decoupler (Python, activement développé) — scverse. https://github.com/scverse/decoupler · decoupleR (R, hérité) — laboratoire Saez-Rodriguez. https://github.com/saezlab/decoupleR

Réutilisation

Citation

BibTeX
@online{2026,
  author = {},
  title = {Activité des voies de signalisation par cellule en R avec
    decoupleR \& PROGENy},
  date = {2026-07-04},
  url = {https://www.datanovia.com/learn/bioinformatics/single-cell/scrnaseq-pathway-activity-decoupler.html},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“Activité des voies de signalisation par cellule en R avec decoupleR & PROGENy.” 2026. July 4. https://www.datanovia.com/learn/bioinformatics/single-cell/scrnaseq-pathway-activity-decoupler.html.