1 Préface
Ce document a pour but d’être un guide pour toute personne aux études supérieures qui ont des connaissances limitées en statistiques et/ou en programmation avec R. Commencer avec R/Rstudio peut être difficile et anxiogène, surtout sans encadrement direct par une personne spécialiste ou avec beaucoup d’expérience dans le domaine. Par contre, l’analyse des données est sûrement une des étapes les plus importantes et les plus difficiles dans le parcours de la recherche.
On parcourt plusieurs thèmes dans les prochaines sections, avec une attention particulière sur l’utilisation de R et RStudio et sur la création de graphiques.
Les propos présents assument une connaissance de base de statistique (équivalent à un cours de statistique ou de biostatistique au baccalauréat) et assume une utilisation précédente de R/RStudio dans un contexte limité. C’est-à-dire que vous savez déjà comment ouvrir le logiciel, ouvrir un script, initialiser des librairies et exécuter une fonction de base (ou deux). Au besoin, vous pouvez vous référer aux définitions de certains termes utilisés qui se retrouvent en annexe (Section 8.1).
Ceci n’est en aucune façon la seule ressource disponible ou recommandée lors de votre apprentissage avec R/RStudio. Tout au long du document, on propose d’autres ressources externes qui contiennent plus de détails et des précisions sur des analyses, des fonctions, des librairies, ou d’autres aspects qui sont mentionnés dans différentes sections.
À noter qu’il est important de mettre à jour R et RStudio régulièrement. La version de R présentement utilisée est 4.6.0 (R Core Team, 2026). Pour mettre à jour R et RStudio, vous pouvez visiter leur site web respectif pour télécharger directement les nouvelles versions, soit le CRAN (Comprehensive R Archive Network) CRAN - R for Windows pour R et Posit Posit - RStudio pour Rstudio. Toutefois, il est aussi possible d’utiliser le package “installr” avec la fonction updateR() pour mettre à jour automatiquement R.
À garder en tête que R est le “vrai” programme de statistique et que RStduio est simplement l’interface qui facilite l’utilisation de R, alors il est plus important de mettre à jour R souvent que RStudio, d’où la grande utilité de updateR().
Si vous avez des commentaires, des suggestions ou des questions, je vous implore de me contacter par courriel1 ou en personne si vous avez le bonheur (ou le malheur) de me côtoyer. Ceci est un document en constante évolution et ne peut s’améliorer sans votre aide.
Sur ce, bonne lecture!
2 Notions et astuces de bases
R et RStudio ont plusieurs fonctionnalités qui sont parfois cachées, mais qui peuvent sauver une quantité surprenante d’heures de recherche, de lecture ou d’analyse. C’est bien pratique de les garder en tête lorsqu’on travaille dans RStudio.
2.1 Documentation et le raccourci F1
La documentation des fonctions et des librairies (“packages”) dans R est une ressource indispensable pour apprendre à bien utiliser et manipuler une fonction. La documentation peut souvent être trouvée sur internet en cherchant la fonction et/ou le package, mais il existe un raccourci dans RStudio directement: F1.
Lorsqu’une fonction est surlignée avec le curseur (qui peut être fait rapidement avec un double-clic), F1 ouvre la fenêtre “Help” sur la page de documentation pour la fonction surlignée. Cela évite de devoir chercher sur internet ou de faire la recherche à travers RStudio manuellement. La documentation généralement inclut:
- une description générale de la fonction
- le package d’où elle vient
- les arguments possibles et leurs types de valeurs/objets associés (numérique, booléen, vecteur, dataframe, etc.)
- des détails spécifiant certains aspects de la fonction au besoin
- des exemples simples d’utilisation de la fonction
Tout ça est très pratique lorsqu’on apprend comment utiliser une nouvelle fonction ou si on veut tout simplement ajuster et personnaliser la fonction à notre besoin, comme des graphiques.
2.2 R Projects
Outre les scripts R, il existe d’autres types de fichiers R, comme des R Projects. Il est pratique (et recommandé) de travailler dans l’espace de travail d’un projet R. Les projets R crée des dossiers dans un emplacement que vous définissez et rassemblent des scripts pertinents et surtout sauvegarde l’environnement globale de la session R lorsqu’elle ferme (sauvegardé sous format .RData). Ceci permet de garder des objets (dataframes, vecteurs, listes, graphiques, etc.) plus facilement entre des sessions de travail.
De plus, il est pratique de placer les fichiers de données à importer dans le dossier de projet (ou un sous-dossier) pour faciliter l’importation des données. Cela évite à spécifier l’emplacement du fichier au complet. Donc au lieu d’avoir un emplacement dans le genre “C:\Utilisateurs\public\Documents\Recherche\Projet1\Données1.xlsx”, cela peut être simplifié à juste le nom du fichier lui-même, soit “Données1.xlsx”.
2.3 Environnement et mémoire
Les sessions R ont plus que juste les scripts et autres fichiers classiques qui changent lors de votre travail et votre progrès dans l’analyse de vos données. L’environnement global de votre session et/ou projet change également. Les nouveaux tableaux ou graphiques, par exemple, vont s’y trouver lorsque vous les créez pour la première fois. Tous ces objets peuvent devenir assez lourds pour la mémoire vive (RAM) de votre appareil et éventuellement votre stockage de données (disque dur). Ceci est particulièrement vrai pour des données spatiales de types raster et shapefiles lors de la création de cartes.
Dans la fenêtre “Environment” de RStudio, lorsqu’on change l’affichage de “List” à “Grid”, on peut classer tous les objets enregistrés par nom, type d’objet, ou bien par taille. Ici on peut voir si certains objets prennent beaucoup d’espace. Souvent, de vieux objets qui ne sont plus utilisés ou qui sont obsolètes y sont encore sauvegardés. Il est pertinent de faire le ménage de l’environnement de temps en temps, ceci peut aider à réduire la taille du fichier .RData qui contient l’environnement d’un projet et/ou d’une session et permet de libérer de l’espace pour assurer une bonne performance de R.
Ceci peut être fait soit avec l’icône de balais pour tout effacer (à utiliser avec caution) ou bien en vue de “Grid” on peut supprimer les objets individuellement, souvent les plus volumineux ou ceux qui sont simplement plus utilisés ou trop vieux.
2.4 Annotations et indexations
Dans les scripts de RStudio, il est possible d’annoter et commenter avant, après ou sur les mêmes lignes que le code lui-même. Ceci est fait avec le symbole “#”. Sur une ligne donnée, tout qui suit le “#” sera transformé en texte et sera ignoré lors de l’exécution du code ou de la fonction.
Il est aussi possible de faire plusieurs lignes de commentaire plus facilement avec le symbole “#’”, ceci fait en sorte que, quand vous faite un retour à la ligne (“enter”), il y a un nouveau symbole “#’” qui y est déjà pour continuer le commentaire automatiquement et plus facilement.
Montrer le code
[1] "Hello World!"
Le symbole “#” peut aussi être utilisé pour faire des indexations à l’intérieur d’un script. En plaçant quatre (4) “#” suivant un commentaire (ex. # Commentaire ici ####), le commentaire se transforme en entête de section comme titre le commentaire lui-même. Donc, avec un commentaire avec la syntaxe “# Titre ####”, vous pouvez nommer des sections de codes qui traitent de données ou de fonctions différentes. En plaçant un deuxième “#” en avant du titre, il est possible de faire un sous-titre. Il n’y a pas de limite sur le nombre de titres, de sous-titres, ni de niveaux de sous-sous-titre. Cette séparation est accessible rapidement en bas à gauche de la fenêtre du script, où on peut voir toutes les indexations d’un script et naviguer entre eux facilement. Vous pouvez donc avec plusieurs sous-sous-sous-sous-sous-titre si vous le désirez, mais, rendu là, il serait peut-être plus sage de séparer ce script en deux scripts différents.
2.5 Importation de données
La deuxième étape à tout travail dans RStudio après avoir initialisé les libraires est évidemment d’importer les données nécessaires. Il existe une panoplie de fonction et de méthode pour le faire, mais les plus globalement utiles sont l’importation de fichiers .csv ou des tableurs Excel.
Pour de fichiers csv, une fonction existe déjà dans la base de R. Il faut simplement spécifier le nom et/ou l’emplacement du fichier, si l’entête se trouve dans le fichier ou non (“header” = T ou F), et le type de séparateur utilisé. Oui, les .csv (comma seperated values) peuvent utiliser un autre symbole que les virgules pour séparer des données, souvent des espaces, des tabulations (tab) ou des points-virgules. Il aussi possible de spécifier le symbole utilisé pour les décimales (rien de pire que de gérer des erreurs de décimales avec des virgules vs des points).
Pour les fichiers Excel (.xlsx ou .xls), il faut d’abord importer une librairie qui nous permet d’importer les données. Avec la fonction read_xlsx (aussi nommée read_excel et read_xls), on peut spécifier la feuille spécifique qu’on veut importer et on peut aussi spécifier un intervalle de cellule à importer. Par défaut, la fonction importe uniquement la première feuille et toutes les cellules qui ne sont pas vides.
2.6 Préparation de données
2.6.1 Gestion des NAs
Il existe plusieurs fonctions qui peuvent nous aider à gérer des données manquantes. Il existe aussi plusieurs fonctions qui possèdent leurs propres arguments déjà inclus qui nous permettent de spécifier quoi faire avec des données manquantes lors de l’exécution de la fonction d’analyse elle-même.
Par exemple, la fonction corrplot() a des arguments pour spécifier une couleur associée à des données manquantes qui apparaîtraient lors de la création du graphique. La fonction prcomp() a aussi un argument pour la gestion des NAs. Elle utilise les fonctions standards, soit la famille de fonctions na.omit().
na.omit() et les fonctions associées (na.fail(), na.pass(), na.exclude()), sont très pratiques pour nous aviser de la présence de données manquante, les retirer, ou bien simplement forcer à les ignorer. na.omit() peut prendre des vecteurs, des matrices, ou bien des dataframes, donc peut être utilisée pour presque tout ce dont on a de besoin.
La fonction complete.cases() a aussi certaines utilités. Cette fonction retourne un vecteur logique (True/False) indiquant les données complètes, donc indiquant False aux données manquantes. Avec la syntaxe [,] des dataframes, on peut l’utiliser comme ça:
Si, pour une raison ou une autre, vous considérez des données négatives (ou positive, ou autre) comme des NAs dans le cadre de vos analyses, les fonctions ici ne vont pas vraiment vous aider. Heureusement, R est un outil magnifique et il y a plusieurs façons de filtrer les données comme on le souhaite.
Par exemple, pour garder seulement les données positives d’un objet quelconque (généralement un dataframe), on peut utiliser la librairie “dplyr” et ses fonctions de filtrage et de sélection. On peut utiliser la fonction filter() pour filtrer des NAs directement aussi, c’est un peu “overkill” lorsqu’utilisé seul, mais bien pratique lorsqu’on veut filtrer une ou des variables selon un critère et enlever les données manquantes en même temps.
2.6.2 Structuration des données
La structure des données est l’une des étapes les plus importantes avant toutes les analyses. Malheureusement, elle n’est pas toujours facile ou évidente à faire.
La structure des données dans R/Rstudio est un peu différente de celle qu’on utiliserait dans Excel, par exemple. Dans Excel, la plupart du temps, un va voir une colonne pour chaque variable ou, dans le cas de présence de facteurs et/ou catégorie, une colonne pour chaque variable et facteur/catégorie différente. Exemple, ça ressemblerait à ceci:
Montrer le code
excel_ex <- data.frame(
"Variable1_FacteurA" = c("1","2","3","...", "n"),
"Variable1_FacteurB" = c("1","2","3","...", "n"),
"Variable2_FacteurA" = c("1","2","3","...", "n"),
"Variable2_FacteurB" = c("1","2","3","...", "n"),
"Variable3_FacteurA" = c("1","2","3","...", "n"),
"Variable3_FacteurB" = c("1","2","3","...", "n")
)
excel_ex| Variable1_FacteurA | Variable1_FacteurB | Variable2_FacteurA | Variable2_FacteurB | Variable3_FacteurA | Variable3_FacteurB |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | 1 | 1 |
| 2 | 2 | 2 | 2 | 2 | 2 |
| 3 | 3 | 3 | 3 | 3 | 3 |
| … | … | … | … | … | … |
| n | n | n | n | n | n |
Quoique cette structure est utilisable dans plusieurs fonctions de R, les fonctions qu’on utilise ici (et de façon générale) nécessitent une structure de données légèrement différente. Au lieu d’avoir une colonne par combinaison de variation-facteur, toutes les données pour une variable sont dans la même colonne avec une colonne pour les facteurs seuls. Ça va ressembler à ça:
Montrer le code
| Variable1 | Variable2 | Variable3 | Facteur |
|---|---|---|---|
| 1 | 1 | 1 | A |
| 2 | 2 | 2 | A |
| 3 | 3 | 3 | A |
| … | … | … | A |
| n | n | n | A |
| 1 | 1 | 1 | B |
| 2 | 2 | 2 | B |
| 3 | 3 | 3 | B |
| … | … | … | B |
| m | m | m | B |
Évidemment, on peut arranger nos données comme ça dans Excel avant de les importer dans R/Rstudio, mais si c’est déjà importer et/ou il y a déjà eu des manipulations de données qui ont été faites, alors on peut réorganiser les données directement dans R/Studio (et c’est plus simple qu’on le pense).
D’abord, une petite parenthèse sur la syntaxe de [,] pour des objets de type dataframe (ça va vraiment aider t’inquiète). Donc, lorsqu’on a un dataframe, un peut utiliser les [,] pour spécifier des lignes ou des colonnes spécifiques, séparées d’une virgule. Les lignes spécifiées sont avant la virgule et les colonnes spécifiées sont après. Exemple, si on veut juste la première ligne d’un dataframe, on peut faire:
| temps | Variable1 | Variable2 | Variable3 | Variable4 | Variable5 | Variable6 |
|---|---|---|---|---|---|---|
| 1 | 1.00031 | 100.366 | 1.0824 | 6.938574 | 52.13836 | 2.43248 |
Si on veut juste la première colonne, on peut faire:
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
[19] 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
[37] 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
[55] 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
[73] 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
[91] 91 92 93 94 95 96 97 98 99 100
Un espace vide indique qu’il n’y a pas de changement, on n’appelle pas de ligne ou de colonne spécifique, alors toutes les lignes/colonnes vont s’afficher si on ne spécifie rien. Exemple avec un dataframe plus petit (sinon vous allez “scroller” longtemps):
| Variable1_FacteurA | Variable1_FacteurB | Variable2_FacteurA | Variable2_FacteurB | Variable3_FacteurA | Variable3_FacteurB |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | 1 | 1 |
| 2 | 2 | 2 | 2 | 2 | 2 |
| 3 | 3 | 3 | 3 | 3 | 3 |
| … | … | … | … | … | … |
| n | n | n | n | n | n |
À l’intérieur des [,] on peut utiliser des vecteurs pour spécifier une série de lignes ou de colonnes, comme ça:
| Variable1 | Variable2 |
|---|---|
| 1.00031 | 100.3660 |
| 2.88990 | 407.3494 |
| 27.67320 | 1809.8954 |
| 16.89164 | 1355.1773 |
| 24.67975 | 1683.5962 |
Si vous voulez d’autres exemples de ce genre d’opération, allez voir la structure des données qu’on utilise ici, l’affichage partiel des dataframes utilisées est fait avec [,].
Bon, de retour à organiser nos colonnes, c’est assez de la syntaxe de R (pour l’instant).
Les fonctions rbind() et cbind() (“row bind”/“column bind”) sont particulièrement utiles pour la manipulation de dataframes pour les reformater comme on veut. Ces fonctions nous permettent de combiner deux dataframes (ou deux parties de dataframe différent) ensemble via ses lignes ou ses colonnes. Pour illustrer ça peut ressembler à quoi, je vais prendre le dataframe typique qu’on aurait dans Excel et je vais le transformer en dataframe qu’on utilise plus typiquement dans R comme vu au début de la Section 2.6.2. La fonction rbind() doit avoir des colonnes avec les mêmes noms pour les combiner ensemble, alors on doit changer le nom des colonnes en premier. Il y a mille et deux façons de changer le nom d’une/plusieurs colonnes d’un dataframe, ici j’en présente une.
Montrer le code
excel_ex1 <- excel_ex[,c(1,2,3)] #séparation du dataframe en 2
excel_ex2 <- excel_ex[,c(4,5,6)] #trust me bro, ça va être plus facile comme ça pour cette méthode
names(excel_ex1) <- c("Var1","Var2","Var3") #on renomme les colonnes
names(excel_ex2) <- c("Var1","Var2","Var3") #avec les mêmes noms
Rdata_ex2 <- rbind(excel_ex1,excel_ex2) #on combine les 2 moitiées par les lignes
Rdata_ex2$Facteur <- c(rep("A", 5), rep("B", 5)) #on ajoute la colonne de facteur
Rdata_ex2 #ta daaa| Var1 | Var2 | Var3 | Facteur |
|---|---|---|---|
| 1 | 1 | 1 | A |
| 2 | 2 | 2 | A |
| 3 | 3 | 3 | A |
| … | … | … | A |
| n | n | n | A |
| 1 | 1 | 1 | B |
| 2 | 2 | 2 | B |
| 3 | 3 | 3 | B |
| … | … | … | B |
| n | n | n | B |
Le reformatage des dataframes est malheureusement plus qu’une seule ligne la plupart du temps. Mais il y a d’autres façons de faire aussi. Au lieu de combiner deux dataframes/moitiés de dataframes ensemble, on peut recréer un nouveau dataframe avec la structure qu’on veut basé sur les informations du dataframe original/mal formaté. Dépendant de la grosseur des dataframes, une méthode pourrait être plus rapide qu’une autre, mais les deux produisent exactement la même chose.
Montrer le code
Rdata_ex3 <- data.frame(
"Var1" = c(excel_ex$Variable1_FacteurA, excel_ex$Variable1_FacteurB),
"Var2" = c(excel_ex$Variable2_FacteurA, excel_ex$Variable2_FacteurB),
"Var3" = c(excel_ex$Variable3_FacteurA, excel_ex$Variable3_FacteurB),
"Facteur" = c(rep("A", 5), rep("B", 5))
)
Rdata_ex3 #ta daaa encore| Var1 | Var2 | Var3 | Facteur |
|---|---|---|---|
| 1 | 1 | 1 | A |
| 2 | 2 | 2 | A |
| 3 | 3 | 3 | A |
| … | … | … | A |
| n | n | n | A |
| 1 | 1 | 1 | B |
| 2 | 2 | 2 | B |
| 3 | 3 | 3 | B |
| … | … | … | B |
| n | n | n | B |
2.7 Choix de couleur
C’est facile de se surexciter à l’idée de mettre beaucoup de belles couleurs dans nos graphiques et de construire notre esthétique colorée personnalisée basée sur nos préférences personnelles. Malheureusement pour les personnes avec un penchant artistique, la représentation graphique en sciences n’apporte pas autant de liberté que les autres arts (puisque la création de graphiques scientifique est absolument une forme d’art). Il faut penser plus loin que nos propres préférences et penser aux autres, et surtout aux personnes avec une déficience de la vue.
Outre les types de daltonismes, une bonne gestion des couleurs est aussi pratique pour l’impression de nos travaux si jamais ils sont imprimés en noir et blanc/nuances de gris ou en monochrome (oui il y a une différence) .
La librairie “viridis” est absolument excellente pour tout ce qui est des couleurs et gradients de couleur accessibles et bien visible tout en gardant une belle palette. Je recommande que vous y jetiez un coup d’œil à leur documentation Viridis. En bonus, l’article de Nuñez (Nuñez, 2018) est une excellente lecture pour pousser plus loin vos connaissances et votre perception des couleurs.
Personnellement, j’utilise les gradients de couleurs de “viridis” systématiquement maintenant pour la gestion et le choix des couleurs dans mes graphiques et c’est ce qui est utilisé la majorité du temps dans ce document-ci (si vous aimez le système de Brewer/ColorBrewer, allez voir ailleurs, c’est pas assez bon pour mes standards). Donc, ce n’est pas les exemples de couleurs qui manquent ici.
2.8 Valeur de p et taille d’échantillon
La valeur de p est parfois présentée comme le Saint Graal, qui doit être absolument sous 0.05 pour que les résultats soient “bons”. Mais on va prendre un (ou plusieurs) pas de recul et réexaminer c’est quoi exactement la valeur de p.
La valeur de p est la probabilité que l’on observe une valeur d’un test statistique plus élevée que la valeur calculée sachant l’hypothèse nulle. Autrement dit, c’est la probabilité que les données qu’on observe soient expliquées par l’hypothèse nulle (c’est une définition quelque peu simpliste, mais, si vous voulez en lire plus sur la valeur de p et son interprétation, c’est un “rabbit-hole” très profond (Gómez‑de‑Mariscal et al. (2021), Nakagawa et Cuthill (2007))).
Donc, plus la valeur de p est petite, plus on devrait rejeter l’hypothèse nulle, dépendant de notre tolérance aux différents types d’erreurs. Parlant des types d’erreurs, en voici un petit rappel. Les erreurs de type I (\(\alpha\)) sont les chances de rejeter l’hypothèse nulle lorsqu’elle est vraie, donc un faux positif; voir une différence lorsqu’il n’y en a probablement pas. Les erreurs de type II (\(\beta\)) sont les chances d’accepter l’hypothèse nulle lorsqu’elle est fausse, donc un faux négatif; ne pas voir de différence lorsqu’il y en a probablement une.
Le seuil typique de 0.05 reflète le taux d’erreur de type I (ce n’est pas une équivalence exacte, mais c’est approximatif). Dans la recherche et le domaine des sciences naturelles, le standard d’acceptation d’erreur de type I est généralement de 5%, donc le seuil pour accepter ou refuser l’hypothèse nulle basée sur la valeur de p est 0.05. Ceci implique une multitude de nuances et de problèmes par soi-même, mais ce paradigme est difficilement confronté, même aujourd’hui.
Bref, personnellement, je ne recommande pas une solution, une alternative ou une façon de faire différente plus qu’une autre. Des personnes bien plus qualifiées ont déjà proposé plusieurs solutions face à ce problème: statistiques bayésiennes, nouvel indice de probabilité qui inclut la taille n, des degrés nuancés de significativité basés sur p au lieu d’un seuil unique, etc. (Gómez‑de‑Mariscal et al. (2021), Halsey (2019), Demortier (2007), Nakagawa et Cuthill (2007)). Ici mon but est simplement de présenter des problématiques et de faire en sorte que vous gardez en tête ces notions lors des analyses et des interprétations de vos résultats.
2.8.1 Échantillonnage aléatoire
Une des plus grosses assomptions dans la recherche est l’aspect aléatoire de l’échantillonnage. Ici est un exemple simple qui illustre la différence entre 2 échantillons aléatoires et deux échantillons hypothétiques qui représente les valeurs maximales et minimales de la population échantillonnée.
Montrer le code
library(readxl)
library(dbplyr)
library(agricolae)
library(performance)
library(viridis)
p <- read_xlsx("pval_files/P var ex.xlsx", 1) #importation
p$ECH <- as.factor(p$ECH) #mettre le facteur en facteur
ech2 <- sample(p$POP, 6, replace = F) #échantillonnage aléatoire
# pour la pérénité des données créées aléatoirement
ech2 <- c(34, 33, 34, 32, 29, 31)
pan <- lm(Values ~ ECH, data = p) #modèle linéaire
anova(pan) #résultats
HSD.test(pan, "ECH", group = TRUE, console = TRUE) #comparaison multiple
#pour les stats "automatique" avec "stat_compare_means"
mycomp <- list( c("Maximum", "Aléatoire"), c("Minimum", "Aléatoire"),
c("Maximum", "Minimum"), c("Aléatoire", "Aléatoire2"),
c("Maximum", "Aléatoire2"), c("Minimum", "Aléatoire2"))
#clean up avant le graphique
p2 <- dplyr::filter(p, ECH != "Moyenne")
p3 <- data.frame(
"Échantillons" = c(as.factor(rep("Population", 30)), p2$ECH,
as.factor(rep("Aléatoire2", 6))),
"Valeurs" = c(p$POP, p2$Values, ech2)
) #nouveau dataframe pour le graphique
p3$Échantillons <- with(p3, reorder(Échantillons, c(rep(1,30), rep(4,6), rep(5,6), rep(2,6), rep(3,6)))) #mettre en ordre les variables qu'on veutOn voit que le premier échantillon aléatoire est bien représentatif de la population, mais que le deuxième échantillon est significativement différent de la population. À la grande surprise de personne, les échantillons qui représentent les valeurs maximales et minimales sont très différents de la population.
Montrer le code
pan2 <- ggplot(p3, aes(x = Échantillons, y = Valeurs, fill = Échantillons)) +
geom_boxplot() +
labs(x = "Échantillons", y = "Distribution des échantillons") +
scale_y_continuous(breaks = seq(0, 40, 5)) +
stat_compare_means(aes(label = after_stat(p.signif)), label.y = 36,
method = "t.test", ref.group = "Population") +
stat_compare_means(comparisons = mycomp, label.y = c(41, 44, 40, 38, 39, 43),
method = "t.test", paired = T)+
ggtitle("Variation potentielle de l'échantillonnage") +
scale_fill_manual(values = plasma(6)) +
labs(fill = "Type d'échantillon", x = "Type d'échantillon") +
annotate("text", x = 1.15 , y = 36.3, label = "Comparaison avec la population:",
color = 'black', size = 4, fontface = "bold") +
annotate("text", x = 1.18 , y = 41, label = "Comparaisons entre échantillons:",
color = 'black', size = 4, fontface = "bold") +
theme_classic()+
theme(axis.text = element_text(size = 15, colour = "black"),
axis.title = element_text(size = 15, colour = "black"),
legend.text = element_text(size = 12, colour = "black"),
legend.title = element_text(size = 15, colour = "black"),
legend.background=element_blank(),
legend.position = "bottom")
pan2Ceci est un exercice simple qui peut être fait dans Excel comme de R/Rstudio. On assume systématiquement que les échantillons pris sont aléatoires et représentatifs de la population, mais à l’exception argumentative des méta-analyses, il n’y a aucune façon de le vérifier ou de le prouver.
Ça peut sembler décourageant comme notion, mais c’est simplement une chose à garder en tête lors de nos interprétations. Il ne faut pas oublier les nuances statistiques dans nos conclusions.
2.8.2 Effet de n
L’effet de la taille d’échantillonnage est un problème hautement documenté dans le domaine de la statistique, surtout dans le domaine biologique et biomédical (Gómez‑de‑Mariscal et al. (2021), Nakagawa et Cuthill (2007)). On illustre un exemple simple avec une situation hypothétique où on compare la longueur totale d’une espèce de poisson entre deux lacs. Une étude échantillonne 50 individus dans chaque lac, alors qu’une autre échantillonne 5 individus. Les populations sont exactement les mêmes entre les deux études, et pourtant, en changeant uniquement le n, on obtient des résultats différents.
Montrer le code
N <- read_xlsx("pval_files/nvar p ex.xlsx", 1) #importation
N$Lac <- as.factor(N$Lac) #factorisation
N$Sublac <- as.factor(N$Sublac) #factorisation
Nsub <- dplyr::filter(N, Sublt > 100) #filtration des données
mean(N[1:50,]$LT) #pour le fun
mean(N[51:100,]$LT)
lacan <- lm(LT ~ Lac, data = N) #modèle linéaire
anova(lacan) #résulats
lacansub <- lm(Sublt ~ Sublac, data = N) #modèle linéaire
anova(lacansub) #résulatsMontrer le code
plotn <- ggplot(N, aes(x = Lac, y = LT)) +
geom_boxplot(fill = c('#37a9e7', '#e77537')) +
labs(x = "Lac", y = "Longueur totale (mm)") +
scale_y_continuous(breaks = seq(60, 300, 20), limits = c(80,300)) +
annotate("text", x = 2 , y = 270, label = "n = 50",
color = 'black', size = 5, fontface = "bold") +
annotate("text", x = 2 , y = 260, label = "p = 0.0008",
color = 'black', size = 5, fontface = "bold") +
theme_classic() +
theme(axis.text = element_text(size = 15, colour = "black"),
axis.title = element_text(size = 15, colour = "black"),
legend.text = element_text(size = 12, colour = "black"),
legend.title = element_text(size = 15, colour = "black"),
legend.background=element_blank())
#plus facile a faire les deux séparement et ensuite les combiner
#à cause de la structure des données
plotnsub <- ggplot(Nsub, aes(x = Sublac, y = Sublt)) +
geom_boxplot(fill = c('#37a9e7', '#e77537')) +
labs(x = "Lac", y = "Longueur totale (mm)") +
scale_y_continuous(breaks = seq(60, 300, 20), limits = c(80,300)) +
annotate("text", x = 2 , y = 250, label = "n = 5",
color = 'black', size = 5, fontface = "bold") +
annotate("text", x = 2 , y = 240, label = "p = 0.4263",
color = 'black', size = 5, fontface = "bold") +
theme_classic() +
theme(axis.text = element_text(size = 15, colour = "black"),
axis.title = element_text(size = 15, colour = "black"),
legend.text = element_text(size = 12, colour = "black"),
legend.title = element_text(size = 15, colour = "black"),
axis.line.y = element_blank(),
axis.ticks.y = element_blank(),
axis.text.y = element_blank(),
axis.title.y = element_blank(),
legend.background=element_blank())
ggarrange(plotn, plotnsub)Ce qui découle de ce phénomène peut être extrêmement problématique, puisque c’est sur ce principe que le p-hacking existe. L’effet du n sur les résultats statistiques devrait nous faire douter des études avec des n extrêmement élevés et les interpréter en conséquence.
À cause des mêmes raisons, il est impératif de regarder plus loin que juste les différences statistiques des données en regardant aussi l’échelle de différence. Autrement dit, il est statistiquement intéressant de savoir s’il y a une différence ou non entre deux groupes, mais il est biologiquement important de savoir si cette différence va engendrer de réelles conséquences et des différences qui sont intéressantes au niveau scientifique et non seulement mathématique.
Par exemple, une différence statistiquement significative dans l’abondance relative d’une espèce entre deux sites peut être biologiquement très intéressante (5% vs 80%) ou complètement inintéressante (5.0% vs 5.5%). Les deux peuvent être autant significatives au point de vue statistique (ex. si p < 0.001), mais une situation est bien plus intéressante au point de vue écologique que l’autre. Il faut rapporter et considérer plus que juste la valeur de p, mais aussi ce que la différence voudrait dire au-delà des statistiques.
Bon, c’est assez sur les problèmes en stats, là on va faire des beaux graphiques (ou presque, on y arrive tranquillement pas vite).
2.9 Vérifications préanalyse
Avant toute analyse, il est important de vérifier plusieurs choses. C’est des fois long et plate, mais c’est nécessaire si on ne veut pas refaire toutes nos analyses parce qu’on a oublié une chose (comme la normalité) qui rend nos analyses et interprétations invalides.
Ici on présente quelques listes de vérification à valider avant de faire certaines analyses. Elles ne sont pas parfaitement exhaustives puisqu’il va toujours avoir un niveau de subjectivité lors de ce type de processus, mais les grandes lignes y seront pour assurer que les analyses qui sont faites soient au minimum statistiquement valide.
2.9.1 ANOVAs
2.9.2 Régression linéaire
2.9.3 Ordination
3 Exploration de base
Entre l’organisation de nos dataframes et la création de beaux petits graphiques, il est souvent bénéfique de faire une petite exploration des données de base, de voir de quoi ça à l’aire, et juste de mettre une simple image aux chiffres et nos fichiers. Ceci dépend des variables qu’on a et de notre question de recherche, alors la section est divisée en conséquence de ça.
Une des étapes préalables possibles, qui est indépendante du type et de la structure des données, est de vérifier la normalité de nos données. Il y a quelques tests possibles et on en présente indirectement dans la Section 6.1 et Section 7.1 avec la fonction check_model(), mais ici on va faire un test de Shapiro-Wilk pour valider la normalité d’une variable à la fois (non, pas ce Shapiro là, un beaucoup plus cool). Il existe aussi le test de Kolmogorov-Smirnov (non, pas ce Smirnov, un légèrement moins cool), mais on le présente pas ici, si vous voulez en lire plus, cette ressource est un bon point de départ: KS-test.
Shapiro-Wilk normality test
data: df[, 2]
W = 0.90974, p-value = 4.184e-06
Pour le fun, voici un exemple de “loop” avec l’opérateur “for”. C’est pratique pour tester rapidement toutes les variables (colonnes) pour la normalité et avoir les résultats de façon compacte. Mais faire des visualisations reste utile.
Montrer le code
[1] "Valeur de p de Shapiro-Wilk, Variable 1 : 4.18419167206342e-06"
[1] "Valeur de p de Shapiro-Wilk, Variable 2 : 8.26972865631847e-08"
[1] "Valeur de p de Shapiro-Wilk, Variable 3 : 4.76914594586927e-06"
[1] "Valeur de p de Shapiro-Wilk, Variable 4 : 0.00112429029390462"
[1] "Valeur de p de Shapiro-Wilk, Variable 5 : 0.000114662873583928"
[1] "Valeur de p de Shapiro-Wilk, Variable 6 : 0.000486478145966095"
Si on veut vérifier visuellement, un graphique de densité et un qqplot sont les meilleures façons de le faire. Ici le qqplot montre que les points suivent assez la ligne centrale pour ne pas trop s’inquiéter par rapport à la normalité.
Montrer le code
3.1 Variable nominale
Maintenant qu’on a survolé des explorations rapides et générales, passons à des idées un peu plus spécifiques. De boxplot à des histogrammes (ou des barplots pour ceux qui les aiment tant), il y a plusieurs options pour explorer visuellement à quoi ressemblerait nos données. En voici quelques exemples:
Montrer le code
3.2 Variable numérique
Pour des variables numériques, des scatterplots sont des représentations assez utiles. Avec des scatterplots, on peut rapidement voir s’il semble avoir une relation potentielle ou pas du tout (c’est toujours bien de le vérifier avec une corrélation et/ou une régression, mais ça peut donner une idée par où commencer).
Un autre exemple de loop pour faire des graphiques simples rapidement pour plusieurs variables.
Montrer le code
4 Exploration: PCAs
Les PCAs, “Principal Component Analysis”, sont des analyses qui permettent de visualiser de façon qualitative la relation entre un ou plusieurs variables et les données qui en découlent. Les PCAs sont un type d’ordination, c’est-à-dire que l’entièreté des données est orientée d’une façon à maximiser, ou aligner, la variation qui est observable dans les données. Autrement dit, c’est une projection en n-dimensions des données.
Il existe plusieurs librairies et fonctions qui peuvent servir à faire des PCAs et des graphiques pour les visualiser. Ici, on se concentre sur les librairies affichées ci-dessous et leurs fonctions principales plus bas.
4.1 Fonction principale
La fonction qu’on présente ici peut automatiquement normaliser et remettre sur la même échelle les différentes données et variables. Ceci est souvent nécessaire avant toute ordination, surtout des PCAs. Les NMDS (non-metric multidimensionnal scaling) sont moins sensibles à des ordres de grandeurs différentes et sont davantage utiles pour comparer des données environnementales avec d’autres types de données qui sont très différentes par leur nature (concentrations, abondances d’espèces, températures, etc.). Les NMDS ne sont pas abordés pour l’instant, mais les principes d’ordination et de graphiques sont les mêmes.
La fonction principale utilisée ici est prcomp(). Il existe aussi princomp() qui peut être utilisée, mais la fonction est quelque peu plus capricieuse et donne les mêmes résultats pour les mêmes données. Si vous voulez en lire plus sur les différences, on vous recommande de lire Learn-PCA.
Ici, on a généré un tableau avec des données aléatoires pour illustrer les exemples d’analyses et de graphiques, et ce, pour la majorité des exemples utilisés à travers le document au complet. Pour les curieuses et curieux de la structure des données des exemples, tous les dataframes utilisés sont en annexe (Section 8.2).
4.2 Évaluation des dimensions
Avant de passer à la création de graphiques pour visualiser la PCA elle-même, il faut évaluer le nombre de dimensions optimal à notre PCA. Il existe deux types de graphique qui nous permet de vérifier le nombre de dimensions qu’on devrait garder. Après tout, une PCA est une projection multidimensionnelle des données, elle va au-delà des 3 dimensions que l’on connait. Mais pas toutes les dimensions sont faites de façon égale.
Les modèles Broken Stick nous permettent de voir, en quelque sorte, la performance des dimensions. Les barres représentent l’inertie (une mesure de variance) de chaque dimension et la ligne brisée (broken stick) représente l’inertie théorique de données distribuées aléatoirement. Donc, on peut garder les dimensions qui ont une inertie plus élevée que le broken stick. Dans ce cas-ci, on devrait en garder qu’une seule.
Les screeplots opèrent sur les mêmes principes, représentant la proportion de la variance dans les données qui est expliquée par chaque dimension. Ici on voit que la première dimension explique plus de 40% de la variance et que la deuxième dimension en explique moins de 18%. C’est une baisse relativement élevée entre ces dimensions. Il y a une certaine subjectivité dans le nombre de dimensions à garder, tout dépend des données utilisées. La première dimension pourrait expliquer 99% de la variance, alors que, dans un autre cas, les 4 premières dimensions expliqueraient près de 25% de la variance chacune.
Les broken sticks et les screeplots facilitent et simplifient l’interprétation d’une PCA et aide à réduire le nombre de dimensions pertinentes, mais ces graphiques ne peuvent pas prendre de décision pour vous. C’est à vous de décider avec vos données du nombre de dimensions qui sont pertinentes.
4.3 Graphiques
On a créé notre objet PCA avec prcomp() et on a évalué le nombre de dimensions pertinentes, maintenant c’est le temps de représenter notre PCA.
Il existe trois types de graphiques qu’on peut faire avec une PCA:
- Individus
- Variables
- Biplot
Il n’y a pas de graphique qui est meilleur qu’un autre, ils représentent tous des informations différentes à des niveaux de clarté différents. Ici on présente les trois avec la famille de fonctions fviz_pca() qui utilise le système de ggplot (il y a d’autres façons de faire des graphiques de PCA, mais le système de ggplot est bien meilleur que les alternatives).
Les graphiques d’individus représentent les individus sous forme de points, souvent identifiés avec leur valeur, selon deux dimensions calculées par la PCA.
Les graphiques de variables représentent les variables sous forme de flèches, souvent identifiés avec leur nom, selon deux dimensions calculées par la PCA.
Les biplots combinent les deux graphiques en un seul. Il a l’avantage de combiner les informations des individus et des variables, mais il peut rapidement devenir trop chargé et difficile à lire.
4.3.1 Par défaut
Les fonctions fviz_pca_ind(), fviz_pca_var() et fviz_pca_biplot() utilisent l’objet créé par prcomp() directement et peuvent faire des graphiques simples rapidement. Les deux dimensions utilisées sont toujours les deux premières dimensions, mais on peut spécifier les dimensions à utiliser au besoin.
4.3.2 Personnalisé
Avec les mêmes fonctions de base pour les graphiques, on peut ajuster une multitude de paramètres. Ici on présente des biplots personnalisés de façon relativement simple et de façon plus complexe. Toutefois, les trois types de graphiques utilisent les mêmes paramètres et la même syntaxe, alors ils sont facilement interchangeables.
Pour la version simple, on a changé la couleur des flèches et du texte des variables (col.var = “red4”), on a spécifié les types de géométrie pour les individus et les variables (geom = c(“point”, “text”)), on a changé le type de point et son remplissage basé sur la variable “temps” (pointshape = 21, fill.ind = df$temps) et on a utilisé un gradient de couleur personnalisé (gradient.cols = mako(100, direction = -1, end = 0.8)).
Avec ces ajustements-là, on peut mieux voir la distribution des individus tout en gardant la direction de variation des variables.
Pour la version complexe, on a regroupé les variables en groupes et on a ajusté la couleur des variables pour refléter ces groupes-là (col.var = colnames(df)[1:7]).
On peut aussi ajouter des ellipses de probabilités autour de certains groupes de points. Ce genre de représentation est davantage utile lorsqu’il y a une variable catégorique dans les données (ex. traitement d’échantillon, stations, etc.). Pour l’exemple ici, on a simplement créé un double des données et ajouté une variable “Station” pour représenter une catégorie de façon aléatoire. Ici on utilise aussi la sous-fonction habillage pour colorier et remplir les groupes avec de couleurs personnalisées. Cet argument est très utile pour rapidement visualiser des groupes spécifiés et permet d’automatiser plusieurs aspects liés aux couleurs du graphique.
5 Exploration: Matrices de corrélations
Encore dans le contexte d’exploration de données, il est souvent pratique de faire des matrices de corrélations. À ne pas confondre avec des régressions, ça reste des analyses similaires, effectuées sur des variables numériques (souvent continues), contrairement aux PCAs qui peuvent inclure des variables catégoriques (nominales ou ordonnées).
Les matrices de corrélations permettent d’aider à déterminer des patrons de corrélations entre une multitude de variables. C’est particulièrement utile lorsqu’on veut comparer plusieurs variables qui appartiennent à un groupe versus d’autres variables qui appartiennent à un groupe différent (des concentrations de molécules d’une famille vs les concentrations de molécules d’une autre famille). Ou bien à des variables qui intersectent entre des catégories plus larges (abondances d’espèces qui représentent un certain gradient écologique).
5.1 Types de corrélation
Avant de représenter graphiquement la matrice, et avant de faire la matrice même, il est important de faire la distinction entre les deux types de corrélations les plus utilisées: Pearson et Spearman (désolé Kendall, je parle pas de ton \(\tau\)).
La grande différence entre ces deux calculs de corrélations est que Pearson utilise la valeur même d’une donnée alors que Spearman utilise le rang de la donnée par rapport au reste. Concrètement, ça veut dire que le Pearson est généralement plus utilisé pour représenter et calculer des relations linéaires (de façon paramétrique), alors que Spearman est davantage utilisé pour des relations non-linéaires ou avec des données distribuées non-normalement (de façon non-paramétrique).
\[r_{pearson} = \frac{(x-\mu_{x})(y-\mu_{y})}{\sigma_{x}\sigma_{y}}\]
\[\rho_{spearman} = 1 - \frac{6\Sigma(R[x_{i}]-R[y_{i}])}{n(n^2-1)}\]
Il est pratique de calculer les deux types de corrélations lorsqu’on ne connait pas nécessairement la nature de la relation entre toutes les variables qui seront utilisées dans la matrice. Heureusement, le calcul n’est pas fait manuellement, c’est simplement un argument spécifié avec les fonctions utilisées.
5.2 Matrices
Pour la création de la matrice de corrélation de base, on utilise la fonction de base cor(). Pour créer une matrice avec les valeurs de p associées avec chaque valeur de r ou \(\rho\), on utilise cor.mtest() qui provient de la librairie “corrplot”.
Les matrices peuvent être créées assez facilement avec les fonctions respectives où on peut simplement spécifier nos données et le type de corrélation à utiliser.
5.3 Graphiques
La fonction corrplot() nous permet de visualiser facilement la matrice de corrélation créée par cor(). Cette fonction peut être personnalisée à un degré surprenant. Quoique corrplot() n’utilise pas le système de ggplot comme le fait fviz_pca(), il y a un niveau équivalent de contrôle pour tous les paramètres. Voici un premier exemple avec la fonction par défaut.
5.3.1 Par défaut
Toutes les variables sont affichées simultanément sur les deux axes de la matrice. L’intersection de deux variables affiche une couleur et une taille de cercle associée au coefficient de corrélation (r ou \(\rho\)). À noter que ces valeurs ne sont pas des valeurs de \(R^2\), elles sont les coefficients de corrélations où \(\sqrt(R^2) = r\) et \(\sqrt(R^2) = \rho\).
Plus la couleur est foncée et le cercle est gros, plus la corrélation est forte. Plus la couleur est pâle et le cercle petit, plus la corrélation est faible. Par défaut, il est difficile de déterminer visuellement si les différentes corrélations sont significatives ou pas, d’où l’importance de faire une matrice des valeurs de p qu’on va pouvoir utiliser plus loin.
5.3.2 Simple
On peut spécifier d’abord le type (“lower”, “upper”, ou “full”) et la présence de la diagonale avec diag pour éliminer les coefficients redondants et ensuite la méthode de représentation des coefficients (ici “color”). On peut aussi changer les couleurs du grillage et du texte ainsi que l’espace entre le texte des variables et la matrice. Maintenant on obtient ceci.
Montrer le code
Si on ajoute notre matrice de valeurs de p et on change insig pour “p-value”, on va maintenant afficher la valeur de p des cases qui sont non-significatives selon un seuil spécifié par sig.level (0.05 par défaut). Il y a plusieurs façons de visualiser les relations non-significatives avec l’argument insig.
Montrer le code
Ce qui est aussi très pratique est d’afficher les valeurs de coefficients de corrélations dans les cases. Ça permet de comparer l’intensité des corrélations entre elles plus facilement qu’avec juste la couleur et/ou la taille d’une forme.
Montrer le code
On peut aussi associer un symbole au niveau de significativité. Ceci permet de rapidement voir quelles relations sont significatives ou pas. On peut aussi spécifier le titre que l’on veut. Mais attention aux marges!
Montrer le code
corrplot(dfcor, method = "square", type = "lower", diag = F,
mar=c(0,0,0,0),
title = "Symboles significatifs",
tl.offset = 0.2, tl.col = "black",
number.digits = 2, p.mat = dfcorpv$p,
sig.level = c(0.001, 0.01, 0.05), insig ='label_sig',
pch.col = "#2e0000", pch.cex = 1,
number.cex = 0.9, addgrid.col = 'black')5.3.3 Complexe
Ici on va explorer différents paramètres de couleur et aussi utiliser une fonction corrplot() modifiée pour permettre une utilisation assez niche de certains paramètres.
D’abord, on peut changer le gradient de couleur par défaut via l’argument “col”. Ici, on utilise le package “viridis” mentionné dans la Section 2.7. La méthode “ellipse” de la fonction permet de visualiser l’intensité de la corrélation de façon à refléter à quoi ressemblerais le nuage de point (scatter plot) qui découlerait de la régression linéaire entre les variables. Aussi, l’option “blank” de l’argument insig retire les éléments des cases qui ne sont pas significatives. Ceci est utilisé pour attirer l’attention que sur les relations significatives rapidement (mais ne permets plus de distinguer l’intensité de la significativité).
Montrer le code
Plus sur les couleurs, c’est aussi possible de mélanger deux gradients de couleurs différents (un gradient pour les relations positives, un pour les négatives, par exemple). Ça permet d’avoir une plus grande diversité de couleur pour différencier entre une plus grande quantité de valeurs, mais pourrait aussi surcharger le graphique avec trop de couleur, alors à utiliser avec caution.
Le prochain graphique utilise la version modifiée de la fonction, nommée “corrplot2()” (oui, très originale, je sais). Cette fonction se trouve dans le script “Customs_Funcscopy.R” (oui, très originale encore, je sais). Cette fonction peut être utilisé de toutes les façons que la fonction originale le peut, mais avec un ajout. Normalement, lorsqu’un symbole associé aux valeurs de p est affiché, il est superposé sur les valeurs des coefficients, ce qui rend la lecture du graphique quasi impossible. Mais la fonction “corrplot2()” ajuste l’emplacement des symboles de significativité pour être plus haut dans la case, ce qui permet de bien lire les symboles et les coefficients. Pour utiliser la fonction, il faut simplement utiliser la fonction source() et spécifier l’emplacement du script avec la fonction.
Montrer le code
corrplot(dfcor, method = "ellipse", type = "lower", diag = F,
addCoef.col = "black", mar=c(0,0,2,0),
title = "Avec Corrplot",
tl.offset = 0.2, tl.col = "black",
number.digits = 2, p.mat = dfcorpv$p,
sig.level = c(0.001, 0.01, 0.05), insig ='label_sig',
pch.col = "#2e0000", pch.cex = 1,
number.cex = 1, addgrid.col = 'black',
col = c(magma(256, begin = 0.3, end = 0.95),
viridis(256, begin = 0.95, end = 0.3))
)Montrer le code
#source("Customs_Funcscopy.R")
corrplot2(dfcor, method = "ellipse", type = "lower", diag = F,
addCoef.col = "black", mar=c(0,0,2,0),
title = "Avec Corrplot2",
tl.offset = 0.2, tl.col = "black",
number.digits = 2, p.mat = dfcorpv$p,
sig.level = c(0.001, 0.01, 0.05), insig ='label_sig',
pch.col = "#2e0000", pch.cex = 1,
number.cex = 0.9, addgrid.col = 'black',
col = c(magma(256, begin = 0.3, end = 0.95),
viridis(256, begin = 0.95, end = 0.3))
)Par défaut, la fonction corrplot(), peu importe le type, montre toutes les intersections entre toutes les variables. Mais parfois on veut juste montrer les corrélations entre deux catégories de variables, ou encore montrer les corrélations entre quelques-unes de nos variables et tout le reste. Pour accomplir cela, on peut spécifier les lignes et colonnes de la matrice de corrélation à utiliser. Attention, la diagonale doit être présente et le type doit être “full” pour ne pas se retrouver avec une matrice manquant la moitié des cases voulues. Il faut aussi spécifier les mêmes lignes et colonnes pour la matrice des valeurs de p si elle est utilisée, les deux matrices doivent avoir la même taille.
Montrer le code
corrplot2(dfcor[1:4,c(1,5:7)], method = "ellipse",
type = "full", diag = T,
addCoef.col = "black", mar=c(0,0,2,0),
title = "Matrice Tronquée",
tl.offset = 0.2, tl.col = "black",
number.digits = 2, p.mat = dfcorpv$p[1:4,c(1,5:7)],
sig.level = c(0.001, 0.01, 0.05), insig ='label_sig',
pch.col = "#2e0000", pch.cex = 1,
number.cex = 0.9, addgrid.col = 'black',
col = c(magma(256, begin = 0.3, end = 0.95))
)6 ANOVAs
Maintenant qu’on a exploré les données, souvent, on veut regarder de plus près certaines variables qui seraient plus intéressantes ou qui donneraient plus d’informations. Une ANOVA “Analysis Of Variance”, malgré son nom, est une analyse qui compare les moyennes entre des groupes ou des catégories. Elle permet de déterminer si deux (ou plus) groupes sont significativement différents l’un de l’autre. L’ANOVA seule n’est pas capable de dire quel groupe varie dans quelle direction (s’ils sont différents) et, dans le cas de plus de 2 groupes, que ça soit 3 ou 17, l’ANOVA ne distingue pas quels groupes sont différents de tel autre groupe (puisque, parmi 3 groupes, il pourrait avoir un seul qui est différent des deux autres, mais l’ANOVA va simplement dire qu’il existe une différence, pas quel groupe est différent).
Bref, on va explorer ensemble les fonctions et analyses de bases, et par la suite aussi montrer des analyses qui, elles, permettent de distinguer quels groupes sont différentes des autres et représenter graphiquement le tout.
6.1 Fonction principale
Les ANOVAs tombent dans la catégorie de modèle linéaire, alors on va utiliser la fonction lm() pour le modèle lui-même et pour tirer les informations qu’on veut, on va utiliser anova() et, pour vérifier les postulats, on utilise check_model() du package “performance”.
La fonction check_model() est extrêmement utile pour valider les postulats de plusieurs analyses, pas juste les ANOVAs. Ce qui est pratique également est le texte sous les titres des différents graphiques qui indiquent à quoi devrait ressembler chaque section. Aussi, si une donnée ou variable est une donnée aberrante (“outlier”), elle va être coloriée en rouge pour la faire ressortir visuellement. Dans notre cas, les postulats semblent tous bien respectés.
Montrer le code
| Df | Sum Sq | Mean Sq | F value | Pr(>F) | |
|---|---|---|---|---|---|
| Traitement | 2 | 22321243 | 11160621.68 | 152.5169 | 0 |
| Residuals | 297 | 21733359 | 73176.29 | NA | NA |
Le tableau de résultat de l’ANOVA indique la présence d’une différence significative entre les traitements. Mais, comme expliquer plus haut, ça ne montre pas quels traitements sont différents. Donc, on va passer aux comparaisons multiples.
6.2 Comparaison multiple
Il existe plusieurs types de comparaisons multiples, mais généralement le HSD de Tukey est suffisant. Ici, on utilise le package “emmeans” et sa fonction principale aussi nommée emmeans().
$emmeans
Traitement emmean SE df lower.CL upper.CL
A 321 27.1 297 268 374
B -160 27.1 297 -214 -107
C 481 27.1 297 428 535
Confidence level used: 0.95
$contrasts
contrast estimate SE df t.ratio p.value
A - B 481 38.3 297 12.585 <0.0001
A - C -160 38.3 297 -4.195 0.0001
B - C -642 38.3 297 -16.780 <0.0001
P value adjustment: tukey method for comparing a family of 3 estimates
Dans la section “contrasts” de la portion inférieure du résultat de emmeans(), on voit les valeurs de p associées pour chaque comparaison des traitements. On voit donc que, dans notre cas, les trois traitements sont tous différents l’un de l’autre. On va garder cette info pour nos graphiques.
6.3 Graphiques
Ici on utilise le système de ggplot. C’est le standard en or de tous graphiques dans R et Rstudio. Il y a déjà une quantité incroyable de tutoriels, de documentations et d’exemples sur tous les aspects et les utilités de ce merveilleux outil. Alors, on ne va pas parler de long et en large, mais plutôt rester spécifique aux graphiques pertinents pour représenter les analyses qu’on présente. Pour en explorer plus, je recommande de commencer ici ggplot2.
Pour des ANOVAs, les boxplots sont parmi les représentations les plus intuitives pour représenter différentes catégories d’une variable nominale. Il existe aussi plusieurs variations des boxplots, comme les violons (ou même des barplots) qui sont quelque peu plus complexes (ou trop simples, comme les barplots), mais présentent une meilleure représentation visuelle des données lorsqu’on comprend leur nature (ou une pire représentation dans le cas des barplots).
À partir des paramètres de base, on peut spécifier l’échelle de l’axe vertical avec scale_y_continuous(), spécifier les couleurs désirées avec fill et ajouter des barres d’erreurs basées sur les quantiles avec stat_boxplot().
On peut aussi assigner les couleurs pour chaque groupe différent et spécifier un gradient de couleur désiré. Ceci ajoute une légende automatiquement qu’on peut retirer à travers le thème. On peut aussi montrer le “notch”, qui aide à mieux voir la médiane des distributions des données.
Si on veut ajouter les résultats des comparaisons multiples, on peut facilement l’ajouter en texte soit via annotate() ou avec geom_text(). Il existe des façons d’automatiser l’inclusion des résultats d’un test de Tukey sur un graphique ggplot, mais ces méthodes impliquent souvent la création de fonctions et sont difficiles à implémenter. Le faire manuellement via l’ajout de texte sur le graphique est bien plus rapide et efficace et permet de mieux contrôler et ajuster l’apparence et l’endroit où apparaît la classification désirée des groupes significativement différents.
Toutefois, si vous voulez ajouter les valeurs de p d’une analyse de comparaison de moyenne (que ce soit ANOVA ou un test de t) la fonction stat_compare_means() utilisée dans la Section 2.8 peut être une belle option.
Les violons peuvent être pratiques pour bien visualiser la distribution de données, avec ou sans quartiles. La géométrie des violons est quand même bien différente de celles des boxplots. D’abord, si le “trim” est mis à “False”, les limites de l’axe vertical ne seront plus les mêmes. Ensuite, on peut ajouter la distribution des points avec geom_jitter(), mais cela sert souvent à peu, puisqu’on voit déjà la distribution des données via la largeur des violons. Aussi, il n’y a pas de quartiles par défaut, si on veut les représenter, il faut les spécifier, mais cela nous permet plus facilement de spécifier des quantiles au-delà des quartiles standards. Le reste des paramètres en grossièrement semblable, le tout reste un objet ggplot après tout.
6.4 Deux Facteurs
Plus haut, on travaille uniquement avec un seul facteur, un seul type de groupe, le “Traitement”. Mais il arrive souvent qu’un à plus qu’un seul facteur, soit des sexes d’individus et leur habitat, soit des traitements expérimentaux qui font varier deux facteurs en même temps, comme la salinité et la température de l’eau ou bien d’autres designs expérimentaux.
Ici le design expérimental fait en sorte que les deux facteurs sont croisés, c’est-à-dire que les deux influencent toutes les données en même temps de façon à avoir des données qui ont deux sources de variations simultanément. Dans le cas de facteurs croisés, on doit prendre en compte l’interaction de l’effet de la “condition” et du “traitement” sur nos données. Ça semble compliqué, mais, dans R, on a juste besoin d’un seul symbole. Pour des facteurs indépendants, dans le modèle linéaire créé par lm() on peut utiliser un “+” entre les variables explicatives. Mais pour de facteurs croisés, on va utiliser le symbole “*” pour dire à lm() qu’on veut l’effet des facteurs et l’interaction entre les facteurs. Il pourrait y avoir une situation où on veut juste l’interaction et non l’effet des facteurs directement, dans ce cas rare, on va utiliser “:” entre les variables. Dans R, ça va ressembler à ça.
Les fonctions de bases sont essentiellement les mêmes, avec quelques différences. D’abord, l’utilisation de lm(), anova() et de check_model() pour les postulats est la même (sauf pour les symboles mentionnés plus haut dépendant du design expérimental). Par contre, emmeans() devient un peu lourd à interprété tel quel dû aux interactions entre les deux facteurs (surtout avec beaucoup de groupes à l’intérieur des facteurs). On peut donc faciliter l’interprétation avec la fonction cld() du package “multcomp” (qui est initialisé avec le package “emmeans”).
| Traitement | Condition | emmean | SE | df | lower.CL | upper.CL | .group | |
|---|---|---|---|---|---|---|---|---|
| 5 | B | 2 | -234.66790 | 30.89252 | 294 | -295.4664 | -173.86939 | a |
| 2 | B | 1 | -86.30114 | 30.89252 | 294 | -147.0997 | -25.50262 | b |
| 1 | A | 1 | 172.60228 | 30.89252 | 294 | 111.8038 | 233.40079 | c |
| 3 | C | 1 | 258.90341 | 30.89252 | 294 | 198.1049 | 319.70193 | c |
| 4 | A | 2 | 469.33580 | 30.89252 | 294 | 408.5373 | 530.13431 | d |
| 6 | C | 2 | 704.00370 | 30.89252 | 294 | 643.2052 | 764.80221 | e |
Le lettrage associé aux groupes nous permet d’identifier rapidement les groupes qui sont différents des autres. Ici, tous les groupes créés par les deux facteurs (traitement et condition) sont différents, à l’exception du groupe A1 et C1.
Avec cette information, on peut faire un graphique pour les résultats qui ressemblerait à ceci.
7 Régressions simples
Les régressions simples peuvent être utilisées dans la même capacité que les ANOVAs, pour explorer la relation plus spécifiquement entre 2 variables (ou potentiellement plus) lorsque ce sont des variables numériques, habituellement continues.
Ici on présente des régressions linéaires et non-linéaires simples et leurs représentations graphiques avec le système de ggplot.
7.1 Linéaires
Les régressions linaires sont les plus simples et utilisent la même fonction de base que les ANOVAs pour créer le modèle, soit lm(). Toutefois, pour visualiser les résultats, on utilise la fonction summary(). Aussi, il est important de ne pas oublier les postulats encore avec check_model().
Call:
lm(formula = Variable1 ~ Variable2, data = dfs2)
Residuals:
Min 1Q Median 3Q Max
-684.6 -249.8 -109.9 179.3 1362.7
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 172.81159 24.46965 7.062 1.16e-11 ***
Variable2 0.11053 0.03027 3.652 0.000308 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 376.2 on 298 degrees of freedom
Multiple R-squared: 0.04283, Adjusted R-squared: 0.03962
F-statistic: 13.34 on 1 and 298 DF, p-value: 0.0003076
Le tableau est similaire à celui produit par anova(), mais avec des légères différences. Les sections auxquelles il faut porter attention sont les valeurs de p des coefficients (“Pr(>|t|)”) et les valeurs de \(R^2\) affichées vers le bas des résultats.
“(Intercept)” réfère à l’abscisse à l’origine du modèle et la deuxième ligne, avec la variable en x réfère à la pente du modèle. Donc, les valeurs de p qui sont associés à chacune indiquent que l’abscisse à l’origine est différente de 0 (ce qui est peu informatif) et que la pente du modèle est aussi différente de 0 (ce qui est beaucoup plus informatif).
Maintenant, c’est difficile de bien visualiser ces données ressemblent à quoi exactement. Donc, évidemment, c’est le temps de faire un graphique.
Ce qui est amusant du système de ggplot est le fait qu’on peut ajouter des résultats d’analyses statistiques directement dans le graphique de façon automatisée. On peut le faire manuellement sans trop de problèmes en ajoutant des annotations qui on a fait avec les comparaisons multiples (Section 6.2), mais c’est pratique avoir une option automatisée.
Si on travaille avec un grand jeu de données, et qu’en plus il y a des facteurs (catégorie) dans nos données en plus des variables continues, on peut facilement les combiner ensemble de façon compacte. On peut d’abord spécifier des couleurs différentes pour chaque facteur et, si on veut évaluer plusieurs paires de variables, on peut juxtaposer les graphiques ensemble avec ggarrange() du package “ggpubr”.
Même avec deux facteurs, il y a plusieurs éléments esthétiques de ggplot qu’on peut modifier selon des facteurs. Ici, les couleurs sont déterminées par le traitement, alors que la forme des points est déterminée par la condition.
7.2 Transformation logarithme
Souvent les données avec lesquelles on travaille ne sont pas parfaites et parfois ne sont pas exactement linéaires. Une façon de faire face à ce problème est de faire une transformation logarithmique avec nos données. Ça peut faire peur, mais c’est remarquablement simple et peut être fait à l’intérieur des fonctions présentées jusqu’à maintenant.
Pour le modèle linéaire, évidemment, on doit avoir des données linéaires. Si on utilise des données non-linéaires pour faire le modèle directement, lorsqu’on regarde les postulats, dit simplement, c’est le bordel.
Montrer le code
Call:
lm(formula = Variable2 ~ Variable1, data = dflog)
Residuals:
Min 1Q Median 3Q Max
-380009 -373694 -297912 -2685 4765729
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 380212.264 84231.716 4.514 1.77e-05 ***
Variable1 -4.668 4.371 -1.068 0.288
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 768800 on 98 degrees of freedom
Multiple R-squared: 0.0115, Adjusted R-squared: 0.001417
F-statistic: 1.141 on 1 and 98 DF, p-value: 0.2882
Mais lorsqu’on transforme les données en log avec la fonction log10() ou log2(), soudainement, comme par magie, les postulats sont mieux respectés. Ceci peut être fait dans la fonction directement, ou un nouveau dataframe peut être créé issu de la transformation. Les deux méthodes sont équivalentes et possèdent des avantages et des désavantages.
Montrer le code
Call:
lm(formula = log10(Variable2) ~ log10(Variable1), data = dflog)
Residuals:
Min 1Q Median 3Q Max
-4.225 -1.353 0.004 1.322 2.654
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.4694 0.3799 11.764 <2e-16 ***
log10(Variable1) -0.1427 0.1283 -1.112 0.269
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 1.565 on 98 degrees of freedom
Multiple R-squared: 0.01246, Adjusted R-squared: 0.002381
F-statistic: 1.236 on 1 and 98 DF, p-value: 0.2689
Graphiquement, la différence est encore plus flagrante.
Pour s’amuser, si on considère des facteurs, on peut observer des différences entre ceux-ci également, et, soudainement, les relations deviennent plus intéressantes (et significatives, presque comme si j’avais fait exprès).
7.3 Logistiques
La régression logistique est une variante unique de la régression. C’est très utile pour des données binaires (0 et 1), comme des données de présence-absence d’espèces selon une variable environnementale quelconque.
Ici on abandonne la fonction lm() puisque nous sommes loin de la linéarité et les transformations ne vont pas linéariser les données non plus. On est dans une distribution de donnée binomiale, pas normale (techniquement c’est pas nos données qui sont binomiales, mais la probabilité d’avoir soit 1 ou 0 dans nos données qui est binomiales, en réalité, nos données binaires ont une distribution Bernoullienne, mais un moment donné ça va faire là, ce qui nous intéresse c’est la probabilité d’avoir 1 ou 0 de toute façon, pas le 1 ou 0 directement, et ça c’est vrai dans pas mal tous les contextes de biologie et des domaines associés). Donc, on va utiliser la fonction glm(), conçue pour des modèles linéaires généralisés (linéaire étant très lousse comme terme ici). Cette fonction est utile pour toutes sortes de distribution de données, comme les distributions poisson ou gamma, pas juste des distributions binomiales. Les résultats et les postulats sont visualisés de la même façon par contre.
Montrer le code
Call:
glm(formula = Présence ~ Température, family = "binomial",
data = dfbin)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -1.38010 0.66100 -2.088 0.0368 *
Température 0.18937 0.05803 3.264 0.0011 **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 64.924 on 50 degrees of freedom
Residual deviance: 49.673 on 49 degrees of freedom
AIC: 53.673
Number of Fisher Scoring iterations: 5
Graphiquement ça ressemble à quoi? Avec ggplot et la fonction stat_smooth(), à laquelle on peut spécifier la méthode de modélisation et le type de distribution, ça va donner quelque chose comme ça:
Pour s’amuser, si on voulait montrer les abondances de deux espèces en même temps, on peut le faire si on considère l’espèce comme un facteur.
8 Annexes
8.1 Définitions
- Argument
-
Élément d’une fonction à être spécifié qui aide à préciser une facette ou un aspect spécifique de la fonction pour que le résultat produit soit valide et exact. Ex: dans la fonction ggarrange() le nombre de lignes de graphique est spécifié via l’argument “nrow” avec une valeur numérique (1,2,3,etc.).
- Corrélation
-
Proportion de variation entre deux variables qui est similaire ou identique, c’est-à-dire la proportion des données qui varient ensemble ou dans la même direction (positif/négatif). Ne représente pas automatiquement un lien de causalité, mais la causalité peut y être inférée.
- Distribution (de données)
-
Arrangement des données basé sur la fréquence qu’apparaît chacune des valeurs possibles. Ex: Distribution normale (gaussienne) où la majorité des données se retrouvent proches de la moyenne et plus la distance de la moyenne est grande, moins il y a de données qui s’y retrouve.
- Dataframe
-
Type d’objet dans R/Rstudio sous forme de tableau, normalement avec des noms de colonnes et des données numériques, factorielles, ou nominales dans les cellules du tableau.
- Facteur
-
Variable nominale, généralement catégorique, qui influence ou affecte une autre variable, souvent numérique continue. Ex: La région d’échantillonnage comme facteur de production de chlorophylle selon la température. (Température: variable continue; Région: facteur).
- Fonction
-
Opération de programmation qui utilise des arguments (“inputs”) qui sont spécifiés par l’utilisateur et qui produit un résultat (“output”) comme un objet spécifique, une valeur, un graphique, etc.
- Librairie (“package”)
-
Ensemble de fonctions dans R/Rstudio qui servent à un but commun ou qui sont utiles dans un certain contexte pour une tâche ou une série de tâches.
- Paramétrique
-
Une analyse ou une approche statistique qui prend en compte les paramètres (moyenne, variance, erreur standard) d’une population et/ou d’un échantillon lors des calculs; à l’opposé d’une analyse non-paramétrique qui n’utilise pas les paramètres dans les calculs. Ex: ANOVA utilise la variance pour comparer des groupes; Kruskal-Wallis utilise le rand des données pour comparer des groupes.
- Parcimonie
-
Principe par lequel la simplicité est priorisée dans la modélisation pour des performances égales ou similaires. Un minimum de variables explicatives est davantage utile que le maximum de variables explicatives.
- Postulat
-
Condition préalable qui doit être respectée pour qu’une analyse statistique soit juste et exacte, pour ne pas avoir d’erreur introduite lors des calculs, souvent basés sur la structure des données ou des variables. Ex: la normalité des résidus pour l’ANOVA.
- Régression
-
Relation entre deux variables numériques pouvant être décrite par une fonction mathématique. Ex: régression linéaire du genre \(y = mx + b\)
- Transformation (de donnée)
-
Modification de la distribution de données via une opération mathématique qui change les valeurs systématiquement. Ex: Transformation logarithme, prendre le \(log()\) des valeurs au lieu des valeurs mêmes.
- Variable numérique
-
Variable représentée par des chiffres, qui peut être contée.
- Variable continue
-
Variable avec des valeurs numériques comportant des nombres réels (\(\mathbb{R}\)), qui ne sont pas restreints aux nombres des chiffres entiers (\(\mathbb{Z}\)). Ex: La température °C.
- Variable discrète
-
Variable avec des valeurs numériques comportant uniquement des nombres entiers (\(\mathbb{Z}\)), qui n’incluent pas de décimales ou de fractions. Ex: le nombre d’individus d’une espèce.
- Variable nominale
-
Variable représentée par des lettres et/ou des mots, souvent référant à un groupement quelconque.
- Variable ordinale
-
Variable nominale avec un ordre naturel prédéterminé. Ex: élevé, moyen, bas.
- Variable catégorique
-
Variable nominale référant à une catégorie parmi une autre ou plusieurs autres. Ex: espèce A, espèce B, espèce C, …
8.2 Structure des données
Pour les tableaux complets, voir les scripts inclus dans le dossier du document.
| temps | Variable1 | Variable2 | Variable3 | Variable4 | Variable5 | Variable6 |
|---|---|---|---|---|---|---|
| 1 | 1.00031 | 100.3660 | 1.0824 | 6.938574 | 52.1383608 | 2.4324804 |
| 2 | 2.88990 | 407.3494 | 108.7878 | 6.633824 | 39.8412603 | 1.8915492 |
| 3 | 27.67320 | 1809.8954 | 254.5626 | 1.324532 | 34.3865538 | 5.3870787 |
| 4 | 16.89164 | 1355.1773 | 400.2592 | 5.353902 | 8.5822233 | 7.8279993 |
| 5 | 24.67975 | 1683.5962 | 214.4405 | 2.447417 | 37.0944294 | 0.5242695 |
| 6 | 24.54582 | 1855.5210 | 472.5984 | 10.774190 | 55.1324802 | 6.3218199 |
| 7 | 64.84576 | 674.0552 | 296.7524 | 10.325360 | 52.4765449 | 6.8219672 |
| 8 | 66.35392 | 1472.2384 | 715.4704 | 3.807187 | 11.7972035 | 3.4049443 |
| 9 | 37.58841 | 815.9811 | 460.7712 | 11.185050 | 11.8796902 | 7.6851288 |
| 10 | 69.97930 | 1630.7946 | 688.1070 | 5.191235 | 0.1030798 | 1.1136201 |
| temps | Variable1 | Variable2 | Variable3 | Variable4 | Variable5 | Variable6 | Station | |
|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1.000310 | 100.3660 | 1.0824 | 6.938574 | 52.1383608 | 2.4324804 | 1 |
| 2 | 2 | 2.889900 | 407.3494 | 108.7878 | 6.633824 | 39.8412603 | 1.8915492 | 1 |
| 3 | 3 | 27.673200 | 1809.8954 | 254.5626 | 1.324532 | 34.3865538 | 5.3870787 | 1 |
| 4 | 4 | 16.891640 | 1355.1773 | 400.2592 | 5.353902 | 8.5822233 | 7.8279993 | 1 |
| 5 | 5 | 24.679750 | 1683.5962 | 214.4405 | 2.447417 | 37.0944294 | 0.5242695 | 1 |
| 6 | 6 | 24.545820 | 1855.5210 | 472.5984 | 10.774190 | 55.1324802 | 6.3218199 | 1 |
| 7 | 7 | 64.845760 | 674.0552 | 296.7524 | 10.325360 | 52.4765449 | 6.8219672 | 1 |
| 8 | 8 | 66.353920 | 1472.2384 | 715.4704 | 3.807187 | 11.7972035 | 3.4049443 | 1 |
| 9 | 9 | 37.588410 | 815.9811 | 460.7712 | 11.185050 | 11.8796902 | 7.6851288 | 1 |
| 10 | 10 | 69.979300 | 1630.7946 | 688.1070 | 5.191235 | 0.1030798 | 1.1136201 | 1 |
| 101 | 1 | -0.500155 | -50.1830 | -0.5412 | -3.469287 | -26.0691804 | -1.2162402 | 2 |
| 102 | 2 | -1.444950 | -203.6747 | -54.3939 | -3.316912 | -19.9206301 | -0.9457746 | 2 |
| 103 | 3 | -13.836600 | -904.9477 | -127.2813 | -0.662266 | -17.1932769 | -2.6935394 | 2 |
| 104 | 4 | -8.445820 | -677.5887 | -200.1296 | -2.676951 | -4.2911116 | -3.9139997 | 2 |
| 105 | 5 | -12.339875 | -841.7981 | -107.2202 | -1.223709 | -18.5472147 | -0.2621348 | 2 |
| 106 | 6 | -12.272910 | -927.7605 | -236.2992 | -5.387095 | -27.5662401 | -3.1609100 | 2 |
| 107 | 7 | -32.422880 | -337.0276 | -148.3762 | -5.162680 | -26.2382725 | -3.4109836 | 2 |
| 108 | 8 | -33.176960 | -736.1192 | -357.7352 | -1.903594 | -5.8986018 | -1.7024721 | 2 |
| 109 | 9 | -18.794205 | -407.9906 | -230.3856 | -5.592525 | -5.9398451 | -3.8425644 | 2 |
| 110 | 10 | -34.989650 | -815.3973 | -344.0535 | -2.595617 | -0.0515399 | -0.5568101 | 2 |
| temps | Variable1 | Variable2 | Variable3 | Variable4 | Variable5 | Variable6 | Traitement | Condition | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 1 | 1.000310 | 100.36600 | 1.0824 | 6.938574 | 52.138361 | 2.4324804 | A | 1 |
| 2 | 2 | 2.889900 | 407.34936 | 108.7878 | 6.633824 | 39.841260 | 1.8915492 | A | 1 |
| 3 | 3 | 27.673200 | 1809.89536 | 254.5626 | 1.324532 | 34.386554 | 5.3870787 | A | 1 |
| 4 | 4 | 16.891640 | 1355.17730 | 400.2592 | 5.353902 | 8.582223 | 7.8279993 | A | 1 |
| 5 | 5 | 24.679750 | 1683.59616 | 214.4405 | 2.447417 | 37.094429 | 0.5242695 | A | 1 |
| 51 | 51 | 432.726840 | 953.50300 | 3542.7711 | 9.470038 | 23.768704 | 3.5744647 | A | 2 |
| 52 | 52 | 255.901880 | 129.98426 | 5079.1156 | 2.018607 | 36.420807 | 2.7120203 | A | 2 |
| 53 | 53 | 227.110300 | 251.22816 | 1714.9952 | 9.282672 | 40.857357 | 2.9848605 | A | 2 |
| 54 | 54 | 283.525920 | 266.42138 | 3159.6966 | 3.539504 | 55.056858 | 1.1111274 | A | 2 |
| 55 | 55 | 270.111050 | 79.09608 | 3882.1365 | 10.071669 | 52.544788 | 8.5444508 | A | 2 |
| 101 | 1 | -0.500155 | -50.18300 | -0.5412 | -3.469287 | -26.069180 | -1.2162402 | B | 1 |
| 102 | 2 | -1.444950 | -203.67468 | -54.3939 | -3.316912 | -19.920630 | -0.9457746 | B | 1 |
| 103 | 3 | -13.836600 | -904.94768 | -127.2813 | -0.662266 | -17.193277 | -2.6935394 | B | 1 |
| 104 | 4 | -8.445820 | -677.58865 | -200.1296 | -2.676951 | -4.291112 | -3.9139997 | B | 1 |
| 105 | 5 | -12.339875 | -841.79808 | -107.2202 | -1.223709 | -18.547215 | -0.2621348 | B | 1 |
| 151 | 51 | -216.363420 | -476.75150 | -1771.3855 | -4.735019 | -11.884352 | -1.7872323 | B | 2 |
| 152 | 52 | -127.950940 | -64.99213 | -2539.5578 | -1.009303 | -18.210403 | -1.3560101 | B | 2 |
| 153 | 53 | -113.555150 | -125.61408 | -857.4976 | -4.641336 | -20.428679 | -1.4924302 | B | 2 |
| 154 | 54 | -141.762960 | -133.21069 | -1579.8483 | -1.769752 | -27.528429 | -0.5555637 | B | 2 |
| 155 | 55 | -135.055525 | -39.54804 | -1941.0683 | -5.035834 | -26.272394 | -4.2722254 | B | 2 |
| 201 | 1 | 1.500465 | 150.54900 | 1.6236 | 10.407861 | 78.207541 | 3.6487206 | C | 1 |
| 202 | 2 | 4.334850 | 611.02404 | 163.1817 | 9.950736 | 59.761890 | 2.8373238 | C | 1 |
| 203 | 3 | 41.509800 | 2714.84304 | 381.8439 | 1.986798 | 51.579831 | 8.0806181 | C | 1 |
| 204 | 4 | 25.337460 | 2032.76595 | 600.3888 | 8.030853 | 12.873335 | 11.7419990 | C | 1 |
| 205 | 5 | 37.019625 | 2525.39424 | 321.6608 | 3.671126 | 55.641644 | 0.7864043 | C | 1 |
| 251 | 51 | 649.090260 | 1430.25450 | 5314.1566 | 14.205056 | 35.653057 | 5.3616970 | C | 2 |
| 252 | 52 | 383.852820 | 194.97639 | 7618.6734 | 3.027911 | 54.631210 | 4.0680304 | C | 2 |
| 253 | 53 | 340.665450 | 376.84224 | 2572.4928 | 13.924007 | 61.286036 | 4.4772907 | C | 2 |
| 254 | 54 | 425.288880 | 399.63207 | 4739.5449 | 5.309256 | 82.585287 | 1.6666911 | C | 2 |
| 255 | 55 | 405.166575 | 118.64412 | 5823.2047 | 15.107503 | 78.817182 | 12.8166763 | C | 2 |
| temps | Variable1 | Variable2 | Variable3 | Traitement | |
|---|---|---|---|---|---|
| 1 | 1 | 51.010960 | 1.002109e+00 | -0.0005710 | A |
| 2 | 2 | 70.785881 | 1.201407e+01 | -0.6186671 | A |
| 3 | 3 | 15851.375936 | 6.985560e+04 | -1.3223747 | A |
| 4 | 4 | 504.180847 | 6.994956e+03 | -1.9869933 | A |
| 5 | 5 | 841.786004 | 6.812947e+04 | -1.2599771 | A |
| 6 | 6 | 477.158553 | 2.576922e+05 | -2.5001369 | A |
| 7 | 7 | 17518.237514 | 2.442295e+02 | -1.7459755 | A |
| 8 | 8 | 9103.597107 | 4.080562e+04 | -3.6661116 | A |
| 9 | 9 | 533.421827 | 8.348001e+02 | -2.6447142 | A |
| 10 | 10 | 3834.494262 | 1.699045e+05 | -3.7501520 | A |
| 51 | 1 | 358.254248 | 1.679133e+06 | -0.3778480 | B |
| 52 | 2 | 30.298826 | 1.346444e+02 | -0.9766873 | B |
| 53 | 3 | 19.495915 | 6.063954e+02 | -0.5860789 | B |
| 54 | 4 | 38.067291 | 7.934668e+02 | -1.3150951 | B |
| 55 | 5 | 30.087868 | 8.322095e+01 | -1.9132576 | B |
| 56 | 6 | 34.147783 | 9.927343e+05 | -1.4968439 | B |
| 57 | 7 | 9.886501 | 2.973787e+05 | -1.6432947 | B |
| 58 | 8 | 2.323517 | 1.215816e+05 | -3.3766198 | B |
| 59 | 9 | 2.167091 | 1.623050e+05 | -0.1435225 | B |
| 60 | 10 | 21.997688 | 3.680029e+05 | -2.5871100 | B |
| Température | Salinité | Présence | Espèce | |
|---|---|---|---|---|
| 1 | 0.0 | 35.0 | 0 | A |
| 2 | 0.5 | 34.5 | 0 | A |
| 3 | 1.0 | 34.0 | 1 | A |
| 4 | 1.5 | 33.5 | 0 | A |
| 5 | 2.0 | 33.0 | 0 | A |
| 6 | 2.5 | 32.5 | 0 | A |
| 7 | 3.0 | 32.0 | 1 | A |
| 8 | 3.5 | 31.5 | 1 | A |
| 9 | 4.0 | 31.0 | 0 | A |
| 10 | 4.5 | 30.5 | 0 | A |
| 52 | 0.0 | 35.0 | 0 | B |
| 53 | 0.5 | 34.5 | 0 | B |
| 54 | 1.0 | 34.0 | 1 | B |
| 55 | 1.5 | 33.5 | 1 | B |
| 56 | 2.0 | 33.0 | 1 | B |
| 57 | 2.5 | 32.5 | 1 | B |
| 58 | 3.0 | 32.0 | 1 | B |
| 59 | 3.5 | 31.5 | 1 | B |
| 60 | 4.0 | 31.0 | 1 | B |
| 61 | 4.5 | 30.5 | 1 | B |
8.3 Éléments graphiques complexes
8.3.1 Graphique radial
En utilisant un système de coordonnées polaires avec \(\theta\), on peut manipuler le système cartésien typique pour faire un graphique radial ou circulaire. Pour plus de détails, je vous réfère à la documentation des fonctions utilisées en exemples ici.
Montrer le code
f1 <- ggplot(Fdata) +
geom_bar(aes(x=a, y=b), width = 1, stat="identity", colour = "black",
fill=c(rep("#83BD78",4), '#F5A954')) +
geom_errorbar(aes(x = a, y = b, ymin = b-(b*0.05),
ymax = b+(b*0.05)),
width = 0.3,
linewidth = 0.7, alpha = 1, color = 'black') +
coord_polar(theta = "x", start=0) +
labs(x = 'Filtrat', y = 'Contenu en A.G.') +
theme_light() +
theme(axis.title.x = element_text(face="bold"),
axis.title.y = element_text(face="bold"))
f2 <- ggplot(Fdata) + #équivalent en barplot
geom_bar(aes(x=a, y=b), width = 0.8, stat="identity", colour = "black",
fill=c(rep("#83BD78",4), '#F5A954'),
position = 'dodge2') +
geom_errorbar(aes(x = a, y = b, ymin = b-(b*0.05),
ymax = b+(b*0.05)),
width = 0.3,
size = 0.7, alpha = 1, color = 'black') +
scale_y_continuous(limits = c(0,34), expand = c(0,0)) +
labs(x = '', y = '') +
theme_light()
ggarrange(f1, f2, ncol = 2)Montrer le code
# Pointe de tarte = stacked barplot + coordonées polaires
# avec données intégrées de mtcars
pie <- ggplot(mtcars, aes(x = factor(1), fill = factor(cyl))) +
geom_bar(width = 1) +
coord_polar(theta = "y") +
labs(x = "proportion on cars with each cylindre count",
y = "",
fill = "Cylindre count") +
theme_minimal() +
theme(axis.text.y = element_blank())
pie8.3.2 Axe secondaire
On peut ajouter un deuxième axe avec ggplot, et ce, peu importe le type de graphique (box, scatter, etc.). Toutefois, cette fonctionnalité est limitée à des relations monotoniques (monotones) simples entre les deux axes. Autrement dit, que la relation soit “simple” et qui peut être représenté par une transformation mathématique qui ne fait pas varier la direction de variation de la transformation. Bref, c’est limité à des relations comme logarithme, exponentielle, additive, multiplicative, etc.
Ça ne peut pas être utilisé pour des axes qui auraient une relation polynomiale, par exemple (puisqu’une fonction polynomiale peut varier positivement et négativement à l’intérieur de la fonction dépendant de la position du “x”).
Donc c’est très pratique pour représenter deux unités différentes d’une même mesure (ex. % et concentration) ou bien deux variables qui auraient une échelle ou unité similaire.
Montrer le code
ggplot(Fdata) +
geom_bar(aes(x=a, y=b), width = 0.8, stat="identity", colour = "black",
fill=c(rep("#83BD78",4), '#F5A954'),
position = 'dodge2') +
geom_errorbar(aes(x = a, y = b, ymin = b-(b*0.05),
ymax = b+(b*0.05)),
width = 0.3,
size = 0.7, alpha = 1, color = 'black') +
scale_y_continuous(limits = c(0,34), expand = c(0,0),
sec.axis = sec_axis(~./2 + 7,
name = "Quantité absolue (mg/g)")) + #1er axe est divisé par 2 et on y ajoute 7 pour créer l'échelle du 2e axe
labs(x = 'Filtrat', y = 'Pourcentage en A.G. (%)') +
theme_light()9 Liens utiles
- R:(RTeam, 2025)
- Rstudio:(PositSoftware, 2026)
- Viridis:(Rudis et al., 2024)
- PCAs:(Harvey et Hanson, 2024)
- ggplot:(Wickham et al., 2026)
- Stackexchange
- Stackoverflow
- ANOVA Types
- Multivariate Analysis in R
- KS-test
- STDHA
- Data Camp
- Rioja Plot
- Kendall’s \(\tau\)
- Kruskal-Wallis
10 Références
Notes de bas de page
elcha99@ulaval.ca↩︎