Annotation des types cellulaires en R : SingleR & celldex

Étiquetez chaque cellule en transférant les types cellulaires depuis une référence annotée avec SingleR et celldex — sans marqueurs curés à la main — puis notez la confiance de chaque appel et validez-la face aux étiquettes connues

Un guide pratique pour étiqueter par type cellulaire les regroupements de RNA-seq single-cell en R sans curer les gènes marqueurs de chaque regroupement. Exécutez l’annotation automatique fondée sur la corrélation avec SingleR face à une référence immunitaire celldex, lisez les étiquettes et les scores de confiance par cellule, élaguez les appels incertains, et validez le résultat face à des étiquettes de types cellulaires connues — puis découvrez l’alternative Seurat fondée sur les ancres (FindTransferAnchors / MapQuery) et où s’inscrit la cartographie de référence à l’échelle d’un atlas (Symphony, Azimuth).

Date de publication

3 juillet 2026

Modifié

7 juillet 2026

AstucePoints clés
  • Nommer les regroupements à la main est lent et subjectif. Après le clustering, vous disposez de groupes numérotés ; décider de l’identité de chacun à partir des gènes marqueurs demande de l’expertise et du jugement. L’annotation automatique évite la curation : elle transfère les étiquettes de types cellulaires depuis une référence déjà annotée sur vos cellules.
  • SingleR étiquette chaque cellule par corrélation. Il compare l’expression de chaque cellule à une référence de types cellulaires purs et étiquetés et attribue l’étiquette la mieux correspondante — (Aran et al., 2019). Aucun clustering requis, aucun marqueur à curer : SingleR(test = ..., ref = ..., labels = ...) et vous avez une étiquette par cellule.
  • Une référence n’est qu’à une ligne de distance. Le package celldex fournit des références curées ; ici, celldex::MonacoImmuneData() donne une référence de cellules immunitaires triées (Monaco et al., 2019) — idéale puisque nos cellules sont des PBMC.
  • Une annotation est une hypothèse assortie d’une confiance, pas une vérité révélée. SingleR renvoie un score par étiquette et élague les appels de faible confiance en les mettant à NA. Lisez la heatmap des scores, gardez les indicateurs d’élagage, et validez les étiquettes face aux marqueurs ou à une vérité connue avant de leur faire confiance.
  • La référence doit correspondre à la biologie. Une référence immunitaire pour des cellules immunitaires fonctionne ; une mauvaise référence produit des absurdités confiantes. Cela, plus la granularité des étiquettes (label.main vs label.fine), est là où l’annotation automatique déraille — et où votre jugement compte encore.

Introduction

Vous avez exécuté le workflow single-cell — contrôle qualité, normalisation, clustering — et vous contemplez un UMAP (uniform manifold approximation and projection, la carte en 2-D de vos cellules) coloré par numéro de regroupement. Regroupement 0, regroupement 1, regroupement 2. La tâche suivante consiste à dire ce qu’est chaque regroupement : monocytes, lymphocytes T, lymphocytes B. La méthode classique consiste à trouver les gènes marqueurs de chaque regroupement et à en déduire l’identité — précise, mais lente, et elle repose sur le fait de savoir que CD14 signifie monocyte et MS4A1 lymphocyte B. Sur un jeu de données comportant une douzaine de regroupements, curer à la main des marqueurs pour chacun est une corvée, et deux analystes peuvent être en désaccord.

Il existe une voie plus rapide et plus reproductible : transférer les étiquettes depuis une référence déjà annotée. Quelqu’un a déjà constitué un catalogue de types cellulaires immunitaires purs et étiquetés ; au lieu de redériver les identités à partir de zéro, vous demandez « à quel type cellulaire de référence chacune de mes cellules ressemble-t-elle le plus ? » C’est l’annotation automatique des types cellulaires, et l’outil R standard pour cela est SingleR.

Cette leçon parcourt toute la boucle. Vous annoterez chaque cellule avec SingleR face à une référence celldex, tracerez l’UMAP annoté, lirez les scores de confiance (la partie que les gens sautent), validerez les appels face aux étiquettes de types cellulaires connues, puis découvrirez l’alternative Seurat fondée sur les ancres (FindTransferAnchors / MapQuery) et où la cartographie de référence à l’échelle d’un atlas (Symphony, Azimuth) trouve sa place. Nous travaillons sur un sous-ensemble du jeu de données PBMC ifnb canonique (cellules mononucléées du sang périphérique — les globules blancs d’une prise de sang), qui est livré avec des étiquettes de types cellulaires publiées que nous mettons de côté comme vérité de terrain pour vérifier l’annotation.

Les données : des PBMC avec des étiquettes connues pour la vérification

Le ifnb_subset.rds commité est une tranche du benchmark ifnb canonique : 3 000 PBMC, stockées comme une matrice de comptage brute plus une table de métadonnées. La colonne seurat_annotations contient les étiquettes de types cellulaires publiées pour 13 types cellulaires connus — nous les utilisons uniquement pour noter l’annotation à la fin, jamais pour la piloter. SingleR veut une expression log-normalisée comme requête, nous normalisons donc l’objet et nous arrêtons là ; aucun clustering ni recherche de marqueurs n’est nécessaire pour annoter.

library(Seurat)

# A subset of the canonical ifnb PBMC benchmark: raw counts + metadata (stim, seurat_annotations)
d <- readRDS("_data/ifnb_subset.rds")
obj <- CreateSeuratObject(counts = d$counts, meta.data = d$meta)
obj <- NormalizeData(obj)        # SingleR wants a log-normalized query

table(obj$seurat_annotations)     # the 13 published cell types — our ground truth to check against

   CD14 Mono  CD4 Naive T CD4 Memory T    CD16 Mono            B        CD8 T 
         925          534          370          255          194          182 
 T activated           NK           DC  B Activated           Mk          pDC 
         125          144          106           77           52           23 
       Eryth 
          13 

Treize types cellulaires, des abondants monocytes CD14+ jusqu’à une poignée d’érythrocytes. Chaque bloc ci-dessous repart exactement de ce point, de sorte que vous pouvez copier n’importe lequel d’entre eux et l’exécuter seul.

Annoter chaque cellule avec SingleR

L’annotation automatique a besoin de deux entrées : votre requête (les cellules log-normalisées) et une référence (un catalogue d’expression de types cellulaires étiquetés). Le package celldex livre la référence en un seul appel. Puisque nos cellules sont des cellules immunitaires, nous utilisons MonacoImmuneData() — une référence de RNA-seq bulk de populations immunitaires humaines triées par cytométrie de flux (Monaco et al., 2019), chaque échantillon étant un type cellulaire connu. Faire correspondre la référence à la biologie est le choix le plus important que vous faites ici ; nous y reviendrons dans les mises en garde.

SingleR() fait alors le travail : pour chacune de vos cellules, il calcule la corrélation à chaque étiquette de référence, sur les gènes les plus informatifs, et attribue l’étiquette la mieux correspondante. Il opère par cellule et ne nécessite aucun clustering.

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

ref  <- readRDS("_data/monaco_immune_ref.rds")   # celldex::MonacoImmuneData(), saved for a reproducible offline render
logq <- GetAssayData(obj, layer = "data")    # the log-normalized query matrix

# One call: correlate every cell against the reference and assign the best-matching label
pred <- SingleR(test = logq, ref = ref, labels = ref$label.main)

sort(table(pred$labels), decreasing = TRUE)  # how many cells got each label

      Monocytes    CD4+ T cells    CD8+ T cells         B cells        NK cells 
           1245             851             322             271             136 
        T cells Dendritic cells     Progenitors 
             99              71               5 

C’est là toute l’annotation. pred est une table avec une ligne par cellule ; pred$labels est le type cellulaire attribué. Les effectifs semblent déjà justes pour du sang : les Monocytes dominent (1 245 cellules), suivis d’une large population de CD4+ T cells (851), puis des CD8+ T cells (322), des B cells (271), des NK cells (136), un petit groupe générique de T cells (99), des Dendritic cells (71) et une poignée de Progenitors (5). Nous avons étiqueté 3 000 cellules par leur seule expression — aucun marqueur curé, aucun regroupement interprété.

Voir le résultat : l’UMAP annoté

La figure qui récompense les efforts est l’UMAP coloré par l’étiquette SingleR. Calculez l’embedding de la manière habituelle (gènes variables → mise à l’échelle → analyse en composantes principales (PCA) → UMAP), attachez les étiquettes, et tracez. Si l’annotation est bonne, chaque étiquette atterrit sur un îlot cohérent et bien séparé.

library(Seurat)
library(SingleR)
library(ggplot2)
d <- readRDS("_data/ifnb_subset.rds")
obj <- CreateSeuratObject(counts = d$counts, meta.data = d$meta)
obj <- NormalizeData(obj)
ref  <- readRDS("_data/monaco_immune_ref.rds")   # celldex::MonacoImmuneData(), saved for a reproducible offline render
pred <- SingleR(test = GetAssayData(obj, layer = "data"), ref = ref, labels = ref$label.main)

# Standard embedding, then colour it by the SingleR label
obj <- FindVariableFeatures(obj, verbose = FALSE)
obj <- ScaleData(obj, verbose = FALSE)
obj <- RunPCA(obj, npcs = 30, verbose = FALSE)
obj <- RunUMAP(obj, dims = 1:30, verbose = FALSE)
obj$singler <- pred$labels

DimPlot(obj, group.by = "singler", label = TRUE, repel = TRUE) + ggtitle("SingleR annotation")

A UMAP scatter plot of 3,000 single cells coloured and labelled by the cell type SingleR assigned. A large Monocytes territory sits on one side; a broad CD4+ T-cell region with CD8+ T cells and a small generic T-cell group beside it occupies another; an NK-cell group sits next to the CD8+ T cells; a separate B-cell island and small Dendritic-cell and Progenitor groups complete the map. The labels sit on top of coherent, well-separated islands — correlation-based reference annotation reproduced the expected immune cell types without hand-curating any markers.

La carte se lit exactement comme du sang le devrait : un territoire de monocytes, une grande région de lymphocytes T (CD4+ et CD8+ l’un à côté de l’autre, comme il se doit), un groupe NK à côté des lymphocytes T CD8+, un îlot de lymphocytes B net, et de petites poches de cellules dendritiques et de progéniteurs. Chaque étiquette repose sur un regroupement cohérent — l’annotation et la structure non supervisée concordent, ce qui est le premier signe que cela a fonctionné. Mais « ça a l’air correct » est là où la plupart des tutoriels s’arrêtent, et c’est une erreur. Les étiquettes automatiques s’accompagnent d’une confiance, et vous devez la lire.

Lire la sortie : les scores, et les appels que SingleR refuse de faire

SingleR ne se contente pas de vous tendre une étiquette ; il la note. Pour chaque cellule, il conserve la corrélation à chaque étiquette de référence, et il élague les appels dont il n’est pas sûr — les cellules dont la meilleure étiquette n’est qu’à peine meilleure que la suivante voient leur pruned.labels mis à NA. Ce sont les cellules à examiner à la main.

library(Seurat)
library(SingleR)
d <- readRDS("_data/ifnb_subset.rds")
obj <- CreateSeuratObject(counts = d$counts, meta.data = d$meta)
obj <- NormalizeData(obj)
ref  <- readRDS("_data/monaco_immune_ref.rds")   # celldex::MonacoImmuneData(), saved for a reproducible offline render
pred <- SingleR(test = GetAssayData(obj, layer = "data"), ref = ref, labels = ref$label.main)

# Low-confidence calls SingleR flagged as NA
sum(is.na(pred$pruned.labels))               # how many cells were pruned
[1] 25

Seulement 25 cellules sur 3 000 (moins de 1 %) étaient trop ambiguës pour être appelées avec confiance — un signe sain que la référence convient. Dans une vraie analyse, vous inspecteriez ces 25 cellules, sans les supprimer : ce sont souvent des doublets, des états transitoires, ou un type cellulaire que la référence ne contient pas.

La heatmap des scores est le diagnostic à toujours tracer. Chaque colonne est une cellule, chaque ligne une étiquette de référence, et la couleur est le score d’attribution. Un jeu de données confiant montre une bande brillante par bloc de type cellulaire — chaque groupe de cellules s’illumine pour exactement une étiquette.

library(Seurat)
library(SingleR)
d <- readRDS("_data/ifnb_subset.rds")
obj <- CreateSeuratObject(counts = d$counts, meta.data = d$meta)
obj <- NormalizeData(obj)
ref  <- readRDS("_data/monaco_immune_ref.rds")   # celldex::MonacoImmuneData(), saved for a reproducible offline render
pred <- SingleR(test = GetAssayData(obj, layer = "data"), ref = ref, labels = ref$label.main)

plotScoreHeatmap(pred)                        # one bright band per cell = a confident call

A SingleR score heatmap: reference cell-type labels down the rows, the 3,000 query cells across the columns grouped by their assigned label, and colour showing each cell's correlation score to each label. Within each column block one row lights up brightly — the assigned label — while the other rows stay dark, so every group of cells matches one reference type cleanly. The Monocytes, CD4+ T, CD8+ T, B-cell and NK blocks each show a single sharp bright band, the visual signature of confident annotation.

Lisez-la bloc de colonnes par bloc de colonnes : au sein de chaque groupe attribué, une ligne est brillante et les autres sont sombres. Ce contraste marqué est la confiance — la cellule corrèle fortement avec une étiquette et faiblement avec les autres. Une cellule qui illuminerait deux lignes de manière égale serait du genre ambigu que SingleR élague. La fonction compagne plotDeltaDistribution(pred) montre la même idée sous la forme de l’écart entre le meilleur score de chaque cellule et la médiane — un petit écart est un appel fragile. La leçon : une étiquette automatique est une hypothèse porteuse d’une confiance, et le score est la façon de séparer les appels dignes de confiance de ceux à vérifier.

Valider les appels face aux types cellulaires connus

Le véritable test d’une annotation est de savoir si elle correspond à ce que les cellules sont réellement. Notre jeu de données est livré avec des étiquettes publiées (seurat_annotations), nous pouvons donc noter SingleR directement : croiser l’étiquette SingleR avec l’étiquette connue et lire si elles concordent biologiquement.

library(Seurat)
library(SingleR)
d <- readRDS("_data/ifnb_subset.rds")
obj <- CreateSeuratObject(counts = d$counts, meta.data = d$meta)
obj <- NormalizeData(obj)
ref  <- readRDS("_data/monaco_immune_ref.rds")   # celldex::MonacoImmuneData(), saved for a reproducible offline render
pred <- SingleR(test = GetAssayData(obj, layer = "data"), ref = ref, labels = ref$label.main)

# SingleR's automated label vs the dataset's published cell type
table(SingleR = pred$labels, known = obj$seurat_annotations)[,
      c("CD14 Mono", "CD16 Mono", "B", "B Activated", "NK", "CD4 Naive T", "CD4 Memory T", "CD8 T")]
                 known
SingleR           CD14 Mono CD16 Mono   B B Activated  NK CD4 Naive T
  B cells                 1         0 186          75   0           0
  CD4+ T cells            1         0   3           1   0         367
  CD8+ T cells            0         0   3           0   1         164
  Dendritic cells         8         0   1           0   0           0
  Monocytes             915       255   0           1   0           0
  NK cells                0         0   0           0 132           0
  Progenitors             0         0   0           0   0           1
  T cells                 0         0   1           0  11           2
                 known
SingleR           CD4 Memory T CD8 T
  B cells                    0     0
  CD4+ T cells             331    14
  CD8+ T cells              21   104
  Dendritic cells            0     0
  Monocytes                  0     0
  NK cells                   0     1
  Progenitors                0     0
  T cells                   18    63

La concordance est forte et, là où elle est imparfaite, interprétable — ce qui est exactement ce que vous voulez voir :

  • Les monocytes sont pratiquement parfaits. Les deux populations connues de monocytes correspondent à Monocytes : sur 925 cellules CD14 Mono, 915 sont appelées Monocytes, et les 255 cellules CD16 Mono le sont toutes — 99 % de concordance. La référence a une seule étiquette Monocytes, elle replie donc correctement les deux sous-types dedans.
  • Les lymphocytes B concordent proprement. 186 des 194 cellules B et 75 des 77 cellules B Activated sont appelées B cells (96 %). Les cellules NK racontent la même histoire — 132 sur 144 atterrissent sur NK cells.
  • Les sous-types de lymphocytes T sont là où se situe la friction honnête. La plupart des cellules CD4 Memory T (331/370) sont appelées CD4+ T cells, mais les CD4 Naive T se répartissent entre CD4+ T cells (367) et CD8+ T cells (164), et les CD8 T s’étalent sur CD8+ T cells, le générique T cells, et CD4+ T cells. Les lymphocytes T CD4 et CD8 sont transcriptionnellement proches, et l’étiquette générique T cells de la référence absorbe les ambigus.

À la granularité de la référence (label.main, les catégories larges), l’appel automatique concorde avec la vérité de terrain pour environ 86 % des cellules dans l’ensemble, et >96 % sur les lignées les mieux séparées (monocytes ~99 %, B ~96 %), avec les NK autour de 92 %. Les désaccords ne sont pas des erreurs aléatoires — c’est la référence qui effondre les états fins de lymphocytes T qu’elle ne distingue pas. Voilà le motif à intégrer : l’annotation automatique cloue les identités grossières et brouille les fines, vous lui faites donc confiance pour « monocyte vs lymphocyte T vs lymphocyte B » et confirmez les sous-types avec des marqueurs.

L’alternative Seurat : le transfert d’étiquettes fondé sur les ancres

SingleR est fondé sur la corrélation et utilise une référence de profils de types cellulaires purs. L’autre grande approche, intégrée à Seurat, est le transfert d’étiquettes fondé sur les ancres : il trouve des « ancres » de plus proches voisins mutuels entre votre requête et un objet Seurat de référence annoté (un vrai jeu de données single-cell que quelqu’un a déjà étiqueté), et transfère les étiquettes à travers ces ancres (Hao et al., 2021).

Le schéma est FindTransferAnchors() puis MapQuery() (ou TransferData()), et il nécessite un objet Seurat de référence étiqueté — le code ci-dessous est donc illustratif ; remplacez-y votre propre référence pour l’exécuter :

# ref_obj = an annotated reference Seurat object (processed: NormalizeData -> ... -> RunUMAP with return.model = TRUE)
# query   = your cells (NormalizeData'd)

anchors <- FindTransferAnchors(reference = ref_obj, query = query,
                               dims = 1:30, reference.reduction = "pca")

# MapQuery: transfer the labels AND project the query onto the reference UMAP in one call
query <- MapQuery(anchorset = anchors, reference = ref_obj, query = query,
                  refdata = list(celltype = "celltype"),   # the label column in ref_obj
                  reference.reduction = "pca", reduction.model = "umap")

# query$predicted.celltype now holds the transferred label; predicted.celltype.score its confidence
table(query$predicted.celltype)

Le compromis est pratique. SingleR + celldex ne nécessite aucun objet de référence à vous — celldex livre des références curées — c’est donc le chemin le plus rapide vers une première annotation. Le transfert par ancres est le choix lorsque vous disposez d’une référence single-cell bien annotée pour votre tissu exact (votre propre atlas, ou un atlas publié), car il transfère la granularité de ce jeu de données et peut co-projeter vos cellules sur l’UMAP de la référence. Comme SingleR, il renvoie un score de prédiction par cellule — même discipline : lisez la confiance, ne faites pas confiance à une étiquette nue.

La cartographie de référence à l’échelle d’un atlas : Symphony et Azimuth

Deux outils portent le transfert d’étiquettes à l’échelle d’un atlas publié — en projetant vos cellules sur une référence figée et compressée de centaines de milliers de cellules annotées :

  • Azimuth est l’application web et le workflow R de Seurat, bâtis sur le transfert par ancres ci-dessus, livrés avec des références curées (PBMC humaines, moelle osseuse, poumon, et plus). Vous lui donnez votre objet ; il renvoie des étiquettes de types cellulaires à plusieurs granularités plus un score de qualité de cartographie. C’est la façon à faible friction d’annoter face à une grande référence étiquetée par des experts sans en construire une.
  • Symphony compresse un atlas de référence une fois, puis projette de nouvelles cellules de requête sur cette référence figée en quelques secondes — le moteur derrière des ressources de cartographie d’atlas comme le BoneMarrowMap de l’hématopoïèse. C’est ce vers quoi vous vous tournez lorsque la référence est un grand atlas publié et que vous voulez placer chaque nouvel échantillon dans le même système de coordonnées.

L’idée est partagée : une référence stable et annotée, et vos cellules projetées dessus. SingleR est le démarrage le plus rapide ; Azimuth et Symphony sont les versions à l’échelle d’un atlas lorsqu’une grande référence curée existe pour votre tissu.

Mises en garde honnêtes : l’annotation automatique est une hypothèse de départ

L’annotation de référence est rapide et reproductible, mais elle ne vaut que ce que valent la référence et votre lecture des scores. Quatre choses à garder au clair :

  • La référence doit correspondre au tissu et à la biologie. Une référence immunitaire pour des cellules immunitaires fonctionne ; exécutez-la sur des cellules de cerveau ou de tumeur et vous obtenez des étiquettes confiantes et fausses — SingleR renvoie toujours une meilleure correspondance, même quand aucune ne convient vraiment. Choisir une référence qui couvre vos types cellulaires est la décision qui fait ou défait le résultat. Dans le doute, vérifiez la cohérence avec deux ou trois marqueurs canoniques.
  • Surveillez les appels élagués / de faible confiance. Les NA dans pruned.labels (25 ici) et les lignes plates de la heatmap des scores signalent les cellules que la référence n’a pas pu placer — doublets, états transitoires, ou un type cellulaire manquant. Inspectez-les ; ne les supprimez pas en silence et ne les gardez pas aveuglément.
  • Granularité : label.main vs label.fine. Nous avons utilisé ref$label.main (catégories larges). Les références celldex portent aussi ref$label.fine (bien plus d’états spécifiques) — passez-le à labels = pour des appels plus fins, au prix de plus d’ambiguïté et de plus d’élagage. Faites correspondre la granularité à ce que votre référence peut réellement résoudre ; demander du CD4-naïf-vs-mémoire à une référence qui les brouille ne fait que déplacer les erreurs.
  • C’est une hypothèse, pas un verdict. Le workflow correct est annoter → vérifier le score → confirmer avec des marqueurs. Utilisez l’appel automatique pour nommer les regroupements rapidement, puis vérifiez les identités qui comptent avec les gènes marqueurs comme vous confirmeriez n’importe quel résultat. L’annotation vous mène à une carte étiquetée en quelques minutes ; votre jugement la rend digne de confiance.

Quelle méthode quand

Vous avez… Utilisez Pourquoi
Un tissu immunitaire / commun, sans référence à vous SingleR + celldex Des références curées sont livrées avec le package ; un appel, des étiquettes par cellule + des scores
Un objet Seurat de référence bien annoté pour votre tissu Transfert par ancres Seurat (FindTransferAnchors / MapQuery) Transfère la granularité de ce jeu de données ; co-projette vos cellules sur l’UMAP de la référence
Un grand atlas publié sur lequel projeter Azimuth ou Symphony Référence figée et compressée ; placement rapide et cohérent de chaque nouvel échantillon
Un regroupement dont l’identité fine compte Marqueurs, pour confirmer Les étiquettes automatiques brouillent les sous-types proches ; les marqueurs tranchent CD4-vs-CD8, les appels de sous-types

Le fil conducteur : l’annotation automatique vous donne les identités grossières rapidement et de façon reproductible ; les marqueurs et une référence appariée tranchent les fines.

Problèmes fréquents

Chaque cellule reçoit une étiquette confiante mais elles sont biologiquement fausses. La référence ne correspond pas à vos cellules. SingleR renvoie une meilleure correspondance pour chaque cellule même lorsque le vrai type est absent de la référence, de sorte qu’une référence immunitaire sur des données de tumeur ou de cerveau produit des absurdités fluides. Choisissez une référence qui couvre les types cellulaires de votre tissu (celldex en a plusieurs — HumanPrimaryCellAtlasData(), MonacoImmuneData(), DatabaseImmuneCellExpressionData(), BlueprintEncodeData()), et confirmez quelques étiquettes avec des marqueurs canoniques.

Beaucoup de cellules reviennent en NA dans pruned.labels. Ce sont des appels de faible confiance — le meilleur score de la cellule n’était pas clairement meilleur que le suivant. Quelques pour cent, c’est normal ; une grande fraction signifie que la référence convient mal (mauvais tissu, ou label.fine demandant une résolution que la référence n’a pas). Tracez plotScoreHeatmap() / plotDeltaDistribution() pour voir si les appels sont véritablement ambigus, et envisagez une référence mieux appariée ou le label.main plus grossier.

SingleR est lent sur un grand jeu de données. L’annotation par cellule de centaines de milliers de cellules est coûteuse. Deux correctifs : annoter au niveau du regroupement plutôt que par cellule (passez vos identifiants de regroupement à SingleR(..., clusters = obj$seurat_clusters), pour qu’il étiquette chaque regroupement une seule fois), ou agréger / sous-échantillonner avant d’annoter. L’annotation au niveau du regroupement est aussi plus robuste — elle met en commun de nombreuses cellules par appel.

Questions fréquentes

Transférez les étiquettes depuis une référence annotée au lieu de lire les marqueurs à la main. En R, SingleR corrèle chacune de vos cellules log-normalisées à une référence étiquetée (du package celldex) et attribue le type cellulaire le mieux correspondant : SingleR(test = GetAssayData(obj, layer = "data"), ref = celldex::MonacoImmuneData(), labels = ref$label.main). Vous obtenez une étiquette par cellule plus un score de confiance — aucune curation de marqueurs requise.

SingleR est fondé sur la corrélation et utilise une référence de profils d’expression de types cellulaires purs (celldex les livre), il ne nécessite donc aucune référence à vous. Azimuth utilise le transfert d’étiquettes fondé sur les ancres de Seurat pour projeter vos cellules sur un grand atlas single-cell curé et renvoie des étiquettes à plusieurs granularités plus un score de cartographie. SingleR est la première annotation la plus rapide ; Azimuth (et Symphony) brillent lorsqu’une grande référence annotée par des experts existe pour votre tissu.

Pour les PBMC et autres cellules immunitaires, MonacoImmuneData() (populations immunitaires humaines triées par cytométrie de flux) est une valeur par défaut solide ; DatabaseImmuneCellExpressionData() est une autre référence immunitaire, et HumanPrimaryCellAtlasData() / BlueprintEncodeData() couvrent des tissus plus larges. La règle est que la référence doit contenir les types cellulaires que vous attendez — une référence immunitaire pour des cellules immunitaires. La mauvaise référence produit des étiquettes confiantes mais incorrectes.

Lisez la confiance, ne prenez pas juste l’étiquette. SingleR élague les appels de faible confiance en NA dans pred$pruned.labels, et plotScoreHeatmap() devrait montrer une bande brillante par cellule (une correspondance nette). Ensuite, validez : vérifiez que les étiquettes atterrissent sur des regroupements UMAP cohérents, concordent avec quelques marqueurs canoniques, et — si vous avez des étiquettes connues — croisez-les avec elles. Traitez l’annotation comme une hypothèse que vous confirmez.

Oui, et c’est souvent mieux. Passez vos identifiants de regroupement avec SingleR(test = ..., ref = ..., labels = ..., clusters = obj$seurat_clusters) et SingleR attribue une étiquette par regroupement en mettant en commun ses cellules. L’annotation au niveau du regroupement est plus rapide sur les grands jeux de données et plus robuste que les appels par cellule, car moyenner de nombreuses cellules réduit le bruit dans le profil de chaque cellule individuelle.

Testez vos connaissances

En partant de ifnb_subset.rds, normalisez l’objet, exécutez SingleR face à celldex::MonacoImmuneData() avec ref$label.main, puis confirmez l’annotation sur les monocytes : croisez pred$labels avec obj$seurat_annotations et vérifiez que (presque) toutes les cellules CD14 Mono et CD16 Mono ont été appelées Monocytes.

L’annotation est pred <- SingleR(test = GetAssayData(obj, layer = "data"), ref = ref, labels = ref$label.main). Pour noter les monocytes, construisez table(SingleR = pred$labels, known = obj$seurat_annotations) et lisez les colonnes CD14 Mono et CD16 Mono — la ligne Monocytes devrait contenir presque toutes leurs cellules.

library(Seurat); library(SingleR); library(celldex)
d <- readRDS("_data/ifnb_subset.rds")
obj <- CreateSeuratObject(counts = d$counts, meta.data = d$meta)
obj <- NormalizeData(obj)
ref  <- celldex::MonacoImmuneData()
pred <- SingleR(test = GetAssayData(obj, layer = "data"), ref = ref, labels = ref$label.main)

tab <- table(SingleR = pred$labels, known = obj$seurat_annotations)
tab[, c("CD14 Mono", "CD16 Mono")]           # both columns concentrate on the Monocytes row

Sur 925 cellules CD14 Mono, 915 sont appelées Monocytes ; les 255 cellules CD16 Mono le sont toutes — l’unique étiquette Monocytes de la référence replie correctement les deux sous-types. Les lignées bien séparées s’annotent presque parfaitement ; ce sont les sous-états proches de lymphocytes T que la référence large brouille.

A. L’annotation a fonctionné — le cerveau doit contenir ces cellules immunitaires. B. SingleR renvoie toujours l’étiquette de référence la mieux correspondante, même lorsque le vrai type cellulaire est absent de la référence, de sorte qu’une référence mal appariée produit des appels confiants mais faux. C. Vous avez oublié de normaliser la requête.

B. SingleR attribue à chaque cellule l’étiquette la plus proche dans la référence que vous lui avez donnée — il ne peut pas inventer une catégorie que la référence n’a pas. Une référence immunitaire sur des cellules de cerveau étiquette donc les neurones et la glie selon le type immunitaire avec lequel ils corrèlent le plus, avec confiance et à tort. Le correctif est une référence qui couvre les types cellulaires de votre tissu, plus une vérification de cohérence par marqueurs. Faire correspondre la référence à la biologie est la décision qui rend l’annotation automatique digne de confiance.

Conclusion

Étiqueter les regroupements à la main est lent et subjectif ; l’annotation automatique transfère plutôt les types cellulaires depuis une référence annotée. Vous avez parcouru toute la boucle : normaliser la requête, annoter chaque cellule avec SingleR face à une référence immunitaire celldex en un seul appel, tracer l’UMAP annoté, lire la confiance (la heatmap des scores, les NA élagués), et valider face aux étiquettes connues — où SingleR a cloué les monocytes (99 %), les lymphocytes B (96 %) et les cellules NK, et a honnêtement brouillé les états proches de lymphocytes T CD4/CD8 que la référence large ne résout pas. Les alternatives suivent la même logique : le transfert par ancres de Seurat (FindTransferAnchors / MapQuery) lorsque vous avez votre propre objet de référence annoté, Azimuth et Symphony lorsqu’un grand atlas curé existe pour votre tissu. La leçon durable est la discipline, pas l’outil : une étiquette automatique est une hypothèse porteuse d’une confiance — faites correspondre la référence à la biologie, lisez le score, et confirmez les appels qui comptent avec des marqueurs.

Leçons connexes

🟢 Avec un agent IA

Demandez à Prova « comment annoter les types cellulaires dans mon propre objet Seurat avec SingleR, et comment vérifier que les étiquettes sont dignes de confiance ? » — elle répond avec du code R que vous pouvez exécuter sur vos propres données : choisir une référence celldex, exécuter SingleR(), lire la heatmap des scores et les appels élagués, et valider les étiquettes face aux marqueurs. 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é — copiez n’importe quel bloc et exécutez-le pour les reproduire. The runtime is the judge.

Références

  • Aran, D., et al. (2019). Reference-based analysis of lung single-cell sequencing reveals a transitional profibrotic macrophage (SingleR). Nature Immunology, 20(2), 163–172. https://doi.org/10.1038/s41590-018-0276-y
  • Monaco, G., et al. (2019). RNA-Seq signatures normalized by mRNA abundance allow absolute deconvolution of human immune cell types — la source de la référence MonacoImmuneData. Cell Reports, 26(6), 1627–1640. https://doi.org/10.1016/j.celrep.2019.01.041
  • Hao, Y., et al. (2021). Integrated analysis of multimodal single-cell data (Seurat v4; FindTransferAnchors / MapQuery). Cell, 184(13), 3573–3587. https://doi.org/10.1016/j.cell.2021.04.048
  • Kang, J. B., et al. (2021). Efficient and precise single-cell reference atlas mapping with Symphony. Nature Communications, 12, 5890. https://doi.org/10.1038/s41467-021-25957-x
  • Kang, H. M., et al. (2018). Multiplexed droplet single-cell RNA-sequencing using natural genetic variation — la source du jeu de données PBMC ifnb. Nature Biotechnology, 36(1), 89–94. https://doi.org/10.1038/nbt.4042

Réutilisation

Citation

BibTeX
@online{2026,
  author = {},
  title = {Annotation des types cellulaires en R : SingleR \& celldex},
  date = {2026-07-03},
  url = {https://www.datanovia.com/learn/bioinformatics/single-cell/scrnaseq-reference-mapping.html},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“Annotation des types cellulaires en R : SingleR & celldex.” 2026. July 3. https://www.datanovia.com/learn/bioinformatics/single-cell/scrnaseq-reference-mapping.html.