Manipulation et analyse de données avec dplyr

Dernière mise à jour le 2024-09-12 | Modifier cette page

Durée estimée : 150 minutes

Vue d'ensemble

Questions

  • Analyse de données dans R à l’aide du méta-paquet Tidyverse

Objectifs

  • Décrivez l’objectif des packages dplyr et tidyr.
  • Décrivez plusieurs de leurs fonctions extrêmement utiles pour manipuler des données.
  • Décrivez le concept d’un format de tableau large et long, et voyez comment remodeler un bloc de données d’un format à l’autre.
  • Montrez comment joindre des tables.

Cet épisode est basé sur la leçon Analyse des données et Visualisation dans R pour les écologistes de Data Carpentries.

Manipulation des données à l’aide de dplyr et tidyr


Le sous-ensemble entre crochets est pratique, mais il peut être fastidieux et difficile à lire, en particulier pour les opérations compliquées.

Certains packages peuvent grandement faciliter notre tâche lorsque nous manipulons des données. Les packages dans R sont essentiellement des ensembles de fonctions supplémentaires qui vous permettent de faire plus de choses. Les fonctions que nous avons utilisées jusqu’à présent, comme str() ou data.frame(), sont intégrées à R ; Le chargement de packages peut vous donner accès à d’autres fonctions spécifiques. Avant d’utiliser un package pour la première fois, vous devez l’installer sur votre machine, puis vous devez l’importer à chaque session R suivante lorsque vous en avez besoin.

  • Le package dplyr fournit des outils puissants pour les tâches de manipulation de données. Il est conçu pour fonctionner directement avec des trames de données, avec de nombreuses tâches de manipulation optimisées.

  • Comme nous le verrons plus loin, nous souhaitons parfois qu’un bloc de données soit remodelé pour pouvoir effectuer des analyses spécifiques ou pour la visualisation. Le package tidyr résout ce problème courant de remodelage des données et fournit des outils pour manipuler les données de manière ordonnée.

Pour en savoir plus sur dplyr et tidyr après l’atelier, vous voudrez peut-être consulter ceci transformation de données pratique avec ** et ceci celui sur .

  • Le package tidyverse est un “package parapluie” qui installe plusieurs packages utiles pour l’analyse des données qui fonctionnent bien ensemble, tels que tidyr, * *dplyr**, ggplot2, tibble, etc. Ces packages nous aident à travailler et à interagir avec les données. Ils nous permettent de faire beaucoup de choses avec vos données, comme le sous-ensemble, la transformation, la visualisation, etc.

Si vous avez effectué la configuration, vous devriez déjà avoir installé le package Tidyverse. Vérifiez si vous l’avez en essayant de le charger depuis la bibliothèque :

R

## load the tidyverse packages, incl. dplyr
library("tidyverse")

Si vous recevez un message d’erreur il n'y a pas de package appelé 'tidyverse' alors vous n’avez pas installé le package pour cette version de R. Pour installer le package tidyverse, tapez :

R

BiocManager::install("tidyverse")

Si vous avez dû installer le package tidyverse, n’oubliez pas de le charger dans cette session R en utilisant la commande library() ci-dessus !

Chargement de données avec Tidyverse


Instead of read.csv(), we will read in our data using the read_csv() function (notice the _ instead of the .), from the tidyverse package readr.

R

rna <- read_csv("data/rnaseq.csv")

## view the data
rna

SORTIE

# A tibble: 32,428 × 19
   gene    sample  expression organism   age sex   infection strain  time tissue
   <chr>   <chr>        <dbl> <chr>    <dbl> <chr> <chr>     <chr>  <dbl> <chr>
 1 Asl     GSM254…       1170 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 2 Apod    GSM254…      36194 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 3 Cyp2d22 GSM254…       4060 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 4 Klk6    GSM254…        287 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 5 Fcrls   GSM254…         85 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 6 Slc2a4  GSM254…        782 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 7 Exd2    GSM254…       1619 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 8 Gjc2    GSM254…        288 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 9 Plp1    GSM254…      43217 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
10 Gnb4    GSM254…       1071 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
# ℹ 32,418 more rows
# ℹ 9 more variables: mouse <dbl>, ENTREZID <dbl>, product <chr>,
#   ensembl_gene_id <chr>, external_synonym <chr>, chromosome_name <chr>,
#   gene_biotype <chr>, phenotype_description <chr>,
#   hsapiens_homolog_associated_gene_name <chr>

Notez que la classe des données est désormais appelée « tibble ».

Tibbles modifie certains des comportements des objets de trame de données que nous avons introduits dans le précédemment. La structure des données est très similaire à une trame de données. Pour nos besoins , les seules différences sont les suivantes :

  1. Il affiche le type de données de chaque colonne sous son nom. Notez que <dbl> est un type de données défini pour contenir des valeurs numériques avec points décimaux.

  2. Il imprime uniquement les premières lignes de données et seulement autant de colonnes que peuvent contenir un écran.

Nous allons maintenant apprendre certaines des fonctions dplyr les plus courantes :

  • select() : sous-ensemble de colonnes
  • filter() : sous-ensemble de lignes sur conditions
  • mutate() : crée de nouvelles colonnes en utilisant les informations d’autres colonnes
  • group_by() et summarise() : créent des statistiques récapitulatives sur des données groupées
  • arrange() : trier les résultats
  • count() : compte les valeurs discrètes

Sélection de colonnes et filtrage de lignes


Pour sélectionner les colonnes d’un bloc de données, utilisez select(). Le premier argument de cette fonction est la trame de données (rna), et les arguments suivants sont les colonnes à conserver.

R

select(rna, gene, sample, tissue, expression)

SORTIE

# A tibble: 32,428 × 4
   gene    sample     tissue     expression
   <chr>   <chr>      <chr>           <dbl>
 1 Asl     GSM2545336 Cerebellum       1170
 2 Apod    GSM2545336 Cerebellum      36194
 3 Cyp2d22 GSM2545336 Cerebellum       4060
 4 Klk6    GSM2545336 Cerebellum        287
 5 Fcrls   GSM2545336 Cerebellum         85
 6 Slc2a4  GSM2545336 Cerebellum        782
 7 Exd2    GSM2545336 Cerebellum       1619
 8 Gjc2    GSM2545336 Cerebellum        288
 9 Plp1    GSM2545336 Cerebellum      43217
10 Gnb4    GSM2545336 Cerebellum       1071
# ℹ 32,418 more rows

Pour sélectionner toutes les colonnes sauf certaines, mettez un “-” devant la variable pour l’exclure.

R

select(rna, -tissue, -organism)

SORTIE

# A tibble: 32,428 × 17
   gene    sample   expression   age sex   infection strain  time mouse ENTREZID
   <chr>   <chr>         <dbl> <dbl> <chr> <chr>     <chr>  <dbl> <dbl>    <dbl>
 1 Asl     GSM2545…       1170     8 Fema… Influenz… C57BL…     8    14   109900
 2 Apod    GSM2545…      36194     8 Fema… Influenz… C57BL…     8    14    11815
 3 Cyp2d22 GSM2545…       4060     8 Fema… Influenz… C57BL…     8    14    56448
 4 Klk6    GSM2545…        287     8 Fema… Influenz… C57BL…     8    14    19144
 5 Fcrls   GSM2545…         85     8 Fema… Influenz… C57BL…     8    14    80891
 6 Slc2a4  GSM2545…        782     8 Fema… Influenz… C57BL…     8    14    20528
 7 Exd2    GSM2545…       1619     8 Fema… Influenz… C57BL…     8    14    97827
 8 Gjc2    GSM2545…        288     8 Fema… Influenz… C57BL…     8    14   118454
 9 Plp1    GSM2545…      43217     8 Fema… Influenz… C57BL…     8    14    18823
10 Gnb4    GSM2545…       1071     8 Fema… Influenz… C57BL…     8    14    14696
# ℹ 32,418 more rows
# ℹ 7 more variables: product <chr>, ensembl_gene_id <chr>,
#   external_synonym <chr>, chromosome_name <chr>, gene_biotype <chr>,
#   phenotype_description <chr>, hsapiens_homolog_associated_gene_name <chr>

Cela sélectionnera toutes les variables de rna sauf tissu et organism.

Pour choisir des lignes en fonction d’un critère spécifique, utilisez filter() :

R

filter(rna, sex == "Male")

SORTIE

# A tibble: 14,740 × 19
   gene    sample  expression organism   age sex   infection strain  time tissue
   <chr>   <chr>        <dbl> <chr>    <dbl> <chr> <chr>     <chr>  <dbl> <chr>
 1 Asl     GSM254…        626 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 2 Apod    GSM254…      13021 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 3 Cyp2d22 GSM254…       2171 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 4 Klk6    GSM254…        448 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 5 Fcrls   GSM254…        180 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 6 Slc2a4  GSM254…        313 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 7 Exd2    GSM254…       2366 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 8 Gjc2    GSM254…        310 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 9 Plp1    GSM254…      53126 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
10 Gnb4    GSM254…       1355 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
# ℹ 14,730 more rows
# ℹ 9 more variables: mouse <dbl>, ENTREZID <dbl>, product <chr>,
#   ensembl_gene_id <chr>, external_synonym <chr>, chromosome_name <chr>,
#   gene_biotype <chr>, phenotype_description <chr>,
#   hsapiens_homolog_associated_gene_name <chr>

R

filter(rna, sex == "Male" & infection == "NonInfected")

SORTIE

# A tibble: 4,422 × 19
   gene    sample  expression organism   age sex   infection strain  time tissue
   <chr>   <chr>        <dbl> <chr>    <dbl> <chr> <chr>     <chr>  <dbl> <chr>
 1 Asl     GSM254…        535 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 2 Apod    GSM254…      13668 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 3 Cyp2d22 GSM254…       2008 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 4 Klk6    GSM254…       1101 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 5 Fcrls   GSM254…        375 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 6 Slc2a4  GSM254…        249 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 7 Exd2    GSM254…       3126 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 8 Gjc2    GSM254…        791 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 9 Plp1    GSM254…      98658 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
10 Gnb4    GSM254…       2437 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
# ℹ 4,412 more rows
# ℹ 9 more variables: mouse <dbl>, ENTREZID <dbl>, product <chr>,
#   ensembl_gene_id <chr>, external_synonym <chr>, chromosome_name <chr>,
#   gene_biotype <chr>, phenotype_description <chr>,
#   hsapiens_homolog_associated_gene_name <chr>

Imaginons maintenant que nous nous intéressions aux homologues humains des gènes de souris analysés dans cet ensemble de données. Ces informations se trouvent dans la dernière colonne du tibble rna, nommée hsapiens_homolog_associated_gene_name. Pour le visualiser facilement, nous allons créer un nouveau tableau contenant uniquement les 2 colonnes gene et hsapiens_homolog_associated_gene_name.

R

genes <- select(rna, gene, hsapiens_homolog_associated_gene_name)
genes

SORTIE

# A tibble: 32,428 × 2
   gene    hsapiens_homolog_associated_gene_name
   <chr>   <chr>
 1 Asl     ASL
 2 Apod    APOD
 3 Cyp2d22 CYP2D6
 4 Klk6    KLK6
 5 Fcrls   FCRL2
 6 Slc2a4  SLC2A4
 7 Exd2    EXD2
 8 Gjc2    GJC2
 9 Plp1    PLP1
10 Gnb4    GNB4
# ℹ 32,418 more rows

Certains gènes de souris n’ont pas d’homologues humains. Ceux-ci peuvent être récupérés en utilisant filter() et la fonction is.na(), qui détermine si quelque chose est un NA.

R

filter(genes, is.na(hsapiens_homolog_associated_gene_name))

SORTIE

# A tibble: 4,290 × 2
   gene     hsapiens_homolog_associated_gene_name
   <chr>    <chr>
 1 Prodh    <NA>
 2 Tssk5    <NA>
 3 Vmn2r1   <NA>
 4 Gm10654  <NA>
 5 Hexa     <NA>
 6 Sult1a1  <NA>
 7 Gm6277   <NA>
 8 Tmem198b <NA>
 9 Adam1a   <NA>
10 Ebp      <NA>
# ℹ 4,280 more rows

Si on veut conserver uniquement les gènes de souris qui ont un homologue humain, on peut insérer un “!” symbole qui annule le résultat, nous demandons donc chaque ligne où hsapiens_homolog_associated_gene_name n’est pas un NA.

R

filter(genes, !is.na(hsapiens_homolog_associated_gene_name))

SORTIE

# A tibble: 28,138 × 2
   gene    hsapiens_homolog_associated_gene_name
   <chr>   <chr>
 1 Asl     ASL
 2 Apod    APOD
 3 Cyp2d22 CYP2D6
 4 Klk6    KLK6
 5 Fcrls   FCRL2
 6 Slc2a4  SLC2A4
 7 Exd2    EXD2
 8 Gjc2    GJC2
 9 Plp1    PLP1
10 Gnb4    GNB4
# ℹ 28,128 more rows

Tuyaux


Et si vous souhaitez sélectionner et filtrer en même temps ? Il existe trois façons de procéder : utiliser des étapes intermédiaires, des fonctions imbriquées ou des tuyaux.

Avec des étapes intermédiaires, vous créez un bloc de données temporaire et l’utilisez comme entrée de la fonction suivante, comme ceci :

R

rna2 <- filter(rna, sex == "Male")
rna3 <- select(rna2, gene, sample, tissue, expression)
rna3

SORTIE

# A tibble: 14,740 × 4
   gene    sample     tissue     expression
   <chr>   <chr>      <chr>           <dbl>
 1 Asl     GSM2545340 Cerebellum        626
 2 Apod    GSM2545340 Cerebellum      13021
 3 Cyp2d22 GSM2545340 Cerebellum       2171
 4 Klk6    GSM2545340 Cerebellum        448
 5 Fcrls   GSM2545340 Cerebellum        180
 6 Slc2a4  GSM2545340 Cerebellum        313
 7 Exd2    GSM2545340 Cerebellum       2366
 8 Gjc2    GSM2545340 Cerebellum        310
 9 Plp1    GSM2545340 Cerebellum      53126
10 Gnb4    GSM2545340 Cerebellum       1355
# ℹ 14,730 more rows

Ceci est lisible, mais peut encombrer votre espace de travail avec de nombreux objets intermédiaires que vous devez nommer individuellement. Avec plusieurs étapes , cela peut être difficile à suivre.

Vous pouvez également imbriquer des fonctions (c’est-à-dire une fonction dans une autre), comme ceci :

R

rna3 <- select(filter(rna, sex == "Male"), gene, sample, tissue, expression)
rna3

SORTIE

# A tibble: 14,740 × 4
   gene    sample     tissue     expression
   <chr>   <chr>      <chr>           <dbl>
 1 Asl     GSM2545340 Cerebellum        626
 2 Apod    GSM2545340 Cerebellum      13021
 3 Cyp2d22 GSM2545340 Cerebellum       2171
 4 Klk6    GSM2545340 Cerebellum        448
 5 Fcrls   GSM2545340 Cerebellum        180
 6 Slc2a4  GSM2545340 Cerebellum        313
 7 Exd2    GSM2545340 Cerebellum       2366
 8 Gjc2    GSM2545340 Cerebellum        310
 9 Plp1    GSM2545340 Cerebellum      53126
10 Gnb4    GSM2545340 Cerebellum       1355
# ℹ 14,730 more rows

C’est pratique, mais peut être difficile à lire si trop de fonctions sont imbriquées, car R évalue l’expression de l’intérieur vers l’extérieur (dans ce cas, filtrer, puis sélectionner).

La dernière option, pipes, est un ajout récent à R. Pipes vous permet de prendre la sortie d’une fonction et de l’envoyer directement à la suivante, ce qui est utile lorsque vous devez faire beaucoup de choses dans le même ensemble de données.

Les tuyaux dans R ressemblent à %>% (mis à disposition via le package magrittr ) ou |> (via la base R). If you use RStudio, you can type the pipe with Ctrl + Shift + M if you have a PC or Cmd + Shift + M if you have a Mac.

Dans le code ci-dessus, nous utilisons le tube pour envoyer l’ensemble de données rna d’abord via filter() pour conserver les lignes où sex est Homme, puis via select() pour conserver uniquement les colonnes gène, échantillon, tissu et expression.

Le tube %>% prend l’objet à sa gauche et le passe directement comme le premier argument de la fonction à sa droite, nous n’avons pas besoin de inclure explicitement le bloc de données comme un argument pour les fonctions filter() et select().

R

rna %>%
  filter(sex == "Male") %>%
  select(gene, sample, tissue, expression)

SORTIE

# A tibble: 14,740 × 4
   gene    sample     tissue     expression
   <chr>   <chr>      <chr>           <dbl>
 1 Asl     GSM2545340 Cerebellum        626
 2 Apod    GSM2545340 Cerebellum      13021
 3 Cyp2d22 GSM2545340 Cerebellum       2171
 4 Klk6    GSM2545340 Cerebellum        448
 5 Fcrls   GSM2545340 Cerebellum        180
 6 Slc2a4  GSM2545340 Cerebellum        313
 7 Exd2    GSM2545340 Cerebellum       2366
 8 Gjc2    GSM2545340 Cerebellum        310
 9 Plp1    GSM2545340 Cerebellum      53126
10 Gnb4    GSM2545340 Cerebellum       1355
# ℹ 14,730 more rows

Certains trouveront peut-être utile de lire le tube comme le mot « alors ». Par exemple, dans l’exemple ci-dessus, nous avons pris la trame de données rna, puis nous avons filtré pour les lignes avec sex == "Male", puis nous avons « sélectionné les colonnes « gène », « échantillon », « tissu » et « expression ».

Les fonctions dplyr en elles-mêmes sont quelque peu simples, mais en les combinant dans des flux de travail linéaires avec le tube, nous pouvons accomplir des manipulations plus complexes de trames de données.

Si nous voulons créer un nouvel objet avec cette version plus petite des données, nous pouvons lui attribuer un nouveau nom :

R

rna3 <- rna %>%
  filter(sex == "Male") %>%
  select(gene, sample, tissue, expression)

rna3

SORTIE

# A tibble: 14,740 × 4
   gene    sample     tissue     expression
   <chr>   <chr>      <chr>           <dbl>
 1 Asl     GSM2545340 Cerebellum        626
 2 Apod    GSM2545340 Cerebellum      13021
 3 Cyp2d22 GSM2545340 Cerebellum       2171
 4 Klk6    GSM2545340 Cerebellum        448
 5 Fcrls   GSM2545340 Cerebellum        180
 6 Slc2a4  GSM2545340 Cerebellum        313
 7 Exd2    GSM2545340 Cerebellum       2366
 8 Gjc2    GSM2545340 Cerebellum        310
 9 Plp1    GSM2545340 Cerebellum      53126
10 Gnb4    GSM2545340 Cerebellum       1355
# ℹ 14,730 more rows

Défi:

À l’aide de tuyaux, sous-ensemblez les données rna pour conserver les observations chez les souris femelles au temps 0, où le gène a une expression supérieure à 50 000, et ne conservez que les colonnes gene, sample, time, expression et age.

R

rna %>%
  filter(expression > 50000,
         sex == "Female",
         time == 0 ) %>%
  select(gene, sample, time, expression, age)

SORTIE

# A tibble: 9 × 5
  gene   sample      time expression   age
  <chr>  <chr>      <dbl>      <dbl> <dbl>
1 Plp1   GSM2545337     0     101241     8
2 Atp1b1 GSM2545337     0      53260     8
3 Plp1   GSM2545338     0      96534     8
4 Atp1b1 GSM2545338     0      50614     8
5 Plp1   GSM2545348     0     102790     8
6 Atp1b1 GSM2545348     0      59544     8
7 Plp1   GSM2545353     0      71237     8
8 Glul   GSM2545353     0      52451     8
9 Atp1b1 GSM2545353     0      61451     8

Subir une mutation


Vous souhaiterez fréquemment créer de nouvelles colonnes basées sur les valeurs des colonnes existantes, par exemple pour effectuer des conversions d’unités ou pour trouver le rapport des valeurs dans deux colonnes . Pour cela, nous utiliserons mutate().

Pour créer une nouvelle colonne de temps en heures :

R

rna %>%
  mutate(time_hours = time * 24) %>%
  select(time, time_hours)

SORTIE

# A tibble: 32,428 × 2
    time time_hours
   <dbl>      <dbl>
 1     8        192
 2     8        192
 3     8        192
 4     8        192
 5     8        192
 6     8        192
 7     8        192
 8     8        192
 9     8        192
10     8        192
# ℹ 32,418 more rows

Vous pouvez également créer une deuxième nouvelle colonne basée sur la première nouvelle colonne dans le même appel de mutate() :

R

rna %>%
  mutate(time_hours = time * 24,
         time_mn = time_hours * 60) %>%
  select(time, time_hours, time_mn)

SORTIE

# A tibble: 32,428 × 3
    time time_hours time_mn
   <dbl>      <dbl>   <dbl>
 1     8        192   11520
 2     8        192   11520
 3     8        192   11520
 4     8        192   11520
 5     8        192   11520
 6     8        192   11520
 7     8        192   11520
 8     8        192   11520
 9     8        192   11520
10     8        192   11520
# ℹ 32,418 more rows

Défi

Créez un nouveau bloc de données à partir des données rna qui répond aux critères suivants : contient uniquement le gène, le nom_chromosome, phenotype_description, sample et expression Colonnes. Les valeurs de l’expression doivent être transformées en log. Cette trame de données doit contenir uniquement des gènes situés sur les chromosomes sexuels, associés à un phénotype _description, et avec une expression log supérieure à 5.

Astuce : réfléchissez à la façon dont les commandes doivent être ordonnées pour produire ce bloc de données !

R

rna %>%
  mutate(expression = log(expression)) %>%
  select(gene, chromosome_name, phenotype_description, sample, expression) %>%
  filter(chromosome_name == "X" | chromosome_name == "Y") %>%
  filter(!is.na(phenotype_description)) %>%
  filter(expression > 5)

SORTIE

# A tibble: 649 × 5
   gene   chromosome_name phenotype_description                sample expression
   <chr>  <chr>           <chr>                                <chr>       <dbl>
 1 Plp1   X               abnormal CNS glial cell morphology   GSM25…      10.7
 2 Slc7a3 X               decreased body length                GSM25…       5.46
 3 Plxnb3 X               abnormal coat appearance             GSM25…       6.58
 4 Rbm3   X               abnormal liver morphology            GSM25…       9.32
 5 Cfp    X               abnormal cardiovascular system phys… GSM25…       6.18
 6 Ebp    X               abnormal embryonic erythrocyte morp… GSM25…       6.68
 7 Cd99l2 X               abnormal cellular extravasation      GSM25…       8.04
 8 Piga   X               abnormal brain development           GSM25…       6.06
 9 Pim2   X               decreased T cell proliferation       GSM25…       7.11
10 Itm2a  X               no abnormal phenotype detected       GSM25…       7.48
# ℹ 639 more rows

Analyse de données fractionnée-appliquée-combinée


De nombreuses tâches d’analyse de données peuvent être abordées à l’aide du paradigme split-apply-combine : divisez les données en groupes, appliquez une analyse à chaque groupe, puis combinez les résultats. dplyr rend cela très facile grâce à l’utilisation de la fonction group_by().

R

rna %>%
  group_by(gene)

SORTIE

# A tibble: 32,428 × 19
# Groups:   gene [1,474]
   gene    sample  expression organism   age sex   infection strain  time tissue
   <chr>   <chr>        <dbl> <chr>    <dbl> <chr> <chr>     <chr>  <dbl> <chr>
 1 Asl     GSM254…       1170 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 2 Apod    GSM254…      36194 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 3 Cyp2d22 GSM254…       4060 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 4 Klk6    GSM254…        287 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 5 Fcrls   GSM254…         85 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 6 Slc2a4  GSM254…        782 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 7 Exd2    GSM254…       1619 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 8 Gjc2    GSM254…        288 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 9 Plp1    GSM254…      43217 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
10 Gnb4    GSM254…       1071 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
# ℹ 32,418 more rows
# ℹ 9 more variables: mouse <dbl>, ENTREZID <dbl>, product <chr>,
#   ensembl_gene_id <chr>, external_synonym <chr>, chromosome_name <chr>,
#   gene_biotype <chr>, phenotype_description <chr>,
#   hsapiens_homolog_associated_gene_name <chr>

La fonction group_by() n’effectue aucun traitement de données, elle regroupe les données en sous-ensembles : dans l’exemple ci-dessus, notre tibble initial de 32428 les observations sont divisées en 1474 en fonction de la variable gene.

On pourrait de même décider de regrouper les tibbles par échantillons :

R

rna %>%
  group_by(sample)

SORTIE

# A tibble: 32,428 × 19
# Groups:   sample [22]
   gene    sample  expression organism   age sex   infection strain  time tissue
   <chr>   <chr>        <dbl> <chr>    <dbl> <chr> <chr>     <chr>  <dbl> <chr>
 1 Asl     GSM254…       1170 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 2 Apod    GSM254…      36194 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 3 Cyp2d22 GSM254…       4060 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 4 Klk6    GSM254…        287 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 5 Fcrls   GSM254…         85 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 6 Slc2a4  GSM254…        782 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 7 Exd2    GSM254…       1619 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 8 Gjc2    GSM254…        288 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 9 Plp1    GSM254…      43217 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
10 Gnb4    GSM254…       1071 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
# ℹ 32,418 more rows
# ℹ 9 more variables: mouse <dbl>, ENTREZID <dbl>, product <chr>,
#   ensembl_gene_id <chr>, external_synonym <chr>, chromosome_name <chr>,
#   gene_biotype <chr>, phenotype_description <chr>,
#   hsapiens_homolog_associated_gene_name <chr>

Ici, notre tibble initial d’observations 32428 est divisé en groupes 22 en fonction de la variable sample.

Une fois les données regroupées, les opérations suivantes seront appliquées sur chaque groupe indépendamment.

La fonction summaris()

group_by() est souvent utilisé avec summarise(), qui réduit chaque groupe en un résumé sur une seule ligne de ce groupe.

group_by() prend comme arguments les noms de colonnes qui contiennent les variables catégorielles pour lesquelles vous souhaitez calculer les statistiques récapitulatives . Donc, pour calculer l’expression moyenne par gène :

R

rna %>%
  group_by(gene) %>%
  summarise(mean_expression = mean(expression))

SORTIE

# A tibble: 1,474 × 2
   gene     mean_expression
   <chr>              <dbl>
 1 AI504432         1053.
 2 AW046200          131.
 3 AW551984          295.
 4 Aamp             4751.
 5 Abca12              4.55
 6 Abcc8            2498.
 7 Abhd14a           525.
 8 Abi2             4909.
 9 Abi3bp           1002.
10 Abl2             2124.
# ℹ 1,464 more rows

Nous pourrions également vouloir calculer les niveaux d’expression moyens de tous les gènes dans chaque échantillon :

R

rna %>%
  group_by(sample) %>%
  summarise(mean_expression = mean(expression))

SORTIE

# A tibble: 22 × 2
   sample     mean_expression
   <chr>                <dbl>
 1 GSM2545336           2062.
 2 GSM2545337           1766.
 3 GSM2545338           1668.
 4 GSM2545339           1696.
 5 GSM2545340           1682.
 6 GSM2545341           1638.
 7 GSM2545342           1594.
 8 GSM2545343           2107.
 9 GSM2545344           1712.
10 GSM2545345           1700.
# ℹ 12 more rows

Mais on peut aussi regrouper par plusieurs colonnes :

R

rna %>%
  group_by(gene, infection, time) %>%
  summarise(mean_expression = mean(expression))

SORTIE

`summarise()` has grouped output by 'gene', 'infection'. You can override using
the `.groups` argument.

SORTIE

# A tibble: 4,422 × 4
# Groups:   gene, infection [2,948]
   gene     infection    time mean_expression
   <chr>    <chr>       <dbl>           <dbl>
 1 AI504432 InfluenzaA      4           1104.
 2 AI504432 InfluenzaA      8           1014
 3 AI504432 NonInfected     0           1034.
 4 AW046200 InfluenzaA      4            152.
 5 AW046200 InfluenzaA      8             81
 6 AW046200 NonInfected     0            155.
 7 AW551984 InfluenzaA      4            302.
 8 AW551984 InfluenzaA      8            342.
 9 AW551984 NonInfected     0            238
10 Aamp     InfluenzaA      4           4870
# ℹ 4,412 more rows

Une fois les données regroupées, vous pouvez également résumer plusieurs variables en même temps (et pas nécessairement sur la même variable). Par exemple, nous pourrions ajouter une colonne indiquant l’expression médiane par gène et par condition :

R

rna %>%
  group_by(gene, infection, time) %>%
  summarise(mean_expression = mean(expression),
            median_expression = median(expression))

SORTIE

`summarise()` has grouped output by 'gene', 'infection'. You can override using
the `.groups` argument.

SORTIE

# A tibble: 4,422 × 5
# Groups:   gene, infection [2,948]
   gene     infection    time mean_expression median_expression
   <chr>    <chr>       <dbl>           <dbl>             <dbl>
 1 AI504432 InfluenzaA      4           1104.             1094.
 2 AI504432 InfluenzaA      8           1014               985
 3 AI504432 NonInfected     0           1034.             1016
 4 AW046200 InfluenzaA      4            152.              144.
 5 AW046200 InfluenzaA      8             81                82
 6 AW046200 NonInfected     0            155.              163
 7 AW551984 InfluenzaA      4            302.              245
 8 AW551984 InfluenzaA      8            342.              287
 9 AW551984 NonInfected     0            238               265
10 Aamp     InfluenzaA      4           4870              4708
# ℹ 4,412 more rows

Défi

Calculer le niveau d’expression moyen du gène « Dok3 » par points temporels.

R

rna %>%
  filter(gene == "Dok3") %>%
  group_by(time) %>%
  summarise(mean = mean(expression))

SORTIE

# A tibble: 3 × 2
   time  mean
  <dbl> <dbl>
1     0  169
2     4  156.
3     8   61 

Compte

Lorsque nous travaillons avec des données, nous souhaitons souvent connaître le nombre d’observations trouvées pour chaque facteur ou combinaison de facteurs. Pour cette tâche, dplyr fournit count(). Par exemple, si nous voulions compter le nombre de lignes de données pour chaque échantillon infecté et non infecté, nous ferions :

R

rna %>%
    count(infection)

SORTIE

# A tibble: 2 × 2
  infection       n
  <chr>       <int>
1 InfluenzaA  22110
2 NonInfected 10318

La fonction count() est un raccourci pour quelque chose que nous avons déjà vu : regrouper par une variable et le résumer en comptant le nombre d’observations dans ce groupe. En d’autres termes, « rna %>% count(infection) » équivaut à :

R

rna %>%
    group_by(infection) %>%
    summarise(n = n())

SORTIE

# A tibble: 2 × 2
  infection       n
  <chr>       <int>
1 InfluenzaA  22110
2 NonInfected 10318

L’exemple précédent montre l’utilisation de count() pour compter le nombre de lignes/observations pour un facteur (c’est-à-dire infection). Si nous voulions compter une combinaison de facteurs, telle que infection et time, nous spécifierions le premier et le deuxième facteur comme arguments de count() :

R

rna %>%
    count(infection, time)

SORTIE

# A tibble: 3 × 3
  infection    time     n
  <chr>       <dbl> <int>
1 InfluenzaA      4 11792
2 InfluenzaA      8 10318
3 NonInfected     0 10318

ce qui équivaut à ceci :

R

rna %>%
  group_by(infection, time) %>%
  summarise(n = n())

SORTIE

`summarise()` has grouped output by 'infection'. You can override using the
`.groups` argument.

SORTIE

# A tibble: 3 × 3
# Groups:   infection [2]
  infection    time     n
  <chr>       <dbl> <int>
1 InfluenzaA      4 11792
2 InfluenzaA      8 10318
3 NonInfected     0 10318

Il est parfois utile de trier le résultat pour faciliter les comparaisons. Nous pouvons utiliser arrange() pour trier le tableau. Par exemple, nous pourrions vouloir organiser le tableau ci-dessus par heure :

R

rna %>%
  count(infection, time) %>%
  arrange(time)

SORTIE

# A tibble: 3 × 3
  infection    time     n
  <chr>       <dbl> <int>
1 NonInfected     0 10318
2 InfluenzaA      4 11792
3 InfluenzaA      8 10318

ou par comptages :

R

rna %>%
  count(infection, time) %>%
  arrange(n)

SORTIE

# A tibble: 3 × 3
  infection    time     n
  <chr>       <dbl> <int>
1 InfluenzaA      8 10318
2 NonInfected     0 10318
3 InfluenzaA      4 11792

Pour trier par ordre décroissant, nous devons ajouter la fonction desc() :

R

rna %>%
  count(infection, time) %>%
  arrange(desc(n))

SORTIE

# A tibble: 3 × 3
  infection    time     n
  <chr>       <dbl> <int>
1 InfluenzaA      4 11792
2 InfluenzaA      8 10318
3 NonInfected     0 10318

Défi

  1. Combien de gènes ont été analysés dans chaque échantillon ?
  2. Utilisez group_by() et summarise() pour évaluer la profondeur de séquençage (la somme de tous les comptes) dans chaque échantillon. Quel échantillon a la profondeur de séquençage la plus élevée ?
  3. Choisissez un échantillon et évaluez le nombre de gènes par biotype.
  4. Identifiez les gènes associés à la description du phénotype « méthylation anormale de l’ADN » et calculez leur expression moyenne (en log) au temps 0, au temps 4 et au temps 8.

R

## 1.
rna %>%
  count(sample)

SORTIE

# A tibble: 22 × 2
   sample         n
   <chr>      <int>
 1 GSM2545336  1474
 2 GSM2545337  1474
 3 GSM2545338  1474
 4 GSM2545339  1474
 5 GSM2545340  1474
 6 GSM2545341  1474
 7 GSM2545342  1474
 8 GSM2545343  1474
 9 GSM2545344  1474
10 GSM2545345  1474
# ℹ 12 more rows

R

## 2.
rna %>%
  group_by(sample) %>%
  summarise(seq_depth = sum(expression)) %>%
  arrange(desc(seq_depth))

SORTIE

# A tibble: 22 × 2
   sample     seq_depth
   <chr>          <dbl>
 1 GSM2545350   3255566
 2 GSM2545352   3216163
 3 GSM2545343   3105652
 4 GSM2545336   3039671
 5 GSM2545380   3036098
 6 GSM2545353   2953249
 7 GSM2545348   2913678
 8 GSM2545362   2913517
 9 GSM2545351   2782464
10 GSM2545349   2758006
# ℹ 12 more rows

R

## 3.
rna %>%
  filter(sample == "GSM2545336") %>%
  count(gene_biotype) %>%
  arrange(desc(n))

SORTIE

# A tibble: 13 × 2
   gene_biotype                           n
   <chr>                              <int>
 1 protein_coding                      1321
 2 lncRNA                                69
 3 processed_pseudogene                  59
 4 miRNA                                  7
 5 snoRNA                                 5
 6 TEC                                    4
 7 polymorphic_pseudogene                 2
 8 unprocessed_pseudogene                 2
 9 IG_C_gene                              1
10 scaRNA                                 1
11 transcribed_processed_pseudogene       1
12 transcribed_unitary_pseudogene         1
13 transcribed_unprocessed_pseudogene     1

R

## 4.
rna %>%
  filter(phenotype_description == "abnormal DNA methylation") %>%
  group_by(gene, time) %>%
  summarise(mean_expression = mean(log(expression))) %>%
  arrange()

SORTIE

`summarise()` has grouped output by 'gene'. You can override using the
`.groups` argument.

SORTIE

# A tibble: 6 × 3
# Groups:   gene [2]
  gene   time mean_expression
  <chr> <dbl>           <dbl>
1 Xist      0            6.95
2 Xist      4            6.34
3 Xist      8            7.13
4 Zdbf2     0            6.27
5 Zdbf2     4            6.27
6 Zdbf2     8            6.19

Remodeler les données


Dans le tibble rna, les lignes contiennent des valeurs d’expression (l’unité) qui sont associées à une combinaison de 2 autres variables : gene et sample.

Toutes les autres colonnes correspondent à des variables décrivant soit l’échantillon (organisme, âge, sexe, …) soit le gène (gène_biotype, ENTREZ_ID, produit, …). Les variables qui ne changent pas avec les gènes ou avec les échantillons auront la même valeur dans toutes les lignes.

R

rna %>%
  arrange(gene)

SORTIE

# A tibble: 32,428 × 19
   gene     sample expression organism   age sex   infection strain  time tissue
   <chr>    <chr>       <dbl> <chr>    <dbl> <chr> <chr>     <chr>  <dbl> <chr>
 1 AI504432 GSM25…       1230 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 2 AI504432 GSM25…       1085 Mus mus…     8 Fema… NonInfec… C57BL…     0 Cereb…
 3 AI504432 GSM25…        969 Mus mus…     8 Fema… NonInfec… C57BL…     0 Cereb…
 4 AI504432 GSM25…       1284 Mus mus…     8 Fema… Influenz… C57BL…     4 Cereb…
 5 AI504432 GSM25…        966 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 6 AI504432 GSM25…        918 Mus mus…     8 Male  Influenz… C57BL…     8 Cereb…
 7 AI504432 GSM25…        985 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 8 AI504432 GSM25…        972 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 9 AI504432 GSM25…       1000 Mus mus…     8 Fema… Influenz… C57BL…     4 Cereb…
10 AI504432 GSM25…        816 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
# ℹ 32,418 more rows
# ℹ 9 more variables: mouse <dbl>, ENTREZID <dbl>, product <chr>,
#   ensembl_gene_id <chr>, external_synonym <chr>, chromosome_name <chr>,
#   gene_biotype <chr>, phenotype_description <chr>,
#   hsapiens_homolog_associated_gene_name <chr>

Cette structure est appelée « format long », car une colonne contient toutes les valeurs, et d’autres colonnes répertorient le contexte de la valeur.

Dans certains cas, le « format long » n’est pas vraiment « lisible par l’homme », et un autre format, un « format large » est préféré, comme manière plus compacte de représenter les données. This is typically the case with gene expression values that scientists are used to look as matrices, were rows represent genes and columns represent samples.

Dans ce format, il deviendrait donc simple d’explorer la relation entre les niveaux d’expression génique au sein et entre les échantillons.

SORTIE

# A tibble: 1,474 × 23
   gene    GSM2545336 GSM2545337 GSM2545338 GSM2545339 GSM2545340 GSM2545341
   <chr>        <dbl>      <dbl>      <dbl>      <dbl>      <dbl>      <dbl>
 1 Asl           1170        361        400        586        626        988
 2 Apod         36194      10347       9173      10620      13021      29594
 3 Cyp2d22       4060       1616       1603       1901       2171       3349
 4 Klk6           287        629        641        578        448        195
 5 Fcrls           85        233        244        237        180         38
 6 Slc2a4         782        231        248        265        313        786
 7 Exd2          1619       2288       2235       2513       2366       1359
 8 Gjc2           288        595        568        551        310        146
 9 Plp1         43217     101241      96534      58354      53126      27173
10 Gnb4          1071       1791       1867       1430       1355        798
# ℹ 1,464 more rows
# ℹ 16 more variables: GSM2545342 <dbl>, GSM2545343 <dbl>, GSM2545344 <dbl>,
#   GSM2545345 <dbl>, GSM2545346 <dbl>, GSM2545347 <dbl>, GSM2545348 <dbl>,
#   GSM2545349 <dbl>, GSM2545350 <dbl>, GSM2545351 <dbl>, GSM2545352 <dbl>,
#   GSM2545353 <dbl>, GSM2545354 <dbl>, GSM2545362 <dbl>, GSM2545363 <dbl>,
#   GSM2545380 <dbl>

Pour convertir les valeurs d’expression génique de rna en un format large, nous devons créer une nouvelle table où les valeurs de la colonne sample deviendraient les noms des variables de colonne.

The key point here is that we are still following a tidy data structure, but we have reshaped the data according to the observations of interest: expression levels per gene instead of recording them per gene and per sample.

La transformation inverse serait de transformer les noms de colonnes en valeurs d’une nouvelle variable.

Nous pouvons effectuer ces deux transformations avec deux fonctions tidyr, pivot_longer() et pivot_wider() (voir ici pour détails).

Pivoter les données dans un format plus large

Sélectionnons les 3 premières colonnes de rna et utilisons pivot_wider() pour transformer les données en grand format.

R

rna_exp <- rna %>%
  select(gene, sample, expression)
rna_exp

SORTIE

# A tibble: 32,428 × 3
   gene    sample     expression
   <chr>   <chr>           <dbl>
 1 Asl     GSM2545336       1170
 2 Apod    GSM2545336      36194
 3 Cyp2d22 GSM2545336       4060
 4 Klk6    GSM2545336        287
 5 Fcrls   GSM2545336         85
 6 Slc2a4  GSM2545336        782
 7 Exd2    GSM2545336       1619
 8 Gjc2    GSM2545336        288
 9 Plp1    GSM2545336      43217
10 Gnb4    GSM2545336       1071
# ℹ 32,418 more rows

pivot_wider prend trois arguments principaux :

  1. les données à transformer ;
  2. le names_from : la colonne dont les valeurs deviendront de nouveaux noms de colonne  ;
  3. les values_from : la colonne dont les valeurs rempliront les nouvelles colonnes .
Grand pivot des données `rna`.
Grand pivot des données rna.

R

rna_wide <- rna_exp %>%
  pivot_wider(names_from = sample,
              values_from = expression)
rna_wide

SORTIE

# A tibble: 1,474 × 23
   gene    GSM2545336 GSM2545337 GSM2545338 GSM2545339 GSM2545340 GSM2545341
   <chr>        <dbl>      <dbl>      <dbl>      <dbl>      <dbl>      <dbl>
 1 Asl           1170        361        400        586        626        988
 2 Apod         36194      10347       9173      10620      13021      29594
 3 Cyp2d22       4060       1616       1603       1901       2171       3349
 4 Klk6           287        629        641        578        448        195
 5 Fcrls           85        233        244        237        180         38
 6 Slc2a4         782        231        248        265        313        786
 7 Exd2          1619       2288       2235       2513       2366       1359
 8 Gjc2           288        595        568        551        310        146
 9 Plp1         43217     101241      96534      58354      53126      27173
10 Gnb4          1071       1791       1867       1430       1355        798
# ℹ 1,464 more rows
# ℹ 16 more variables: GSM2545342 <dbl>, GSM2545343 <dbl>, GSM2545344 <dbl>,
#   GSM2545345 <dbl>, GSM2545346 <dbl>, GSM2545347 <dbl>, GSM2545348 <dbl>,
#   GSM2545349 <dbl>, GSM2545350 <dbl>, GSM2545351 <dbl>, GSM2545352 <dbl>,
#   GSM2545353 <dbl>, GSM2545354 <dbl>, GSM2545362 <dbl>, GSM2545363 <dbl>,
#   GSM2545380 <dbl>

Notez que par défaut, la fonction pivot_wider() ajoutera NA pour les valeurs manquantes.

Imaginons que, pour une raison quelconque, nous ayons des valeurs d’expression manquantes pour certains gènes dans certains échantillons. In the following fictive example, the gene Cyp2d22 has only one expression value, in GSM2545338 sample.

R

rna_with_missing_values <- rna %>%
  select(gene, sample, expression) %>%
  filter(gene %in% c("Asl", "Apod", "Cyp2d22")) %>%
  filter(sample %in% c("GSM2545336", "GSM2545337", "GSM2545338")) %>%
  arrange(sample) %>%
  filter(!(gene == "Cyp2d22" & sample != "GSM2545338"))
rna_with_missing_values

SORTIE

# A tibble: 7 × 3
  gene    sample     expression
  <chr>   <chr>           <dbl>
1 Asl     GSM2545336       1170
2 Apod    GSM2545336      36194
3 Asl     GSM2545337        361
4 Apod    GSM2545337      10347
5 Asl     GSM2545338        400
6 Apod    GSM2545338       9173
7 Cyp2d22 GSM2545338       1603

Par défaut, la fonction pivot_wider() ajoutera NA pour les valeurs manquantes. Ceci peut être paramétré avec l’argument values_fill de la fonction pivot_wider().

R

rna_with_missing_values %>%
  pivot_wider(names_from = échantillon,
              values_from = expression)

ERREUR

Error in `pivot_wider()`:
! Can't select columns that don't exist.
✖ Column `échantillon` doesn't exist.

R

rna_with_missing_values %>%
  pivot_wider(names_from = échantillon,
              values_from = expression,
              valeurs_fill = 0)

ERREUR

Error in `pivot_wider()`:
! Can't select columns that don't exist.
✖ Column `échantillon` doesn't exist.

Pivoter les données dans un format plus long

Dans la situation inverse, nous utilisons les noms de colonnes et les transformons en une paire de nouvelles variables. Une variable représente les noms de colonnes sous forme de valeurs , et l’autre variable contient les valeurs précédemment associées aux noms de colonnes.

pivot_longer() prend quatre arguments principaux :

  1. les données à transformer ;
  2. le names_to : le nouveau nom de colonne que nous souhaitons créer et remplir avec les noms de colonnes actuels ;
  3. les values_to : le nouveau nom de colonne que nous souhaitons créer et remplir avec valeurs actuelles ;
  4. les noms des colonnes à utiliser pour renseigner les variables names_to et values_to (ou à supprimer).
Pivot long des données `rna`.
Pivot long des données rna.

To recreate rna_long from rna_wide we would create a key called sample and value called expression and use all columns except gene for the key variable. Here we drop gene column with a minus sign.

Notice how the new variable names are to be quoted here.

R

rna_long <- rna_wide %>%
    pivot_longer(names_to = "sample",
                 values_to = "expression",
                 -gene)
rna_long

SORTIE

# A tibble: 32,428 × 3
   gene  sample     expression
   <chr> <chr>           <dbl>
 1 Asl   GSM2545336       1170
 2 Asl   GSM2545337        361
 3 Asl   GSM2545338        400
 4 Asl   GSM2545339        586
 5 Asl   GSM2545340        626
 6 Asl   GSM2545341        988
 7 Asl   GSM2545342        836
 8 Asl   GSM2545343        535
 9 Asl   GSM2545344        586
10 Asl   GSM2545345        597
# ℹ 32,418 more rows

Nous aurions également pu utiliser une spécification indiquant les colonnes à inclure. Cela peut être utile si vous disposez d’un grand nombre de colonnes d’identification , et il est plus facile de spécifier ce qu’il faut rassembler que ce qu’il faut laisser seul. Ici, la fonction starts_with() peut aider à récupérer des exemples de noms sans avoir à tous les lister ! Une autre possibilité serait d’utiliser l’opérateur : !

R

rna_wide %>%
    pivot_longer(names_to = "sample",
                 values_to = "expression",
                 cols = start_with("GSM"))

ERREUR

Error in `pivot_longer()`:
ℹ In argument: `start_with("GSM")`.
Caused by error in `start_with()`:
! could not find function "start_with"

R

rna_wide %> %
    pivot_longer(names_to = "échantillon",
                 valeurs_to = "expression",
                 GSM2545336:GSM2545380)

ERREUR

Error in rna_wide %> % pivot_longer(names_to = "échantillon", valeurs_to = "expression", : could not find function "%> %"

Notez que si nous avions des valeurs manquantes dans le format large, le « NA » serait inclus dans le nouveau format long.

Souvenez-vous de notre précédent tibble fictif contenant des valeurs manquantes :

R

rna_with_missing_values

SORTIE

# A tibble: 7 × 3
  gene    sample     expression
  <chr>   <chr>           <dbl>
1 Asl     GSM2545336       1170
2 Apod    GSM2545336      36194
3 Asl     GSM2545337        361
4 Apod    GSM2545337      10347
5 Asl     GSM2545338        400
6 Apod    GSM2545338       9173
7 Cyp2d22 GSM2545338       1603

R

wide_with_NA <- rna_with_missing_values %>%
  pivot_wider(names_from = sample,
              values_from = expression)
wide_with_NA

SORTIE

# A tibble: 3 × 4
  gene    GSM2545336 GSM2545337 GSM2545338
  <chr>        <dbl>      <dbl>      <dbl>
1 Asl           1170        361        400
2 Apod         36194      10347       9173
3 Cyp2d22         NA         NA       1603

R

wide_with_NA %>%
    pivot_longer(names_to = "sample",
                 values_to = "expression",
                 -gene)

SORTIE

# A tibble: 9 × 3
  gene    sample     expression
  <chr>   <chr>           <dbl>
1 Asl     GSM2545336       1170
2 Asl     GSM2545337        361
3 Asl     GSM2545338        400
4 Apod    GSM2545336      36194
5 Apod    GSM2545337      10347
6 Apod    GSM2545338       9173
7 Cyp2d22 GSM2545336         NA
8 Cyp2d22 GSM2545337         NA
9 Cyp2d22 GSM2545338       1603

Passer à des formats plus larges et plus longs peut être un moyen utile d’équilibrer un ensemble de données afin que chaque réplique ait la même composition.

Question

A partir de la table arn, utilisez la fonction pivot_wider() pour créer un tableau grand format donnant les niveaux d’expression génique chez chaque souris. Utilisez ensuite la fonction pivot_longer() pour restaurer un tableau au format long.

R

rna1 <- rna %>%
select(gène, souris, expression) %>%
pivot_wider(names_from = souris, valeurs_from = expression)

ERREUR

Error in `select()`:
! Can't select columns that don't exist.
✖ Column `gène` doesn't exist.

R

rna1

ERREUR

Error in eval(expr, envir, enclos): object 'rna1' not found

R

rna1 %>%
pivot_longer(names_to = "mouse_id", valeurs_to = "counts", -gene)

ERREUR

Error in eval(expr, envir, enclos): object 'rna1' not found

ERREUR

Error in `pivot_longer()`:
! Arguments in `...` must be used.
✖ Problematic argument:
• valeurs_to = "counts"
ℹ Did you misspell an argument name?

Question

Sous-ensemble de gènes situés sur les chromosomes X et Y de la trame de données « rna » et répartissent la trame de données avec « sexe » en colonnes, « nom_chromosome » en lignes et l’expression moyenne des gènes localisés dans chaque chromosome comme valeurs, comme dans le tableau suivant :

Il faudra résumer avant de remodeler !

Calculons d’abord le niveau d’expression moyen des gènes liés X et Y à partir de échantillons mâles et femelles…

R

 arn %>%
  filter(chromosome_name == "Y" | chromosome_name == "X") %>%
  group_by(sex, chromosome_name) %>%
  résumé(moyenne = moyenne(expression))

ERREUR

Error in résumé(., moyenne = moyenne(expression)): could not find function "résumé"

Et faites pivoter le tableau au format large

R

rna_1 <- rna %>%
  filter(chromosome_name == "Y" | chromosome_name == "X") %>%
  group_by(sex, chromosome_name) %>%
  summarise(mean = moyenne(expression)) %>%
  pivot_wider(names_from = sexe,
              valeurs_from = moyenne)

ERREUR

Error in `summarise()`:
ℹ In argument: `mean = moyenne(expression)`.
ℹ In group 1: `sex = "Female"` and `chromosome_name = "X"`.
Caused by error in `moyenne()`:
! could not find function "moyenne"

R

rna_1

ERREUR

Error in eval(expr, envir, enclos): object 'rna_1' not found

Maintenant, prenez cette trame de données et transformez-la avec pivot_longer() afin que chaque ligne soit une combinaison unique de chromosome_name par gender.

R

rna_1 %>%
  pivot_longer(names_to = "gender",
               valeurs_to = "mean",
               -chromosome_name)

ERREUR

Error in eval(expr, envir, enclos): object 'rna_1' not found

ERREUR

Error in `pivot_longer()`:
! Arguments in `...` must be used.
✖ Problematic argument:
• valeurs_to = "mean"
ℹ Did you misspell an argument name?

Question

Utilisez l’ensemble de données rna pour créer une matrice d’expression où chaque ligne représente les niveaux d’expression moyens des gènes et les colonnes représentent les différents moments.

Calculons d’abord l’expression moyenne par gène et par temps

R

arn %>%
  group_by(gène, temps) %>%
  résumé(mean_exp = moyenne(expression))

ERREUR

Error in résumé(., mean_exp = moyenne(expression)): could not find function "résumé"

avant d’utiliser la fonction pivot_wider()

R

rna_time <- rna %>%
  group_by(gene, time) %>%
  summarise(mean_exp = mean(expression)) %>%
  pivot_wider(names_from = time,
              values_from = mean_exp)

SORTIE

`summarise()` has grouped output by 'gene'. You can override using the
`.groups` argument.

R

rna_time

SORTIE

# A tibble: 1,474 × 4
# Groups:   gene [1,474]
   gene         `0`     `4`     `8`
   <chr>      <dbl>   <dbl>   <dbl>
 1 AI504432 1034.   1104.   1014
 2 AW046200  155.    152.     81
 3 AW551984  238     302.    342.
 4 Aamp     4603.   4870    4763.
 5 Abca12      5.29    4.25    4.14
 6 Abcc8    2576.   2609.   2292.
 7 Abhd14a   591.    547.    432.
 8 Abi2     4881.   4903.   4945.
 9 Abi3bp   1175.   1061.    762.
10 Abl2     2170.   2078.   2131.
# ℹ 1,464 more rows

Notez que cela génère un tibble avec certains noms de colonnes commençant par un nombre. Si nous voulions sélectionner la colonne correspondant aux points temporels, nous ne pourrions pas utiliser directement les noms de colonnes… Que se passe-t-il lorsque l’on sélectionne la colonne 4 ?

R

rna %>%
  group_by(gene, time) %>%
  summarise(mean_exp = mean(expression)) %>%
  pivot_wider(names_from = time,
              values_from = mean_exp) %>%
  select(gene, 4)

SORTIE

`summarise()` has grouped output by 'gene'. You can override using the
`.groups` argument.

SORTIE

# A tibble: 1,474 × 2
# Groups:   gene [1,474]
   gene         `8`
   <chr>      <dbl>
 1 AI504432 1014
 2 AW046200   81
 3 AW551984  342.
 4 Aamp     4763.
 5 Abca12      4.14
 6 Abcc8    2292.
 7 Abhd14a   432.
 8 Abi2     4945.
 9 Abi3bp    762.
10 Abl2     2131.
# ℹ 1,464 more rows

Pour sélectionner le timepoint 4, il faudrait citer le nom de la colonne, avec des backticks “\`”

R

rna %>%
  group_by(gene, time) %>%
  summarise(mean_exp = mean(expression)) %>%
  pivot_wider(names_from = time,
              values_from = mean_exp) %>%
  select(gene, `4`)

SORTIE

`summarise()` has grouped output by 'gene'. You can override using the
`.groups` argument.

SORTIE

# A tibble: 1,474 × 2
# Groups:   gene [1,474]
   gene         `4`
   <chr>      <dbl>
 1 AI504432 1104.
 2 AW046200  152.
 3 AW551984  302.
 4 Aamp     4870
 5 Abca12      4.25
 6 Abcc8    2609.
 7 Abhd14a   547.
 8 Abi2     4903.
 9 Abi3bp   1061.
10 Abl2     2078.
# ℹ 1,464 more rows

Une autre possibilité serait de renommer la colonne, en choisissant un nom qui ne commence pas par un chiffre :

R

rna %>%
  group_by(gene, time) %>%
  summarise(mean_exp = mean(expression)) %>%
  pivot_wider(names_from = time,
              values_from = mean_exp) %>%
  rename("time0" = `0`, "time4" = `4`, "time8" = `8`) %>%
  select(gene, time4)

SORTIE

`summarise()` has grouped output by 'gene'. You can override using the
`.groups` argument.

SORTIE

# A tibble: 1,474 × 2
# Groups:   gene [1,474]
   gene       time4
   <chr>      <dbl>
 1 AI504432 1104.
 2 AW046200  152.
 3 AW551984  302.
 4 Aamp     4870
 5 Abca12      4.25
 6 Abcc8    2609.
 7 Abhd14a   547.
 8 Abi2     4903.
 9 Abi3bp   1061.
10 Abl2     2078.
# ℹ 1,464 more rows

Question

Utilisez la trame de données précédente contenant les niveaux d’expression moyens par point temporel et créez une nouvelle colonne contenant les changements de pli entre le point temporel 8 et le point temporel 0, et les changements de pli entre le point temporel 8 et le point temporel 4. Convertissez ce tableau en un tableau au format long regroupant les changements de pli calculés.

À partir du tibble rna_time :

R

arn_time

ERREUR

Error in eval(expr, envir, enclos): object 'arn_time' not found

Calculer les changements de plis :

R

rna_time %>%
  muter (time_8_vs_0 = `8` / `0`, time_8_vs_4 = `8` / `4`)

ERREUR

Error in muter(., time_8_vs_0 = `8`/`0`, time_8_vs_4 = `8`/`4`): could not find function "muter"

Et utilisez la fonction pivot_longer() :

R

rna_time %>%
  mutate(time_8_vs_0 = `8` / `0`, time_8_vs_4 = `8` / `4`) %>%
  pivot_longer(names_to = "comparisons",
               values_to = "Fold_changes",
               time_8_vs_0:time_8_vs_4)

SORTIE

# A tibble: 2,948 × 6
# Groups:   gene [1,474]
   gene         `0`     `4`     `8` comparisons Fold_changes
   <chr>      <dbl>   <dbl>   <dbl> <chr>              <dbl>
 1 AI504432 1034.   1104.   1014    time_8_vs_0        0.981
 2 AI504432 1034.   1104.   1014    time_8_vs_4        0.918
 3 AW046200  155.    152.     81    time_8_vs_0        0.522
 4 AW046200  155.    152.     81    time_8_vs_4        0.532
 5 AW551984  238     302.    342.   time_8_vs_0        1.44
 6 AW551984  238     302.    342.   time_8_vs_4        1.13
 7 Aamp     4603.   4870    4763.   time_8_vs_0        1.03
 8 Aamp     4603.   4870    4763.   time_8_vs_4        0.978
 9 Abca12      5.29    4.25    4.14 time_8_vs_0        0.784
10 Abca12      5.29    4.25    4.14 time_8_vs_4        0.975
# ℹ 2,938 more rows

Joindre des tables


Dans de nombreuses situations réelles, les données sont réparties sur plusieurs tables. Cela se produit généralement parce que différents types d’informations sont collectés à partir de différentes sources.

Il peut être souhaitable que certaines analyses combinent les données de deux ou plusieurs tables en une seule trame de données basée sur une colonne qui serait commune à toutes les tables.

Le package dplyr fournit un ensemble de fonctions de jointure pour combiner deux trames de données basées sur des correspondances dans des colonnes spécifiées. Ici, nous fournissons une brève introduction aux jointures. Pour en savoir plus, veuillez vous référer au chapitre sur les jointures de table . La Data Transformation Cheat Sheet fournit également un bref aperçu sur les jointures de table.

Nous allons illustrer la jointure en utilisant une petite table, rna_mini que nous allons créer en sous-définissant la table rna d’origine, en ne gardant que 3 colonnes et 10 lignes.

R

rna_mini <- rna %>%
   select(gène, échantillon, expression) %>%
   head(10)

ERREUR

Error in `select()`:
! Can't select columns that don't exist.
✖ Column `gène` doesn't exist.

R

rna_mini

ERREUR

Error in eval(expr, envir, enclos): object 'rna_mini' not found

Le deuxième tableau, annot1, contient 2 colonnes, gene et gene_description. Vous pouvez soit télécharger annot1.csv en cliquant sur le lien puis en vous déplaçant dans le dossier data/, ou vous pouvez utiliser le code R ci-dessous pour le télécharger directement dans le dossier.

R

download.file(url = "https://carpentries-incubator.github.io/bioc-intro/data/annot1.csv",
              destfile = "data/annot1.csv")
annot1 <- read_csv(file = "data/annot1.csv")
annot1

SORTIE

# A tibble: 10 × 2
   gene    gene_description
   <chr>   <chr>
 1 Cyp2d22 cytochrome P450, family 2, subfamily d, polypeptide 22 [Source:MGI S…
 2 Klk6    kallikrein related-peptidase 6 [Source:MGI Symbol;Acc:MGI:1343166]
 3 Fcrls   Fc receptor-like S, scavenger receptor [Source:MGI Symbol;Acc:MGI:19…
 4 Plp1    proteolipid protein (myelin) 1 [Source:MGI Symbol;Acc:MGI:97623]
 5 Exd2    exonuclease 3'-5' domain containing 2 [Source:MGI Symbol;Acc:MGI:192…
 6 Apod    apolipoprotein D [Source:MGI Symbol;Acc:MGI:88056]
 7 Gnb4    guanine nucleotide binding protein (G protein), beta 4 [Source:MGI S…
 8 Slc2a4  solute carrier family 2 (facilitated glucose transporter), member 4 …
 9 Asl     argininosuccinate lyase [Source:MGI Symbol;Acc:MGI:88084]
10 Gjc2    gap junction protein, gamma 2 [Source:MGI Symbol;Acc:MGI:2153060]    

Nous voulons maintenant joindre ces deux tables en une seule contenant toutes les variables en utilisant la fonction full_join() du package dplyr. La fonction trouvera automatiquement la variable commune correspondant aux colonnes de la première et de la deuxième table. Dans ce cas, « gène » est la variable commune . Ces variables sont appelées clés. Les clés sont utilisées pour faire correspondre observations dans différentes tables.

R

full_join(rna_mini, annot1)

ERREUR

Error in eval(expr, envir, enclos): object 'rna_mini' not found

Dans la vraie vie, les annotations génétiques sont parfois étiquetées différemment.

La table annot2 est exactement la même que annot1 sauf que la variable contenant les noms de gènes est étiquetée différemment. Encore une fois, soit télécharger annot2.csv vous-même et déplacez-le vers data/ ou utilisez le code R ci-dessous.

R

download.file(url = "https://carpentries-incubator.github.io/bioc-intro/data/annot2.csv",
              destfile = "data/annot2.csv")
annot2 <- read_csv(file = "data/annot2.csv")
annot2

SORTIE

# A tibble: 10 × 2
   external_gene_name description
   <chr>              <chr>
 1 Cyp2d22            cytochrome P450, family 2, subfamily d, polypeptide 22 [S…
 2 Klk6               kallikrein related-peptidase 6 [Source:MGI Symbol;Acc:MGI…
 3 Fcrls              Fc receptor-like S, scavenger receptor [Source:MGI Symbol…
 4 Plp1               proteolipid protein (myelin) 1 [Source:MGI Symbol;Acc:MGI…
 5 Exd2               exonuclease 3'-5' domain containing 2 [Source:MGI Symbol;…
 6 Apod               apolipoprotein D [Source:MGI Symbol;Acc:MGI:88056]
 7 Gnb4               guanine nucleotide binding protein (G protein), beta 4 [S…
 8 Slc2a4             solute carrier family 2 (facilitated glucose transporter)…
 9 Asl                argininosuccinate lyase [Source:MGI Symbol;Acc:MGI:88084]
10 Gjc2               gap junction protein, gamma 2 [Source:MGI Symbol;Acc:MGI:…

Si aucun des noms de variables ne correspond, nous pouvons définir manuellement les variables à utiliser pour la correspondance. Ces variables peuvent être définies en utilisant l’argument by, comme indiqué ci-dessous avec les tables rna_mini et annot2.

R

full_join(rna_mini, annot2, by = c("gene" = "external_gene_name"))

ERREUR

Error in eval(expr, envir, enclos): object 'rna_mini' not found

Comme on peut le voir ci-dessus, le nom de variable de la première table est conservé dans celle jointe.

Défi:

Téléchargez la table annot3 en cliquant sur ici et placez la table dans votre Dépôt de données. À l’aide de la fonction full_join() , joignez les tables rna_mini et annot3. Que s’est-il passé pour les gènes Klk6, mt-Tf, mt-Rnr1, mt-Tv, mt-Rnr2 et mt-Tl1 ?

R

annot3 <- read_csv("data/annot3.csv")
full_join(rna_mini, annot3)

ERREUR

Error in eval(expr, envir, enclos): object 'rna_mini' not found

Les gènes Klk6 ne sont présents que dans rna_mini, tandis que les gènes mt-Tf, mt-Rnr1, mt-Tv, mt-Rnr2 et mt-Tl1 sont présent uniquement dans la table annot3. Leurs valeurs respectives pour les variables du tableau ont été codées comme manquantes.

Exporter des données


Maintenant que vous avez appris à utiliser dplyr pour extraire des informations de ou résumer vos données brutes, vous souhaiterez peut-être exporter ces nouveaux ensembles de données pour les partager avec vos collaborateurs ou pour les archiver.

Semblable à la fonction read_csv() utilisée pour lire les fichiers CSV dans R, il existe une fonction write_csv() qui génère des fichiers CSV à partir de trames de données.

Avant d’utiliser write_csv(), nous allons créer un nouveau dossier, data_output, dans notre répertoire de travail qui stockera cet ensemble de données généré. Nous ne voulons pas que écrive les ensembles de données générés dans le même répertoire que nos données brutes. C’est une bonne pratique de les garder séparés. Le dossier data ne doit contenir que les données brutes et non modifiées, et doit être laissé seul pour nous assurer que nous ne supprimons pas ou ne le modifions pas. En revanche, notre script générera le contenu du répertoire data_output , donc même si les fichiers qu’il contient sont supprimés, nous pouvons toujours les régénérer.

Utilisons write_csv() pour sauvegarder la table rna_wide que nous avons créée précédemment.

R

write_csv(rna_wide, file = "data_output/rna_wide.csv")

Points clés

  • Données tabulaires dans R utilisant le méta-paquet Tidyverse