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:
Ajouter ou modifier des colonnes
Reformater des données
Ordonner un tableau en utilisant les valeurs d’une colonne
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`
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.
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
ettotal.leaf.length.mm
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
ettotal.leaf.length.mm
Créez une nouvelle colonne (nommée par exemple
condition
) en concaténantday.length
,temperature
etfluctuation
Sélectionnez les background
Col
etLer
Faites un boxplot du ratio de
blade.length.mm
ettotal.leaf.length.mm
en fonction de lacondition
, en créant des facets en fonction du backgroundPas 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
etfluctuation
, créer une colonneLD.SD
dans laquelle vous aurez “LD” à la place de la valeur “16” de la colonneday.length
, et “SD” à la place de la valeur “8” de la colonneday.length
. Utilisez ensuite cette colonneLD.SD
pour la concaténation avectemperature
etfluctuation
pour créer la colonnecondition
- Changez le thème du graphique pour enlever la grille et avoir un fond blanc.
spread()
et gather()
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.
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:
- Utilisez la fonction
gather()
pour restructurer le tableau afin de faire un boxplot deblade.length.mm
ettotal.leaf.length.mm
, coloré parfluctuation
.
- Ajoutez aux boxplots des encoches indiquant l’étendue de l’intervalle de confiance à 95% de la médiane (voir l’option
notch
dansgeom_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.
- 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:
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>
*_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()
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
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
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 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