Retour à la page d’accueil



1. Organisation des données dans un tableur

Adapté de ce cours

Pourquoi bien organiser les données dans un fichier?

Il est crucial d’avoir des données bien organisées afin de pouvoir les étudier correctement. Bien que formater, nettoyer et organiser les données peut être long et pénible, c’est une étape essentielle pour l’analyse ultérieure des données.

La plupart d’entre nous utilisent à un moment donné ou à un autre, un tableur (“Excel”) pour y enregistrer des données. Nous allons voir dans tableur:

  • comment éviter les pièges courants quand nous enregistrons des données

  • les bonnes habitudes pour organiser les données

  • les différents formats et leur compatibilité avec d’autres programmes (comme R)


Bonnes habitudes pour organiser les données dans un tableur

  • Ne modifiez jamais les données brutes! Toujours travailler sur une copie des données. C’est essentiel, surtout dans un logiciel comme excel, ou les modifications des données ne sont pas enregistrées. Si par exemple vous faites une erreur et ne le réalisez que plus tard (genre, des mois plus tard), c’est très difficile voir impossible de revenir sur les données brutes et de corriger l’erreur.

  • Notez et conservez l’information des manipulations de vos données. Par exemple, écrivez ces informations dans un document README ou dans un onglet séparé dans excel.

  • Toutes les données d’une expérience doivent être dans un seul et même tableau:
    • Les colonnes doivent contenir les variables (ce qui est mesuré)
    • Les lignes doivent contenir les observations (les unités de l’étude)


Exercice:

Une étude a été faite pour déterminer le sexe et le poids des animaux attrapés dans différentes parcelles expérimentales. L’expérience a été répétées sur deux années.

  • Ouvrez le fichier “dataset_messy.xls” situé dans le dossier “session1_organisation/data”. Ce fichier contient les données enregistrées lors de l’étude.
  • A partir des bonnes habitudes d’organisation indiquées plus haut, identifiez les problèmes de format dans ces données. Discutez-en

Problèmes dans l’organisation des données

  • Les données ne doivent pas être éparpillées dans plusieurs tableaux ou onglets

  • Les données manquantes doivent être indiquées par une cellule vide ou un “NA”. Un zéro doit être utilisé pour les zéros et non pour des données manquantes.

  • Le formatage (gras, cellules colorées etc) et commentaires ne doivent pas être utilisés. Les données importantes doivent être associées à une variable (par exemple dans le nom de la colonne).

  • Ne pas utiliser de caractères spéciaux (comme !, #, *).

  • Pour que ce soit compatible avec R, utiliser _ plutôt que des espaces entre les mots.

  • Attention aux dates! Cela peut causer des problèmes de format d’un tableur à un autre. Le mieux est de garder le jour, le mois et l’année comme des variables (colonnes) séparées

Exporter les données

Bien que excel est souvent utilisé, son format de fichier par défaut n’est malheureusement pas compatible avec d’autres programmes, y compris R. Pour cela le mieux est d’enregistrer les données tabulaires dans un format texte.

Les deux formats les plus utilisés sont:

CSV (séparateur: virgule (UK, US) ou point-virgule (EU))

TXT (séparateur: tabulation)

Attention: les documents avec un format CSV qui ont un séparateur virgule ou un séparateur point-virgule ne sont pas la même chose. Les confondre peut poser des problèmes lors de l’import des données dans R. C’est pourquoi nous recommandons de sauver les données en format TXT (séparateur: tabulation) pour ensuite pouvoir les importer dans `R.

Pour cela, dans excel, choisissez “Enregistrez sous” et ensuite sélectionnez le format TXT (séparateur: tabulation) .

Exercice:

  • Ouvrez le fichier “dataset_tidy.xls” dans le dossier “session1_organisation/data”
  • Regardez le tableau, est-ce que vous pouvez comprendre ce qu’il contient?
  • Exportez les données au format TXT (séparateur: tabulation) et sauvez le dans le dossier “session1_organisation/data”


2. Importer des données dans R et vérifier leur intégrité

R est un logiciel de statistique et un langage de programmation. Afin de faire quoi que ce soit avec R nous devons écrire des instructions avec un code spécifique. Apprendre à utiliser R peut prendre du temps mais nous allons le faire ensemble pas à pas. Cependant, le meilleur moyen d’apprendre est d’utiliser R régulièrement, par exemple pour vos projets de TP ou lors de vos stage.

Nous allons utiliser Rstudio, qui est un logiciel qui permet d’utiliser une interface facile d’utilisation quand nous travaillons avec R.

Voici à quoi ressemble RStudio:

Mise en place

Tout d’abord, nous allons créer un projet R qui contiendra tous nos scripts et leurs sorties. Pour cela allez dans file puis sélectionnez New Project…. Indiquez que vous voulez créer le projet dans un Existing Directory, choisissez le dossier contenant le cours (2021_M2_R) et cliquez sur Create Project. Cela va créer 2021_M2_R.Rproj qu’il vous suffit d’ouvrir la prochaine fois pour avoir accès à votre projet R dans Rstudio.

Lors de cette séance nous allons utiliser plusieurs packages qui contiennent les fonctions dont nous avons besoin:
- tidyverse qui contient plusieurs packages dont ggplot2
- visdat qui permet une représentation rapide des données

Ces packages sont normalement déjà installés. Pour les importer dans votre session, utilisez la fonction library() :

library(tidyverse)
library(visdat)

Import et vérification des données

Pour cette formation, nous allons utiliser une version légèrement modifiée du jeu de données publié par Burghard et al 2015.

Il s’agit d’une expérience de phénotypage de plantes d’Arabidopsis thaliana qui ont poussé dans différentes conditions:

  • A 12°C ou à 22°C
  • Avec une température constante ou qui fluctue dans la journée
  • Avec une période de 8h de jour ou de 16h de jour par cycle de 24h
  • Avec un traitement de froid qui imite l’hiver (vernalisation)

Des plantes de différents génotypes ont été analysées: des mutants et sauvages et des écotypes différents.

Pour chaque plante dans chaque condition plusieurs phénotypes ont été mesurés (voir illustration ci-dessous pour mieux comprendre les termes):

  • Le nombre de jour pour que la tige (qui contient les fleurs) émerge: days to bolt
  • Le nombre de jour pour que la première fleur s’ouvre: days to flower
  • Le nombre de feuilles dans la rosette à la fin de l’expérience: rosette leaf num
  • Le nombre de feuilles caulines à la fin de l’expérience: cauline leaf num
  • La longueur du limbe de la feuille: blade lenght mm
  • La longueur de la feuille (avec le pétiole et le limbe) total leaf length mm

Afin de charger les données dans R, et de les garder dans un objet que nous pourrons réutiliser, nous utilisons:

# Import des données et chargement dans l'objet expt1 
expt1 <- read_tsv("../data/burghardt_et_al_2015_expt1.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   plant_nb = col_double(),
##   genotype = col_character(),
##   background = col_character(),
##   temperature = col_double(),
##   fluctuation = col_character(),
##   day.length = col_double(),
##   vernalization = col_character(),
##   survival.bolt = col_character(),
##   bolt = col_character(),
##   days.to.bolt = col_double(),
##   days.to.flower = col_double(),
##   rosette.leaf.num = col_double(),
##   cauline.leaf.num = col_double(),
##   blade.length.mm = col_double(),
##   total.leaf.length.mm = col_double()
## )

La fonction read_tsv() imprime un message indiquant quel type de données sont contenues dans les différentes colonnes du fichier.

Dans notre cas, certaines colonnes contiennent des données de type “character” (du texte) et d’autres des données numériques (“double” en présence de décimale, “integer” en absence de décimale).

Pour regarder rapidement les données, tapez le nom de l’objet où sont les données (expt1).

expt1
## # A tibble: 957 x 15
##    plant_nb genotype background temperature fluctuation day.length vernalization
##       <dbl> <chr>    <chr>            <dbl> <chr>            <dbl> <chr>        
##  1        1 Col Ama  Col                 12 Con                 16 NV           
##  2        2 Col Ama  Col                 12 Con                 16 NV           
##  3        3 Col Ama  Col                 12 Con                 16 NV           
##  4        4 Col Ama  Col                 12 Con                 16 NV           
##  5        5 Col Ama  Col                 12 Con                 16 NV           
##  6        6 Col Ama  Col                 12 Con                 16 NV           
##  7        7 Col Ama  Col                 12 Con                 16 NV           
##  8        8 Col Ama  Col                 12 Con                 16 NV           
##  9        1 Col Ama  Col                 12 Con                  8 NV           
## 10        2 Col Ama  Col                 12 Con                  8 NV           
## # … 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>

Cela va montrer les 10 premières lignes du tableau ainsi que les colonnes qui rentrent dans l’écran.

Exercice: Combien y a-t-il de lignes et colonnes dans les données?

Une autre option est d’utiliser la fonction View() pour accéder à une table interactive où il est possible de trier et filtrer les données sans modifier l’objet:

View(expt1)
  • La fonction glimpse() permet d’avoir une idée de la structure des données:
glimpse(expt1)
## Rows: 957
## Columns: 15
## $ plant_nb             <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, …
## $ genotype             <chr> "Col Ama", "Col Ama", "Col Ama", "Col Ama", "Col…
## $ background           <chr> "Col", "Col", "Col", "Col", "Col", "Col", "Col",…
## $ temperature          <dbl> 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, …
## $ fluctuation          <chr> "Con", "Con", "Con", "Con", "Con", "Con", "Con",…
## $ day.length           <dbl> 16, 16, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8…
## $ vernalization        <chr> "NV", "NV", "NV", "NV", "NV", "NV", "NV", "NV", …
## $ survival.bolt        <chr> "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y"…
## $ bolt                 <chr> "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y"…
## $ days.to.bolt         <dbl> 28, 29, 31, 31, 32, 33, 34, 35, 69, 72, 76, 79, …
## $ days.to.flower       <dbl> 43, 44, 43, 42, 44, 47, 47, 49, 90, 91, 97, 99, …
## $ rosette.leaf.num     <dbl> 18, 15, 13, 17, 19, 14, 15, 18, 53, 49, 51, 55, …
## $ cauline.leaf.num     <dbl> 6, 5, 4, 5, 4, 4, 3, 5, 6, 5, 6, 9, 6, 9, 8, 10,…
## $ blade.length.mm      <dbl> 12.9, 10.5, 13.2, 14.6, 13.3, 14.7, 13.0, 17.8, …
## $ total.leaf.length.mm <dbl> 21.1, 19.1, 23.4, 27.2, 20.4, 25.3, 23.2, 31.3, …

Exercice Quel est le type des variables dans les données ?

  • dim() indique les dimensions du jeu de données (nombre de lignes et colonnes).
dim(expt1)
## [1] 957  15
  • Pour les données numériques, la fonction summary() permet d’obtenir des stats de base pour chaque colonne.
summary(expt1)
##     plant_nb        genotype          background         temperature   
##  Min.   : 1.000   Length:957         Length:957         Min.   :12.00  
##  1st Qu.: 2.000   Class :character   Class :character   1st Qu.:12.00  
##  Median : 4.000   Mode  :character   Mode  :character   Median :12.00  
##  Mean   : 4.589                                         Mean   :16.98  
##  3rd Qu.: 7.000                                         3rd Qu.:22.00  
##  Max.   :12.000                                         Max.   :22.00  
##                                                                        
##  fluctuation          day.length    vernalization      survival.bolt     
##  Length:957         Min.   : 8.00   Length:957         Length:957        
##  Class :character   1st Qu.: 8.00   Class :character   Class :character  
##  Mode  :character   Median :16.00   Mode  :character   Mode  :character  
##                     Mean   :12.01                                        
##                     3rd Qu.:16.00                                        
##                     Max.   :16.00                                        
##                                                                          
##      bolt            days.to.bolt    days.to.flower   rosette.leaf.num
##  Length:957         Min.   : 15.00   Min.   : 21.00   Min.   :  5.00  
##  Class :character   1st Qu.: 38.00   1st Qu.: 46.00   1st Qu.: 24.00  
##  Mode  :character   Median : 57.00   Median : 66.00   Median : 40.00  
##                     Mean   : 66.04   Mean   : 71.59   Mean   : 39.71  
##                     3rd Qu.: 85.00   3rd Qu.: 92.00   3rd Qu.: 53.00  
##                     Max.   :162.00   Max.   :182.00   Max.   :112.00  
##                                      NA's   :83       NA's   :95      
##  cauline.leaf.num blade.length.mm total.leaf.length.mm
##  Min.   : 1.000   Min.   : 7.10   Min.   : 9.00       
##  1st Qu.: 5.000   1st Qu.:18.00   1st Qu.:29.10       
##  Median : 8.000   Median :20.95   Median :34.60       
##  Mean   : 7.208   Mean   :21.11   Mean   :34.69       
##  3rd Qu.: 9.000   3rd Qu.:24.30   3rd Qu.:40.27       
##  Max.   :17.000   Max.   :59.00   Max.   :66.30       
##  NA's   :96       NA's   :327     NA's   :303

Nous avons déjà utilisé de nombreuses fonctions:

  • install.packages()
  • library()
  • read_tsv()
  • View()
  • glimpse()
  • summary()
  • dim()

Il est bien sûr difficile de ce souvenir du nom de toutes ces fonctions, ce qu’elles font et comment les utiliser. Heureusement, pour nous aider, une aide est disponible dans R en tapant le nom d’une fonction précédé de ?

?summary

Bien sur, une recherche sur internet est aussi une solution très efficace pour trouver de l’aide!

Exercice que fait la fonction head() ?

Exercice Comment regarder les dernières lignes de le notre jeu de données? (indice: ?tail)

Inspection visuelle des données

Pour avoir une vue d’ensemble du jeu de données et détecter des problèmes, nous allons utiliser la fonction vis_dat().

vis_dat(expt1)

Exercice Quel est le type de données le plus courant dans le jeu de données ? Y a-t-il des problèmes?

3. Faires des graphiques avec ggplot2

Quels types de graphiques pouvons nous faire avec ggplot2?

Il est possible de représenter les données de différentes manières et ggplot2 offre de nombreuses options de visualisation.

Parmi les plus connues:

Et encore plus. Pour toutes les découvrir, voir cette galerie de graphiques avec ggplot2

Comme il existe de nombreuses options, utilisez ce guide avec un arbre de décision pour choisir la meilleure méthode de visualisation

Maintenant que nous avons vérifié la qualité de notre jeu de donnée, nous pouvons générer des graphiques afin d’en apprendre plus sur les données générées par l’expérience.

Nous allons utiliser le package R ggplot2, qui utilise le principe de “grammar or graphics”. Il s’agit des briques du graphique. Cette méthode permettant de combiner et superposer différentes couches de briques:

  • data (données)
  • aesthetics
  • objet géométrique (type de graphique)
  • transformations statistiques
  • ajustements positionels
  • faceting

Les trois premières briques sont essentielles: data, aesthetics et objet géométrique.

  • data - Vos données
  • aesthetics - Ce que l’on veux montrer sur le graphique et qui dépend des données. Par exemple ce qui est en x et y, la couleur, forme, type de ligne, taille, etc… Pour cela nous utilisons la fonction aes().
  • geom_objects - les objets que nous voulons dans le graphique. Un graphique doit avoir au moins un geom_object, et peut en avoir plusieurs. Par exemple:
    • points (geom_point pour des scatter plots, dot plots)
    • lignes (geom_line pour des tendance, séries chronologiques)

Pour plus d’information sur la création de graphique avec ggplot2, voir cette antisèche très utile.

Commençons avec un boxplot: Dessinons le days.to.flower pour les différents génotypes.

La fonction ggplot() permet de commencer le graphique. Il faut aussi indiquer les données à utiliser:

ggplot(expt1)

Mais cela ne produit qu’un canevas gris!

Il nous manque des briques. En l’occurrence nous devons indiquer quelle aesthetics (c’est la terminologie de ggplot2) nous voulons sur ce canevas gris. Nous devons indiquer quelles sont les variables x et y du boxplot.

ggplot(expt1, aes(x = genotype, y = days.to.flower))

ggplot indique maintenant les variables genotype et days.to.flower de nos données sur les axes x et y du graphique.

Mais toujours pas de graphique. C’est parce que nous pas indiqué à ggplot quelle géométrie nous voulons dessiner sur le canevas. Pour faire un boxplot, nous ajoutons au canevas (littéralement avec un +) geom_boxplot():

ggplot(expt1, aes(genotype, days.to.flower)) +
  geom_boxplot()
## Warning: Removed 83 rows containing non-finite values (stat_boxplot).

Exercice 1: Pouvez vous dessiner un violin plot? (indice: ?geom_violin)

Ajout de plusieurs couches

Nous allons maintenant ajouter d’autres geom_objects au même graphique. Par exemple, des points pour les valeurs des individus en plus du boxplot:

ggplot(expt1, aes(genotype, rosette.leaf.num)) +
  geom_jitter() +
  geom_boxplot()
## Warning: Removed 95 rows containing non-finite values (stat_boxplot).
## Warning: Removed 95 rows containing missing values (geom_point).

Exercice 2: Modifiez le graphique pour que les points soient devant plutôt que derrière les boxplots.

Couleurs!

Changeons la couleur des boxplots:

ggplot(expt1, aes(genotype, days.to.flower)) +
  geom_boxplot(colour = "red")
## Warning: Removed 83 rows containing non-finite values (stat_boxplot).

Ou la couleur à l’intérieur ( fill) des boxplots:

ggplot(expt1, aes(genotype, days.to.flower)) +
  geom_boxplot(colour = "red", fill = "royalblue")
## Warning: Removed 83 rows containing non-finite values (stat_boxplot).

Ou même leur transparence:

ggplot(expt1, aes(genotype, days.to.flower)) +
  geom_boxplot(colour = "red", fill = "royalblue", alpha = 0.5)
## Warning: Removed 83 rows containing non-finite values (stat_boxplot).

C’est sympa, mais cela ne nous apporte pas d’information en plus sur les données.

Par exemple, ajoutons une couleur qui change en fonction d’un des traitements auquel les plantes ont été exposées (par exemple fluctuation). En langage ggplot2, nous voulons lier la valeur de la variable fluctuation à la couleur dans l’ aesthetic du graphique.

Nous devons donc inclure cette information dans aes():

ggplot(expt1, aes(genotype, days.to.flower, colour = fluctuation)) +
  geom_boxplot()
## Warning: Removed 83 rows containing non-finite values (stat_boxplot).

Wow! ggplot a automatiquement séparé les données de chaque génotype en deux groupes en fonction de fluctuation et leur a attribué une couleur.

Imaginons que nous voulons ajouter les points pour les valeurs des individus, sans couleur, derrière les boxplots colorés:

ggplot(expt1, aes(genotype, days.to.flower, colour = fluctuation)) +
  geom_jitter() +
  geom_boxplot(alpha = 0.5)
## Warning: Removed 83 rows containing non-finite values (stat_boxplot).
## Warning: Removed 83 rows containing missing values (geom_point).

Ce n’est pas ce que nous voulons. L’aesthetique colour a été liée à toutes les géométries du graphique. C’est parce qu’elle a été définie dans la fonction ggplot(), qui affecte tous les geom_object qui viennent après.

Mais nous pouvons aussi définir l’aesthetique dans chaque géométrie:

ggplot(expt1, aes(genotype, days.to.flower)) +
  geom_jitter() +
  geom_boxplot(aes(fill = fluctuation), alpha = 0.5)
## Warning: Removed 83 rows containing non-finite values (stat_boxplot).
## Warning: Removed 83 rows containing missing values (geom_point).

Exercice 3: Nous voulons étudier la relation entre le nombre de feuille de rosette et la longueur la limbe des feuilles (en mm) pour les génotypes.

Pour cela, dessinez un scatter plot (geom_point()) entre blade.length.mm et rosette.leaf.num en colorant les points en fonction de genotype.

Que se passe t-il si les points sont colorés en fonction de days.to.bolt?

4. Créer des graphiques avec des facets

Souvent trop de variables, ou de groupes, sont dans nos données pour pouvoir uniquement utiliser les couleurs pour les discriminer.

C’est le cas par exemple du scatterplot produit dans l’exercice précédent, où les points sont colorés en fonction du génotype. Il est difficile de bien discerner les données pour chaque génotype car ils sont très rapprochés. L’idéal serait d’avoir un scatterplot par génotype.

Ceci est assez facile à faire avecggplot2, il suffit d’ajouter une couche au graphique appelée “facet”:

  • facet_grid() - qui permet d’organiser les panneaux du graphique en lignes et/ou colonnes
  • facet_wrap() - qui permet d’organiser les panneaux du graphique à la suite les uns des autres qui reviennent à la ligne après un certain nombre de panneaux.

Voyons comment facet_grid() fonctionne:

ggplot(expt1, aes(blade.length.mm, rosette.leaf.num, colour = genotype)) +
    geom_point() +
    facet_grid(genotype ~ temperature)
## Warning: Removed 333 rows containing missing values (geom_point).

Dans facet_grid(), nous utilisons la notation (ligne ~ colonne) pour définir les variables qui sont utilisées pour séparer les panneaux en ligne et colonnes.

Exercice 4: Les couleurs n’apportent plus d’information supplémentaire. Pensez à une utilisation plus intéressante des couleurs dans ce graphique.

Il est possible de ne préciser qu’une variable dans facet_grid() :

# Faceter en ligne
ggplot(expt1, aes(blade.length.mm, rosette.leaf.num, colour = fluctuation)) +
    geom_point() +
    facet_grid(genotype ~ .)
## Warning: Removed 333 rows containing missing values (geom_point).

# Faceter en colonne
ggplot(expt1, aes(blade.length.mm, rosette.leaf.num, colour = fluctuation)) +
    geom_point() +
    facet_grid(. ~ genotype)
## Warning: Removed 333 rows containing missing values (geom_point).

Il est aussi possible d’utiliser facet_wrap() si l’on n’utilise qu’une variable pour séparer les données :

ggplot(expt1, aes(blade.length.mm, rosette.leaf.num, colour = fluctuation)) +
    geom_point() +
    facet_wrap( ~ genotype)
## Warning: Removed 333 rows containing missing values (geom_point).

Exercice 5: Modifiez le graphique précédent afin de séparer les données (facet) en fonction de fluctuation en ligne, et day.length en colonne et de colorer les points en fonction du génotype.

## Warning: Removed 333 rows containing missing values (geom_point).


Exercice 6: Reproduisez le graphique suivant (ou quelque chose d’approchant): Fig. 2B-C of Burghard et al 2015.

Indice: facet le graphique avec day.length et temperature et colorer l’intérieur des boxplot en fonction de fluctuation.




En conclusion, il est possible de représenter de nombreuses informations en combinant efficacement facets, couleurs et autres aesthetiques!

Cependant, il y a certains types de représentation à éviter, et d’autres qui sont plus adaptés à vos données. Lisez ce document pour en savoir plus sur les bonnes pratiques à suivre quand vous créez vos graphiques.