Retour à la page d’accueil


Dans cette partie du cours vous allez apprendre à restructurer des tables dans R. Ces changement sont parfois nécessaire pour mettre les données dans le format adapté au graphique que vous voulez réaliser.

Aujourd’hui nous allons voir comment:

  1. Ajouter ou modifier des colonnes

  2. Reformater des données

  3. Ordonner un tableau en utilisant les valeurs d’une colonne

  4. Combiner plusieurs tableaux en un seul


Tout d’abord, créez un nouveau script R et préparez votre environnement de travail:

# Chargez la librairie `tidyverse`

# Changez votre répertoire de travail pour être dans `session3_plots_reorganisation`

# Importer `burghardt_et_al_2015_expt1.txt` et mettez le dans un objet appelé `expt1`


Modifier ou ajouter des colonnes avec mutate()

La fonction mutate() permet d’ajouter de nouvelles variables (i.e. nouvelles colonnes) dans une table, ou de modifier des colonnes déjà existantes.

source de l’image

Par exemple, ajoutons une colonne leaf.length.cm qui va contenir la longueur des feuilles en cm. Pour cela nous devons créer une nouvelle colonne en utilisant la colonne leaf.length.mm qui existe dans la table.

# Créez une nouvelle table avec la colonne supplémentare  
expt1.cm <- mutate(expt1, total.leaf.length.cm = total.leaf.length.mm/10)

# Vérifier que la nouvelle colonne est bien là
colnames(expt1.cm)
##  [1] "plant_nb"             "genotype"             "background"          
##  [4] "temperature"          "fluctuation"          "day.length"          
##  [7] "vernalization"        "survival.bolt"        "bolt"                
## [10] "days.to.bolt"         "days.to.flower"       "rosette.leaf.num"    
## [13] "cauline.leaf.num"     "blade.length.mm"      "total.leaf.length.mm"
## [16] "total.leaf.length.cm"

Nous pouvons aussi créer et modifier plus d’une colonne à la fois, en les séparant par une virgule (,) dans la fonction mutate():

# Créez deux nouvelles colonnes
expt1.cm <- mutate(expt1, 
                   blade.length.cm = blade.length.mm/10,
                   total.leaf.length.cm = total.leaf.length.mm/10)

# Vérifier que les nouvelles colonnes sont bien là
colnames(expt1.cm)
##  [1] "plant_nb"             "genotype"             "background"          
##  [4] "temperature"          "fluctuation"          "day.length"          
##  [7] "vernalization"        "survival.bolt"        "bolt"                
## [10] "days.to.bolt"         "days.to.flower"       "rosette.leaf.num"    
## [13] "cauline.leaf.num"     "blade.length.mm"      "total.leaf.length.mm"
## [16] "blade.length.cm"      "total.leaf.length.cm"

Attention!! Si vous utilisez le nom d’une colonne déjà existante, vous allez la modifier et non créer une nouvelle colonne.

Exercice 1:

Créez une nouvelle colonne (blade.ratio) avec le ratio de blade.length.mm et total.leaf.length.mm


Concaténer ou séparer des colonnes avec unite() et separate()


Pour concaténer deux ou plusieurs colonnes ensemble, utilisez la fonction unite(). Par exemple, pour concaténer vernalization, survival.bolt et bolt:

# Créez deux nouvelles colonnes
expt1.concatenated <- unite(expt1, "Vern_survival_bolt",vernalization,survival.bolt,bolt)

# Vérifier que la nouvelles colonnes sont bien là
colnames(expt1.concatenated)
##  [1] "plant_nb"             "genotype"             "background"          
##  [4] "temperature"          "fluctuation"          "day.length"          
##  [7] "Vern_survival_bolt"   "days.to.bolt"         "days.to.flower"      
## [10] "rosette.leaf.num"     "cauline.leaf.num"     "blade.length.mm"     
## [13] "total.leaf.length.mm"

A contrario, pour séparer une colonne en deux ou plusieurs colonnes, utilisez la fonction separate(). Par exemple, pour séparer la colonne barkground :

# Créez deux nouvelles colonnes
expt1.separated <- separate(expt1, background, into=c("genotype", "FRI mutation"))

# Vérifier que la nouvelles colonnes sont bien là
colnames(expt1.separated)
##  [1] "plant_nb"             "temperature"          "genotype"            
##  [4] "FRI mutation"         "fluctuation"          "day.length"          
##  [7] "vernalization"        "survival.bolt"        "bolt"                
## [10] "days.to.bolt"         "days.to.flower"       "rosette.leaf.num"    
## [13] "cauline.leaf.num"     "blade.length.mm"      "total.leaf.length.mm"



Exercice 2:

Reproduisez cette figure de Burghard et al 2015

Aide:

  • Créez une nouvelle colonne (blade.ratio) avec le ratio de blade.length.mm et total.leaf.length.mm

  • Créez une nouvelle colonne (nommée par exemple condition) en concaténant day.length, temperature et fluctuation

  • Sélectionnez les background Col et Ler

  • Faites un boxplot du ratio de blade.length.mm et total.leaf.length.mm en fonction de la condition, en créant des facets en fonction du background

  • Pas besoin de mettre de la couleur qui n’apporte rien au graphique

  • N’essayez pas de reproduire l’ordre des conditions (sur l’axe x). Nous verrons comment le faire à la prochaine séance

BONUS: Ce bonus vous permettra d’avoir des valeurs de x plus proches du graphique

  • Avant de créer la nouvelle colonne en concaténant day.length, temperature et fluctuation, créer une colonne LD.SD dans laquelle vous aurez “LD” à la place de la valeur “16” de la colonne day.length, et “SD” à la place de la valeur “8” de la colonne day.length. Utilisez ensuite cette colonne LD.SD pour la concaténation avec temperature et fluctuation pour créer la colonne condition
  • Changez le thème du graphique pour enlever la grille et avoir un fond blanc.



Reformater des données avec spread() et gather()


Passer au format large avec spread()

Parfois, le format de vos données ne vous permet pas de faire l’analyse ou le graphique que vous voulez.

Par exemple, essayons de reproduire le graphique suivant extrait de Burghard et al 2015


Pour faire cette figure il nous faut une colonne avec le temps de floraison pour les plantes en conditions constante et une autre colonne avec le temps de floraison pour les plantes en condition variable. Le temps de floraison pour toutes les plantes sont dans la même colonne dans notre tableau. Par contre, l’information sur le type de traitement (variable ou constant) est dans une autre colonne. Ce n’est pas ce que nous voulons! Heureusement, nous pouvons utiliser la fonction spread() pour reformater notre tableau.

Pour y voir plus clair, ne gardons que les colonnes qui vont nous être utiles à la création du tableau:

expt1_subset <- select(expt1, plant_nb:vernalization, days.to.bolt)

Maintenant nous devons changer la structure de la table pour avoir une colonne avec le temps de floraison pour les plantes en conditions constante et une autre colonne avec le temps de floraison pour les plantes en condition variable. Un peu comme dans le schéma ci-dessous (pour aller du format “long” au format “wide”).


La fonction spread() a besoin de deux informations:

  • Le nom de la colonne qui va permettre de créer les noms de colonnes dans la nouvelle table. Dans notre cas fluctuation

  • Le nom de la colonne qui contient les valeurs qui vont remplir les nouvelles colonnes. Dans notre cas days.to.bolt

Voici comment restructurer notre tableau avec spread():

expt1_wide <- spread(expt1_subset, key=fluctuation, value = days.to.bolt)

Afin de pouvoir reproduire les couleurs du graphique, nous devons concaténer les colonnes temperature et day.length. Et nous pouvons enfin faire le graphique:

unite(expt1_wide, "treatment", temperature, day.length) %>% 
ggplot(aes(x=Con, y=Var, col=treatment, shape=treatment)) +
  geom_point()
## Warning: Removed 51 rows containing missing values (geom_point).

Comme vous avez vu, changer la structure du tableau nous a permis de faire un graphique que nous n’aurions pas pu faire autrement. Cela peut aussi permettre de faire des analyses supplémentaires.




Passer au format long avec gather()


Imaginons que nous souhaitons faire un boxplot pour le days.to.bolt et le days.to.flower.


Pour faire ce boxplor il nous faut réorganiser le tableau pour avoir les données pour ces deux mesures dans la même colonnes (trait) et une colonne indiquant s’il s’agit de la mesure de days.to.bolt ou days.to.flower (time.in.days).


Pour cela nous utilisons la fonction gather() qui permet de passer d’un format “wide” à un format “long”.


Dans ce cas, le nom des colonnes sélectionnées devient la “clé”, c’est à dire les catégories dans la première colonne crée (en violet dans l’illustration). Et les valeurs de toutes ces colonnes sélectionnées vont remplir la deuxième colonne crée (en bleu dans l’illustration).


gather() à besoin de trois informations:

  • le nom de la nouvelle colonne contenant les nom des vieilles colonnes (dans notre cas trait)

  • le nom de la nouvelle colonne contenant les valeurs des anciennes colonnes (dans notre cas time.in.days)

  • le nom des anciennes colonnes que l’ont veut rassembler

Voici comment restructurer notre tableau avec gather():

expt1_long <- gather(expt1, "trait", "time.in.days", days.to.bolt, days.to.flower)

Nous pouvons maintenant faire notre boxplot

ggplot(expt1_long, aes(x=trait, y=time.in.days, color=genotype)) +
  geom_boxplot()
## Warning: Removed 83 rows containing non-finite values (stat_boxplot).


Afin d’exporter ce graphique et de le sauver, nous utilisons la fonction ggsave():

ggplot(expt1_long, aes(x=trait, y=time.in.days, color=genotype)) +
  geom_boxplot()
## Warning: Removed 83 rows containing non-finite values (stat_boxplot).

ggsave("boxplot_daystobolt_daystoflower_genotypes.jpg")
## Saving 7 x 5 in image
## Warning: Removed 83 rows containing non-finite values (stat_boxplot).


Exercice 3:

  1. Utilisez la fonction gather() pour restructurer le tableau afin de faire un boxplot de blade.length.mm et total.leaf.length.mm, coloré par fluctuation.
  1. Ajoutez aux boxplots des encoches indiquant l’étendue de l’intervalle de confiance à 95% de la médiane (voir l’option notch dans geom_boxplot). Si les encoches sont étroite, il y a peu d’incertitude sur la médiane, si les encoches sont large, il y a une forte incertitude sur la médiane. Si les encoches de boxplots que nous comparons se chevauchent, alors nous ne pouvons pas conclure à une différence de médiane entre les médiane des deux groupes.
  1. Interprétez le graphique: Y a t’il un effet de la fluctuation de température sur la longueur de blade ou de la feuille? Pourquoi?

BONUS Optimisez le graphique obtenu en jouant sur le thème, les couleurs utilisée (visibles par des daltoniens), le titre et la valeur des axes et de la légende, de manière à avoir un graphique similaire au graphique suivant:


Ordonner un tableau en utilisant les valeurs d’une colonne

Parfois, nous voulons ordonner nos données en fonction des valeurs d’une colonne.

Pour cela, nous pouvons utiliser la fonction arrange():

arrange(expt1, days.to.flower)
## # A tibble: 957 x 15
##    plant_nb genotype background temperature fluctuation day.length vernalization
##       <dbl> <chr>    <chr>            <dbl> <chr>            <dbl> <chr>        
##  1        5 Col Ama  Col                 22 Con                 16 V            
##  2        1 flc-3 F… Col FRI             22 Con                 16 V            
##  3        1 Col Ama  Col                 22 Con                 16 V            
##  4        3 Col Ama  Col                 22 Con                 16 V            
##  5        4 Col Ama  Col                 22 Con                 16 V            
##  6        2 flc-3 F… Col FRI             22 Con                 16 V            
##  7        3 flc-3 F… Col FRI             22 Con                 16 V            
##  8        7 flc-3 F… Col FRI             22 Con                 16 V            
##  9        3 flc-3 F… Col FRI             22 Var                 16 V            
## 10        5 flc-3 F… Col FRI             22 Var                 16 V            
## # … with 947 more rows, and 8 more variables: survival.bolt <chr>, bolt <chr>,
## #   days.to.bolt <dbl>, days.to.flower <dbl>, rosette.leaf.num <dbl>,
## #   cauline.leaf.num <dbl>, blade.length.mm <dbl>, total.leaf.length.mm <dbl>

Par défaut, les valeurs sont ordonnées de la plus basse à la plus haute.

Pour ordonner les valeurs de la plus haute à la plus basse, nous devons le spécifier en utilisant desc():

arrange(expt1, desc(days.to.flower))
## # A tibble: 957 x 15
##    plant_nb genotype background temperature fluctuation day.length vernalization
##       <dbl> <chr>    <chr>            <dbl> <chr>            <dbl> <chr>        
##  1        7 vin3-4 … Col FRI             12 Con                  8 NV           
##  2        8 vin3-4 … Col FRI             12 Con                  8 NV           
##  3        4 vin3-4 … Col FRI             12 Con                  8 NV           
##  4        8 vin3-4 … Col FRI             12 Var                  8 NV           
##  5        7 vin3-4 … Col FRI             12 Con                  8 V            
##  6        5 vin3-4 … Col FRI             12 Con                  8 NV           
##  7        1 vin3-4 … Col FRI             22 Con                  8 V            
##  8        2 ld-1     Col                 22 Con                  8 NV           
##  9        7 vin3-4 … Col FRI             12 Var                  8 NV           
## 10        8 vin3-4 … Col FRI             12 Con                  8 V            
## # … with 947 more rows, and 8 more variables: survival.bolt <chr>, bolt <chr>,
## #   days.to.bolt <dbl>, days.to.flower <dbl>, rosette.leaf.num <dbl>,
## #   cauline.leaf.num <dbl>, blade.length.mm <dbl>, total.leaf.length.mm <dbl>


Combiner plusieurs tableaux en un (*_join())

Quand nous analysons des données, il n’est pas rare que nous ayons plusieurs tableaux contenant des informations de différents types mais qui sont liées les unes aux autres. Afin de répondre à certaines questions, nous devons parfois combiner ces différents tableau en un seul, à l’aide d’une certaine colonne.

Pour cela nous pouvons utiliser une des fonction de la famille *_join.

Toutes ces fonctions ont besoin de trois choses: - Le nom du premier tableau (celui de gauche) - Le nom du second tableau (celui de droite) - Le nom de la colonne qui est utilisée pour combiner les tableaux ensemble (il est aussi possible d’utiliser plus d’une colonne)

Afin de comprendre comment ces fonctions marchent, nous allons utiliser deux jeux de données qui sont déjà présent dans R:

  • band_members
band_members
## # A tibble: 3 x 2
##   name  band   
##   <chr> <chr>  
## 1 Mick  Stones 
## 2 John  Beatles
## 3 Paul  Beatles
  • band_instruments
band_instruments
## # A tibble: 3 x 2
##   name  plays 
##   <chr> <chr> 
## 1 John  guitar
## 2 Paul  bass  
## 3 Keith guitar

La fonction full_join(), permet de garder toutes les lignes et toutes les colonnes des deux tableaux dans le nouveau tableau créé en les combinant. Dans notre cas, pour avoir toutes les information sur le groupe de musique et l’instrument pour chaque musicien, nous utilisons:

full_join(band_members, band_instruments, by="name")
## # A tibble: 4 x 3
##   name  band    plays 
##   <chr> <chr>   <chr> 
## 1 Mick  Stones  <NA>  
## 2 John  Beatles guitar
## 3 Paul  Beatles bass  
## 4 Keith <NA>    guitar

Vous pouvez voir que quand le groupe de musique ou l’instrument d’un musicien est manquante, un ‘NA’ est utilisé à la place.

Regardons les autres fonctions de la famille *_join()

  • Pour garder les données uniquement pour les musiciens présents dans band_members (table de gauche dans la fonction), nous utilisons left_join():
left_join(band_members, band_instruments, by="name")
## # A tibble: 3 x 3
##   name  band    plays 
##   <chr> <chr>   <chr> 
## 1 Mick  Stones  <NA>  
## 2 John  Beatles guitar
## 3 Paul  Beatles bass
  • Pour garder les données uniquement pour les musiciens présents dans band_instruments (table de droite dans la fonction), nous utilisons right_join():
right_join(band_instruments, band_members, by="name")
## # A tibble: 3 x 3
##   name  plays  band   
##   <chr> <chr>  <chr>  
## 1 John  guitar Beatles
## 2 Paul  bass   Beatles
## 3 Mick  <NA>   Stones
  • Pour garder uniquement les musiciens qui sont les deux tableaux, nous utilisons inner_join():
inner_join(band_members, band_instruments, by="name")
## # A tibble: 2 x 3
##   name  band    plays 
##   <chr> <chr>   <chr> 
## 1 John  Beatles guitar
## 2 Paul  Beatles bass

Dans ce cas il n’y a pas de ‘NA’

Ces fonctions peuvent être utiles pour comparer de gros jeux de données :

  • inner_join() est l’équivalent de l’intersection entre deux jeux de données.

  • full_join() est l’équivalent de l’union de deux jeux de données.


A faire pour la prochaine séance

A partir ce ce que nous avons vu aujourd’hui:

  • Utilisez mutate, gather ou spread pour reformater vos données. Est-ce que cela vous permet de faire de nouveaux graphiques qui n’étaient pas possibles sur les données non reformatées?

  • Utiliser une ou plusieurs fonctions de la famille *_join() pour combiner des tableaux ensemble. Est-ce que cela vous permet de faire de nouveaux graphiques qui n’étaient pas possibles sans combiner les tableaux?

  • N’oubliez pas d’utiliser des pipes (%>%) pour faire des chaines de commandes si vous utilisez plus d’une fonction sur vos données

Pour ceux qui n’ont pas de données, vous pouvez utiliser le tableau Pan_Rui_2017_flowering time_raw_data.txt (publié par Pan et Rui) dans le dossier data


Retour à la page d’accueil