Le conteneur SummarizedExperiment en R : assays, rowData & colData
Gardez votre matrice de comptage, votre table de gènes et votre table d’échantillons dans un seul objet qui s’indexe de concert — pour qu’un réordonnancement malencontreux ne puisse jamais les désaligner silencieusement
Le SummarizedExperiment est le conteneur sur lequel repose presque tout workflow omique Bioconductor. Apprenez ce qu’il contient — une matrice assays (gènes × échantillons), un rowData par gène et un colData par échantillon — comment ces trois pièces restent alignées quand vous extrayez un sous-ensemble ou réordonnez, et comment en construire un à partir d’une simple matrice. Sur un exemple jouet et le vrai jeu de données airway, avec une note sur son extension single-cell, SingleCellExperiment.
Date de publication
29 juin 2026
Modifié
7 juillet 2026
AstucePoints clés
Un SummarizedExperiment regroupe trois choses dans un seul objet : une matrice assays (lignes = gènes/éléments, colonnes = échantillons), rowData (une ligne par gène) et colData (une ligne par échantillon).
Tout son intérêt est l’alignement : extrayez un sous-ensemble ou réordonnez l’objet et la matrice, rowData et colData bougent ensemble — ils ne peuvent jamais se désynchroniser silencieusement.
Construisez-en un avec SummarizedExperiment(assays = list(counts = m), colData = ..., rowData = ...) ; le constructeur lève une erreur quand les noms ne concordent pas — un garde-fou utile, pas une gêne.
Accédez-y avec assay()/assays(), colData(), rowData(), dim(), et rownames()/colnames().
Le vrai objet airway est un RangedSummarizedExperiment ; DESeqDataSet et (pour le single-cell) SingleCellExperiment l’étendent tous deux — apprenez-le une fois, utilisez-le partout dans Bioconductor.
Introduction
La plupart des analyses omiques commencent avec trois tables : une matrice de comptage (gènes × échantillons), une table de métadonnées d’échantillons (traitement, lignée cellulaire, batch), et une table d’informations sur les gènes (symbole, biotype, coordonnées). Gardez-les comme trois objets séparés et vous n’êtes qu’à une ligne d’étourderie du désastre — triez les colonnes de la matrice, retirez un échantillon, ou réordonnez les métadonnées, et les trois tables ne concordent plus. Rien ne lève d’erreur. Vos échantillons « traités » sont désormais étiquetés « contrôle », et chaque résultat en aval est silencieusement faux.
Le SummarizedExperiment est la réponse de Bioconductor : un conteneur unique qui relie la matrice, la table par échantillon et la table par gène pour qu’ils forment un sous-ensemble et se réordonnent comme une seule unité. C’est l’objet que comprennent airway, DESeq2, edgeR, limma et les outils single-cell. Apprenez son anatomie une fois et le reste de la pile génomique cesse de ressembler à un tas de data frames mal accordés.
Le problème : trois objets qui doivent rester alignés
Imaginez les trois tables séparément. La matrice a les échantillons en colonnes ; la table d’échantillons a une ligne par échantillon ; la table de gènes a une ligne par gène. Le lien entre elles est la position — la colonne 3 de la matrice est censée être la ligne 3 de la table d’échantillons. Re-triez l’une et pas les autres et ce lien se rompt silencieusement :
m <-matrix(1:6, nrow =2,dimnames =list(c("geneA", "geneB"), c("s1", "s2", "s3")))samples <-data.frame(condition =c("ctrl", "ctrl", "treated"),row.names =c("s1", "s2", "s3"))# Reorder the matrix columns but forget the sample table:m <- m[, c("s3", "s1", "s2")]colnames(m) # s3, s1, s2
[1] "s3" "s1" "s2"
rownames(samples) # still s1, s2, s3 -> now out of sync
[1] "s1" "s2" "s3"
La colonne 1 de la matrice est maintenant s3, mais la ligne 1 de samples est toujours s1. Un SummarizedExperiment rend cette erreur impossible.
Un seul conteneur : SummarizedExperiment
Un SummarizedExperiment contient les mêmes trois tables, mais comme un seul objet dont les dimensions sont verrouillées ensemble. Les colonnes de la matrice assay sont les lignes de colData ; les lignes de la matrice assay sont les lignes de rowData. Extrayez un sous-ensemble ou réordonnez l’objet et les trois pièces suivent de concert — il n’y a aucun moyen de bouger l’une sans les autres.
En construire un de zéro
Rien de magique ici. Partez d’une simple matrice d’entiers (gènes × échantillons), d’une table colData avec une ligne par échantillon, et d’une table rowData avec une ligne par gène — puis confiez les trois au constructeur. Les noms de lignes relient le tout.
L’affichage est une carte de l’objet : dim: 4 3 (4 gènes × 3 échantillons), un assay nommé counts, les quatre noms de gènes dans rownames, une colonne rowData (symbol), les trois noms d’échantillons dans colnames, et une colonne colData (condition). Tout ce que vous avez mis est comptabilisé, et les dimensions sont désormais liées ensemble.
Anatomie d’un SummarizedExperiment
Trois slots, chacun atteint par un accesseur du même nom :
flowchart TD
SE["SummarizedExperiment"]
SE --> A["assays() — les mesures<br/>une matrice gènes × échantillons<br/>(ex. comptages bruts)"]
SE --> R["rowData() — table des éléments<br/>une ligne par gène<br/>(symbole, biotype, …)"]
SE --> C["colData() — table d'échantillons<br/>une ligne par échantillon<br/>(condition, batch, …)"]
A -. "les lignes s'alignent sur" .-> R
A -. "les colonnes s'alignent sur" .-> C
Accédez à chaque slot avec son accesseur. Chaque bloc ci-dessous reconstruit d’abord l’objet jouet, pour que vous puissiez copier et exécuter n’importe lequel d’entre eux indépendamment :
DataFrame with 3 rows and 1 column
condition
<character>
sample1 ctrl
sample2 ctrl
sample3 treated
rowData(se) # the per-gene table
DataFrame with 4 rows and 1 column
symbol
<character>
gene1 TP53
gene2 EGFR
gene3 MYC
gene4 GAPDH
Quelques règles à fixer en mémoire :
assay() vs assays() — un conteneur peut contenir plusieurs matrices de même forme (comptages bruts, comptages normalisés, comptages logarithmiques). assays() est la liste nommée entière ; assay(se) (ou assay(se, "counts")) en extrait une comme simple matrice.
rowData vs colData — rowData annote les lignes (gènes), colData les colonnes (échantillons). Atteignez une seule colonne colData avec se$condition, exactement comme un data frame.
dim(se) est gènes × échantillons — les lignes d’abord, les colonnes ensuite, comme toute matrice.
L’indexation alignée : la fonctionnalité phare
C’est la raison d’être du conteneur. Indexez-le comme une matrice — se[genes, samples] — et l’assay, rowDataetcolData sont tous mis en sous-ensemble d’un seul geste. Prenez les deux premiers gènes :
library(SummarizedExperiment)set.seed(1)counts <-matrix(rpois(12, lambda =50), nrow =4,dimnames =list(paste0("gene", 1:4), paste0("sample", 1:3)))se <-SummarizedExperiment(assays =list(counts = counts),colData =DataFrame(condition =c("ctrl", "ctrl", "treated"), row.names =colnames(counts)),rowData =DataFrame(symbol =c("TP53", "EGFR", "MYC", "GAPDH"), row.names =rownames(counts)))sub <- se[1:2, ] # first two GENES, all samplesrowData(sub) # rowData followed automatically
DataFrame with 2 rows and 1 column
symbol
<character>
gene1 TP53
gene2 EGFR
rowData s’est réduit aux deux gènes que vous avez gardés — vous n’y avez jamais touché directement. Maintenant, le geste contre lequel l’introduction mettait en garde : sélectionner des échantillons par une condition dans colData. Les colonnes de la matrice et la table d’échantillons restent parfaitement cohérentes, car elles sont le même objet :
colData(treated) # the matching sample row(s) — still aligned
DataFrame with 1 row and 1 column
condition
<character>
sample3 treated
Un échantillon, la bonne colonne de comptages, la bonne ligne de métadonnées — aucune comptabilité à tenir, aucun risque d’inversion. Cette garantie est toute la raison d’être du format.
Un vrai cas : le jeu de données airway
L’objet jouet est la vraie chose en miniature. Le jeu de données airway — du RNA-seq de cellules musculaires lisses des voies respiratoires, traitées ou non à la dexaméthasone — se présente comme un RangedSummarizedExperiment (un SummarizedExperiment dont les lignes portent aussi des plages génomiques, stockées dans rowRanges()). Les mêmes accesseurs fonctionnent :
dim: 63677 8 — 63 677 gènes répartis sur 8 échantillons, un assay counts, les identifiants de gènes dans rownames, les identifiants d’échantillons dans colnames. Extrayez les pièces exactement comme avant :
library(airway)data("airway")assay(airway)[1:5, 1:4] # raw integer counts: genes × samples
library(airway)data("airway")colData(airway)[, c("cell", "dex")] # the experimental design
DataFrame with 8 rows and 2 columns
cell dex
<factor> <factor>
SRR1039508 N61311 untrt
SRR1039509 N61311 trt
SRR1039512 N052611 untrt
SRR1039513 N052611 trt
SRR1039516 N080611 untrt
SRR1039517 N080611 trt
SRR1039520 N061011 untrt
SRR1039521 N061011 trt
Le colDataest le plan d’expérience : quatre lignées cellulaires (cell), chacune mesurée non traitée (dex = untrt) et traitée (dex = trt). Cette table est ce que vous confiez à une formule de modèle comme ~ cell + dex. L’annotation par gène vit dans rowData (ici, les symboles de gènes et les biotypes) :
C’est exactement l’objet que consomme la série RNA-seq bulk : la leçon matrice de comptage & CQ charge airway comme un SummarizedExperiment, et l’expression différentielle avec DESeq2 l’enveloppe dans un DESeqDataSet — qui est lui-même un SummarizedExperiment avec des slots supplémentaires. Apprenez le conteneur ici et ces leçons se lisent comme de petites étapes, pas comme du vocabulaire nouveau.
SingleCellExperiment : l’extension single-cell
Les données single-cell sont la même idée avec deux slots supplémentaires. SingleCellExperimentétend SummarizedExperiment : c’est un SummarizedExperiment (donc assay(), colData(), rowData() et l’indexation alignée fonctionnent tous à l’identique) plus reducedDims pour les représentations de cellules (PCA, t-SNE, UMAP) et altExps pour les éléments alternatifs (spike-ins, marqueurs dérivés d’anticorps) :
library(SingleCellExperiment)# A SingleCellExperiment IS a SummarizedExperiment, plus:sce <-SingleCellExperiment(assays =list(counts = counts))reducedDim(sce, "PCA") # per-cell coordinates from a dimension reductionaltExp(sce, "ERCC") # a second feature set (e.g. spike-in controls)
Parce qu’il hérite de SummarizedExperiment, tout dans cette leçon se transpose directement — les seules nouveautés sont les représentations (embeddings) et les expériences alternatives. La future série single-cell RNA-seq construit tout son workflow sur SingleCellExperiment.
Problèmes fréquents
Les noms de lignes de colData ne correspondent pas aux colonnes de l’assay. Le constructeur refuse de deviner : si les noms de lignes de colData (ou rowData) ne sont pas identiques aux noms de colonnes (ou de lignes) de la matrice, il lève une erreur : “the rownames and colnames of the supplied assay(s) must be NULL or identical to those of the SummarizedExperiment object … to construct”. Cette erreur, c’est le garde-fou qui fait son travail. Alignez d’abord les noms vous-même — counts <- counts[, rownames(colData)] — puis construisez.
Confondre assay() et assays().assays(se) renvoie la liste de toutes les matrices stockées ; assay(se) renvoie une seule matrice (la première, ou celle que vous nommez avec assay(se, "logcounts")). Si une fonction se plaint d’avoir reçu une liste là où elle voulait une matrice, vous avez appelé assays() là où vous vouliez assay().
Indexer en inversant les dimensions. L’indexation est se[genes, samples] — les lignes (gènes) d’abord, les colonnes (échantillons) ensuite, comme toute matrice R. se[, se$dex == "trt"] sélectionne des échantillons ; se[my_genes, ] sélectionne des gènes. Inversez-les et vous obtenez soit une erreur, soit, pire, la mauvaise tranche.
Questions fréquentes
NoteQu’est-ce qu’un SummarizedExperiment en R ?
C’est un conteneur Bioconductor qui stocke une matrice assay (lignes = gènes/éléments, colonnes = échantillons) avec une table par échantillon (colData) et une table par gène (rowData) dans un seul objet. Ses dimensions sont verrouillées, de sorte que l’extraction de sous-ensembles ou le réordonnancement déplace la matrice et les deux tables de métadonnées ensemble — elles ne peuvent jamais se désynchroniser.
NoteQuelle est la différence entre assay() et assays() ?
Un SummarizedExperiment peut contenir plusieurs matrices de même forme (ex. counts, logcounts). assays(se) renvoie la liste nommée entière ; assay(se) renvoie une seule matrice — la première, ou celle que vous nommez avec assay(se, "counts").
NoteEn quoi rowData diffère-t-il de colData ?
rowData annote les lignes de l’assay — une ligne par gène/élément (symbole, biotype, coordonnées). colData annote les colonnes — une ligne par échantillon (condition, batch, lignée cellulaire). Lisez un seul champ d’échantillon avec se$condition, exactement comme un data frame.
NoteUn DESeqDataSet est-il un SummarizedExperiment ?
Oui. DESeqDataSet (DESeq2) étendRangedSummarizedExperiment, donc tous les accesseurs — assay(), colData(), rowData(), dim() — et l’indexation alignée fonctionnent dessus. Il ajoute simplement les slots dont DESeq2 a besoin (facteurs de taille, dispersions, résultats).
NoteQuelle est la différence entre SummarizedExperiment et SingleCellExperiment ?
SingleCellExperiment est un SummarizedExperiment avec deux slots supplémentaires pour les données single-cell : reducedDims (représentations PCA, t-SNE, UMAP) et altExps (ensembles d’éléments alternatifs comme les spike-ins). Tout ce que vous apprenez sur SummarizedExperiment s’y applique à l’identique.
Testez vos connaissances
ImportantÀ vous : construire et indexer un SummarizedExperiment
Construisez un petit SummarizedExperiment à partir d’une matrice de comptage de 3 gènes × 4 échantillons. Donnez-lui un colData avec une colonne group ("A", "A", "B", "B") et un rowData avec une colonne symbol. Puis gardez uniquement les échantillons du groupe « B » et confirmez que assay() et colData() sont toujours alignés.
AstuceIndice
Définissez row.names sur colData et rowData pour correspondre aux colnames et rownames de la matrice. Indexez avec se[, se$group == "B"], puis affichez assay() et colData() du résultat.
Seules les colonnes du groupe B de la matrice survivent, et colData affiche exactement ces deux échantillons — vous n’avez jamais indexé les métadonnées vous-même, le conteneur les a maintenues au pas.
NoteVérification rapide : que renvoie se[1:10, se$dex == "trt"] ?
A. Seule la matrice assay est mise en sous-ensemble ; rowData et colData gardent leurs tailles d’origine. B. Les 10 premiers gènes et les échantillons traités, avec rowData et colData mis en sous-ensemble pour correspondre. C. Une erreur, car on ne peut pas indexer un SummarizedExperiment avec une condition.
AstuceAfficher la réponse
B. L’indexation est se[genes, samples]. Les 10 premières lignes (gènes) et les colonnes où dex == "trt" sont conservées, et rowData et colData sont mis en sous-ensemble de concert — cette indexation alignée est toute la raison d’être du conteneur.
Conclusion
Un SummarizedExperiment est l’objet sur lequel repose le monde Bioconductor : une matrice assays de gènes × échantillons, une table rowData pour les gènes, et une table colData pour les échantillons, le tout réuni dans un conteneur dont les dimensions bougent ensemble. Vous en avez construit un à partir d’une simple matrice, y avez accédé avec assay()/colData()/rowData(), et avez vu la fonctionnalité qui justifie son existence — l’indexation alignée, où se[genes, samples] garde la matrice et les deux tables de métadonnées cohérentes pour qu’un réordonnancement ne puisse jamais mal étiqueter un échantillon. Le vrai objet airway est la même chose à grande échelle, et DESeqDataSet et SingleCellExperiment ne font que l’étendre. Ensuite, mettez-le à l’œuvre dans la matrice de comptage RNA-seq & le CQ et l’expression différentielle avec DESeq2.
Cette leçon est reproductible : chaque objet et chaque nombre de cette page a été produit par le code montré — copiez n’importe quel bloc et exécutez-le pour les reproduire. The runtime is the judge.
Références
Morgan, M., Obenchain, V., Hester, J., & Pagès, H. (2024). SummarizedExperiment: a container for representing assay data and metadata. Bioconductor. Package R.
Amezquita, R. A., et al. (2020). Orchestrating single-cell analysis with Bioconductor (la classe SingleCellExperiment). Nature Methods, 17, 137–145.
Himes, B. E., et al. (2014). RNA-Seq transcriptome profiling identifies CRISPLD2 as a glucocorticoid responsive gene in airway smooth muscle cells (le jeu de données airway). PLoS ONE, 9(6), e99625.