Contrôle qualité Seurat : charger et filtrer un jeu de données scRNA-seq (pbmc3k)

Transformez une matrice 10x brute en un objet Seurat propre — inspectez les gènes, les comptages et le contenu mitochondrial par cellule, puis filtrez les gouttelettes vides et les cellules mourantes avant de regrouper

Un guide pratique du contrôle qualité pour le RNA-seq single-cell en R avec Seurat. Chargez le jeu de données 10x canonique pbmc3k avec Read10X, construisez un objet Seurat, et calculez les trois métriques de CQ que toute analyse passe au crible — gènes par cellule (nFeature_RNA), comptages par cellule (nCount_RNA) et pourcentage mitochondrial (percent.mt). Visualisez-les avec des graphiques en violon et des nuages de points, choisissez des seuils de filtrage pertinents avec un raisonnement en langage clair, et sous-sélectionnez un ensemble propre de cellules prêtes pour la normalisation et le regroupement.

Date de publication

29 juin 2026

Modifié

7 juillet 2026

AstucePoints clés
  • Un run 10x vous donne une matrice de comptage gènes × cellules, mais toutes les colonnes ne sont pas une vraie cellule — gouttelettes vides, doublets et cellules mourantes s’y mélangent. Le contrôle qualité les retire avant l’analyse.
  • Chargez la matrice avec Read10X() et construisez un objet Seurat avec CreateSeuratObject(), qui écarte déjà les gouttelettes les plus vides (min.features) et les gènes jamais détectés (min.cells).
  • Examinez chaque cellule sur trois métriques de CQ : gènes par cellule (nFeature_RNA), comptages par cellule (nCount_RNA) et la fraction mitochondriale (percent.mt, calculée avec PercentageFeatureSet).
  • Regardez avant de couper : un VlnPlot des trois métriques plus un FeatureScatter de leur relation vous indiquent où finissent les vraies cellules et où commence le rebut — les seuils se lisent sur la distribution, ils ne se mémorisent pas.
  • Filtrez avec subset(), puis indiquez ce que vous avez conservé. Sur pbmc3k, nFeature_RNA 200–2 500 et percent.mt < 5 % conserve 2 638 cellules sur 2 700.

Introduction

Votre run single-cell 10x Genomics revient sous forme de matrice de comptage gènes × cellules creuse — des milliers de colonnes, une par code-barres de cellule. Mais un code-barres n’est pas une cellule. Certaines gouttelettes étaient vides et n’ont capté que de l’ARN ambiant ; d’autres ont attrapé deux cellules à la fois (un doublet) ; certaines cellules étaient déjà mourantes au moment de l’encapsulation, laissant fuir l’ARNm cytoplasmique et un pic révélateur de transcrits mitochondriaux. Injectez ce mélange directement dans le regroupement et vous obtenez des types cellulaires fantômes et des frontières floues.

Le contrôle qualité est la première chose à faire, et c’est simple : mesurez quelques propriétés de chaque cellule, examinez leurs distributions, et écartez les cellules qui se trouvent dans les queues de rebut. Cette leçon fait exactement cela sur pbmc3k — le jeu de données canonique de 2 700 cellules mononucléées du sang périphérique sur lequel repose le tutoriel Seurat — de sorte que le workflow se transpose directement à vos propres données 10x.

Charger les données dans un objet Seurat

La sortie 10x se compose de trois fichiers dans un même dossier : la matrice creuse (matrix.mtx.gz), les codes-barres de cellules (barcodes.tsv.gz) et les noms de gènes (features.tsv.gz). Read10X() lit le dossier et renvoie la matrice de comptage ; CreateSeuratObject() l’enveloppe dans l’objet sur lequel travaille chaque étape en aval.

library(Seurat)

# Read the 10x folder -> a sparse genes x cells count matrix
pbmc.data <- Read10X("_data/filtered_gene_bc_matrices/hg19")
dim(pbmc.data)                  # genes x cells, before any filtering
[1] 32738  2700
# Build the Seurat object: drop genes seen in < 3 cells and cells with < 200 genes
pbmc <- CreateSeuratObject(pbmc.data, project = "pbmc3k",
                           min.cells = 3, min.features = 200)
pbmc
An object of class Seurat 
13714 features across 2700 samples within 1 assay 
Active assay: RNA (13714 features, 0 variable features)
 1 layer present: counts

La matrice brute compte 32 738 gènes pour 2 700 cellules. Les deux arguments du constructeur réalisent un premier nettoyage peu coûteux : min.cells = 3 retire les gènes détectés dans moins de trois cellules (ils ne portent aucun signal exploitable et ne font qu’alourdir la matrice), et min.features = 200 retire les gouttelettes exprimant moins de 200 gènes (presque certainement vides). Il reste 13 714 gènes pour 2 700 cellules — les mêmes 2 700 ici parce que la matrice 10x filtrée avait déjà subi l’appel des codes-barres, mais sur une sortie brute min.features seul peut écarter des milliers de gouttelettes vides.

Les trois métriques de CQ

CreateSeuratObject() stocke automatiquement deux métriques pour chaque cellule : nCount_RNA (comptages totaux, la taille de librairie) et nFeature_RNA (nombre de gènes détectés). La troisième — le pourcentage mitochondrial — c’est vous qui l’ajoutez. Une fraction mitochondriale élevée est la signature classique d’une cellule stressée ou mourante : à mesure que la membrane se dégrade, l’ARNm cytoplasmique fuit tandis que les transcrits mitochondriaux restent piégés, de sorte que leur part dans le total augmente.

PercentageFeatureSet() le calcule à partir des noms de gènes. Dans ce jeu de données humain, les gènes mitochondriaux commencent tous par MT-, si bien qu’un motif "^MT-" les capture.

library(Seurat)
pbmc.data <- Read10X("_data/filtered_gene_bc_matrices/hg19")
pbmc <- CreateSeuratObject(pbmc.data, project = "pbmc3k",
                           min.cells = 3, min.features = 200)

# Fraction of counts from mitochondrial genes (human: gene symbols start with "MT-")
pbmc[["percent.mt"]] <- PercentageFeatureSet(pbmc, pattern = "^MT-")

head(pbmc@meta.data)            # the per-cell QC table
                 orig.ident nCount_RNA nFeature_RNA percent.mt
AAACATACAACCAC-1     pbmc3k       2419          779  3.0177759
AAACATTGAGCTAC-1     pbmc3k       4903         1352  3.7935958
AAACATTGATCAGC-1     pbmc3k       3147         1129  0.8897363
AAACCGTGCTTCCG-1     pbmc3k       2639          960  1.7430845
AAACCGTGTATGCG-1     pbmc3k        980          521  1.2244898
AAACGCACTGGTAC-1     pbmc3k       2163          781  1.6643551

Les trois métriques résident maintenant dans pbmc@meta.data, une ligne par cellule. Résumez-les avant de tracer — les nombres vous disent à quoi ressemble la « normale » pour ce jeu de données :

summary(pbmc@meta.data[, c("nFeature_RNA", "nCount_RNA", "percent.mt")])
  nFeature_RNA      nCount_RNA      percent.mt    
 Min.   : 212.0   Min.   :  546   Min.   : 0.000  
 1st Qu.: 690.0   1st Qu.: 1756   1st Qu.: 1.537  
 Median : 816.0   Median : 2196   Median : 2.031  
 Mean   : 845.5   Mean   : 2365   Mean   : 2.217  
 3rd Qu.: 952.0   3rd Qu.: 2762   3rd Qu.: 2.643  
 Max.   :3400.0   Max.   :15818   Max.   :22.569  

La cellule médiane exprime 816 gènes à partir de 2 196 comptages, avec une fraction mitochondriale d’environ 2 %. Mais les maxima — 3 400 gènes, 15 818 comptages, 22,6 % mitochondrial — sont loin dans les queues. Ce sont ces extrêmes que vise le CQ.

Visualiser les métriques de CQ

Un graphique en violon montre la distribution complète de chaque métrique sur l’ensemble des cellules — où se situe le gros de l’effectif et la longueur de la queue. C’est la figure sur laquelle vous lisez vos seuils.

library(Seurat)

VlnPlot(pbmc, features = c("nFeature_RNA", "nCount_RNA", "percent.mt"), ncol = 3)

Three violin plots side by side for the pbmc3k cells. nFeature_RNA: most cells between roughly 500 and 1,300 genes with a thin tail above 2,500. nCount_RNA: most cells between about 1,000 and 4,000 counts. percent.mt: most cells under 3 percent with a sparse tail of cells reaching above 5 and up to 22 percent. Each cell is a point overlaid on the violin.

Lisez-le de gauche à droite. nFeature_RNA et nCount_RNA sont denses en bas et s’amincissent vers le haut — un petit nombre de cellules expriment bien plus de gènes et de comptages que les autres, la signature des doublets (deux cellules, donc environ deux fois plus de matériel). percent.mt colle au bas pour presque toutes les cellules mais présente une fine queue supérieure dépassant 20 % — ce sont les cellules mourantes.

Les deux nuages de points montrent comment les métriques se rapportent les unes aux autres, ce qui affine les coupes. FeatureScatter() affiche la corrélation dans son titre.

library(Seurat)
library(patchwork)

plot1 <- FeatureScatter(pbmc, feature1 = "nCount_RNA", feature2 = "percent.mt")
plot2 <- FeatureScatter(pbmc, feature1 = "nCount_RNA", feature2 = "nFeature_RNA")
plot1 + plot2

Two scatter plots of pbmc3k cells. Left: counts per cell against mitochondrial percentage, a weak negative correlation of -0.13, with a cluster of cells low on both axes and a few high-mitochondrial cells off to the upper left. Right: counts per cell against genes per cell, a tight near-linear relationship with correlation 0.95.

Comptages vs gènes (à droite) sont fortement corrélés (0,95) — comme attendu, les cellules ayant plus de transcrits détectent plus de gènes, et la ligne quasi droite signifie qu’aucune grande population ne se comporte de façon anormale. Comptages vs pourcentage mitochondrial (à gauche) ne sont presque pas corrélés (−0,13) : les cellules à fort taux mitochondrial sont dispersées hors du nuage principal au lieu de suivre la taille de librairie, et c’est exactement pourquoi percent.mt est un filtre distinct, non redondant avec nCount_RNA.

Choisir les seuils de filtrage

Les seuils se lisent sur les distributions ci-dessus, ils ne se mémorisent pas — ils dépendent du tissu, de la chimie et de la profondeur de séquençage. La logique se résume toujours aux trois mêmes coupes :

  • Une borne inférieure sur les gènes par cellule retire les gouttelettes vides et les cellules abîmées sans presque aucun transcrit. Le min.features = 200 du constructeur a déjà fixé ce plancher, si bien que nFeature_RNA > 200 ne fait que le confirmer.
  • Une borne supérieure sur les gènes par cellule retire les doublets probables — des cellules exprimant bien plus de gènes que la population. Le violon de pbmc3k s’amincit au-delà de ~2 500 gènes, donc nFeature_RNA < 2500 rogne cette queue.
  • Une borne supérieure sur le pourcentage mitochondrial retire les cellules mourantes. Le gros des cellules pbmc se situe sous 3 %, avec une queue nette au-delà de 5 %, si bien que percent.mt < 5 est la coupe naturelle ici.

L’objectif est de rogner les queues de rebut évidentes, pas de poursuivre un nombre parfait — placez chaque coupe à l’épaule de la distribution, là où finissent les vraies cellules. Pour pbmc3k, les seuils établis sont nFeature_RNA entre 200 et 2 500 et percent.mt en dessous de 5 %.

Filtrer les cellules

subset() ne conserve que les cellules qui satisfont les trois conditions.

library(Seurat)
pbmc.data <- Read10X("_data/filtered_gene_bc_matrices/hg19")
pbmc <- CreateSeuratObject(pbmc.data, project = "pbmc3k",
                           min.cells = 3, min.features = 200)
pbmc[["percent.mt"]] <- PercentageFeatureSet(pbmc, pattern = "^MT-")

before <- ncol(pbmc)
pbmc <- subset(pbmc, subset = nFeature_RNA > 200 & nFeature_RNA < 2500 & percent.mt < 5)
after <- ncol(pbmc)

c(before = before, after = after, removed = before - after)
 before   after removed 
   2700    2638      62 

Le filtrage retire 62 cellules sur 2 700 (2,3 %), en laissant 2 638 pour l’analyse en aval. La répartition est parlante : 57 cellules échouent sur le pourcentage mitochondrial (≥ 5 %) et 5 sur la borne supérieure des gènes (≥ 2 500) — le filtre mitochondrial fait donc l’essentiel du travail, et aucune cellule n’a été perdue sur la borne inférieure des gènes (le constructeur s’en était déjà chargé).

Ce que vous indiqueriez : Les cellules ont été conservées si elles exprimaient 200 à 2 500 gènes avec moins de 5 % de comptages mitochondriaux, retirant 62 des 2 700 gouttelettes (2,3 %) considérées comme probablement vides, doublets ou mourantes ; 2 638 cellules de haute qualité ont été conservées. L’objet pbmc nettoyé est maintenant prêt à normaliser et trouver les gènes variables.

Problèmes fréquents

Rien n’est filtré (ou tout l’est). La cause la plus fréquente est un motif mitochondrial qui ne correspond pas aux noms de gènes. "^MT-" vise les symboles humains ; la souris utilise "^mt-" (en minuscules), et un jeu de données annoté avec des identifiants Ensembl n’a aucun préfixe MT-. Vérifiez avec grep("^MT-", rownames(pbmc), value = TRUE) — s’il ne renvoie rien, percent.mt ne contient que des zéros et le filtre est sans effet.

Read10X génère une erreur sur le dossier. Il attend les trois fichiers réunis (matrix.mtx[.gz], barcodes.tsv[.gz], features.tsv[.gz]/genes.tsv[.gz]) dans le répertoire que vous lui indiquez. Pointez-le vers le dossier, pas vers un fichier unique, et assurez-vous que les trois sont présents et tous gzippés ou tous non gzippés.

Réutiliser un même jeu de seuils partout. nFeature_RNA < 2500 et percent.mt < 5 conviennent à pbmc3k, pas universellement. Les tissus métaboliquement actifs (cœur, foie) présentent naturellement des fractions mitochondriales plus élevées ; un séquençage plus profond décale les distributions de comptages. Tracez toujours d’abord et fixez la coupe à partir des données que vous avez sous les yeux.

Questions fréquentes

nCount_RNA est le nombre total de molécules d’ARN (UMI) détectées dans une cellule — sa taille de librairie. nFeature_RNA est le nombre de gènes distincts détectés dans cette cellule. Les deux sont calculés automatiquement par CreateSeuratObject() et stockés dans pbmc@meta.data.

Utilisez PercentageFeatureSet() avec un motif qui correspond aux noms de gènes mitochondriaux : pbmc[["percent.mt"]] <- PercentageFeatureSet(pbmc, pattern = "^MT-"). Utilisez "^MT-" pour les symboles de gènes humains et "^mt-" pour la souris.

Il n’existe aucun nombre universel. Tracez nFeature_RNA, nCount_RNA et percent.mt avec VlnPlot(), puis placez chaque coupe à l’épaule de sa distribution, là où finissent les vraies cellules. Pour pbmc3k, c’est nFeature_RNA entre 200 et 2 500 et percent.mt en dessous de 5 %, mais un tissu ou une profondeur différents décaleront ces valeurs.

Une fraction mitochondriale élevée est la signature d’une cellule stressée ou mourante : à mesure que la membrane cellulaire se dégrade, l’ARNm cytoplasmique fuit tandis que les transcrits mitochondriaux restent piégés à l’intérieur de l’organite, de sorte que leur part dans les comptages restants augmente. Conserver ces cellules injecte un bruit technique qui peut se faire passer pour un type cellulaire.

En partie. Une borne supérieure élevée sur nFeature_RNA/nCount_RNA retire les doublets les plus évidents (deux cellules donnent environ deux fois plus de matériel), ce que fait ici la coupe nFeature_RNA < 2500. Pour une élimination rigoureuse des doublets, des outils dédiés (DoubletFinder, scDblFinder) modélisent explicitement la distribution des doublets — les seuils de CQ sont un premier passage, pas une solution complète.

Testez vos connaissances

À partir de la matrice pbmc3k commitée, construisez l’objet Seurat, ajoutez percent.mt, et indiquez combien de cellules ont une fraction mitochondriale de 5 % ou plus. Appliquez ensuite le filtre complet et confirmez le compte final de cellules.

Après avoir ajouté percent.mt, sum(pbmc$percent.mt >= 5) compte les cellules à fort taux mitochondrial. subset() avec les trois conditions applique le filtre ; ncol() donne le compte de cellules.

library(Seurat)
pbmc.data <- Read10X("_data/filtered_gene_bc_matrices/hg19")
pbmc <- CreateSeuratObject(pbmc.data, project = "pbmc3k",
                           min.cells = 3, min.features = 200)
pbmc[["percent.mt"]] <- PercentageFeatureSet(pbmc, pattern = "^MT-")

sum(pbmc$percent.mt >= 5)            # 57 cells fail the mitochondrial cut
pbmc <- subset(pbmc, subset = nFeature_RNA > 200 & nFeature_RNA < 2500 & percent.mt < 5)
ncol(pbmc)                           # 2638 cells remain

57 des 2 700 cellules portent 5 % ou plus de comptages mitochondriaux ; après le filtre complet, 2 638 cellules de haute qualité subsistent.

A. Des doublets — deux cellules capturées dans une même gouttelette. B. Des cellules mourantes ou stressées laissant fuir l’ARNm cytoplasmique. C. Les cellules les plus profondément séquencées et de plus haute qualité.

B. Une fraction mitochondriale élevée marque les cellules mourantes ou stressées : l’ARNm cytoplasmique fuit à mesure que la membrane se dégrade, laissant les transcrits mitochondriaux surreprésentés. Les doublets, eux, sont repérés par un nFeature_RNA/nCount_RNA anormalement élevé.

Conclusion

Le contrôle qualité est le passage obligé par lequel commence toute analyse single-cell. Vous avez chargé la matrice 10x pbmc3k avec Read10X(), construit un objet Seurat, et examiné chaque cellule sur les trois métriques qui comptent — nFeature_RNA, nCount_RNA et percent.mt. Vous avez lu les seuils sur un VlnPlot et un FeatureScatter plutôt que de les mémoriser, puis utilisé subset() pour conserver les 2 638 cellules nettoyées. Les règles durables : tracez avant de couper, placez chaque seuil à l’épaule de sa distribution, et indiquez ce que vous avez conservé. L’objet nettoyé est prêt à être normalisé, à révéler ses gènes variables et à être regroupé.

Leçons connexes

🟢 Avec un agent IA

Demandez à Prova « comment contrôler la qualité de mes propres données single-cell 10x dans Seurat ? » — elle répond avec du code R que vous pouvez exécuter sur votre propre matrice, calcule les métriques de CQ et vous aide à choisir les seuils à partir de vos distributions. 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

  • Hao, Y., et al. (2021). Integrated analysis of multimodal single-cell data (Seurat v4). Cell, 184(13), 3573–3587.
  • Satija, R., Farrell, J. A., Gennert, D., Schier, A. F., & Regev, A. (2015). Spatial reconstruction of single-cell gene expression data. Nature Biotechnology, 33(5), 495–502.
  • 10x Genomics. 3k PBMCs from a Healthy Donor — la matrice gène–code-barres filtrée pbmc3k canonique (Cell Ranger 1.1.0).

Réutilisation

Citation

BibTeX
@online{2026,
  author = {},
  title = {Contrôle qualité Seurat : charger et filtrer un jeu de
    données scRNA-seq (pbmc3k)},
  date = {2026-06-29},
  url = {https://www.datanovia.com/learn/bioinformatics/single-cell/scrnaseq-quality-control.html},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“Contrôle qualité Seurat : charger et filtrer un jeu de données scRNA-seq (pbmc3k).” 2026. June 29. https://www.datanovia.com/learn/bioinformatics/single-cell/scrnaseq-quality-control.html.