Bible R

Analyses de bases et création de graphiques

Auteur·rice

Elliott O. H. Chartrand

Date de publication

1 mars 2026

Modifié

22 mai 2026


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().

Montrer le code
install.packages("installr")
library(installr)
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!

Certaines astuces ou fonctionnalités, telles que des raccourcis de clavier, sont différentes entre les versions Windows, Mac et Linux de R/Rstudio. Généralement, elles ont toutes des équivalences entre elles permettant de les utiliser tout de même, mais parfois nécessitent une légère modification ou un changement quelconque pour son bon fonctionnement.

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.

Dans une période où les IAs génératives, comme les LLMs (Large Language Models) dans le style de Claude ou ChatGPT, sont malheureusement populaires, il faut être en mesure de travailler et surtout d’apprendre sans eux. Par leur nature probabiliste, les LLMs ne vont jamais comprendre ce qui se trouve dans les “prompts” et encore moins ce qui se trouve dans les réponses qu’ils génèrent. Même en mettant de côté la destruction environnementale engendrée par tout ce qui entoure les IAs génératives (chose qui ne devrait pas être ignorée, surtout en recherche en sciences naturelles), leur utilisation ne devrait jamais surpasser les forums de questions/réponses qui sont dédiés pour R et d’autres langages de programmation et de statistiques comme Stackexchange et Stackoverflow. Quoiqu’à première vue, il peut être tentant d’utiliser les LLMs ou d’autres outils d’IA, le but de l’analyse des données et des statistiques, surtout avec R et RStudio, est de comprendre les fonctions et leurs résultats pour être en mesure de les valider et de biens les interpréter, chose qui est impossible à faire avec l’IA. De toute façon, les LLMs sont entrainés sur des jeux de données/de texte qui proviennent des sites cités plus haut. Alors, en allant sur les sites de Stack, vous allez à la source de l’information sans passé par l’IA et ses inconvénients.

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.

La même chose s’applique aux graphiques qui sont affichés et sauvegardés dans la fenêtre “Plots”. Quoique non sauvegardés dans .RData, ils peuvent parfois commencer à être lourd. Effacer l’historique des graphiques produits pendant une session de travail peut aider avec la performance dans certaines instances, surtout si on passe la journée au complet à faire des graphiques et à les ajuster.

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
# un commentaire peut être placer ici
print("Hello World!") #ou bien ici
#'ou même ici, et le code est exécuté comme si 
#'le texte n'y était pas
[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.

Montrer le code
# Titre de section ####
## Sous-titre de section ####
### Sous-sous-titre de section ####

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).

Montrer le code
read.csv(fichier, header = T, sep = ",", dec = ".")

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.

Montrer le code
install.packages("readxl")
library(readxl)
read_xlsx("fichier.xlsx", "nom_feuille", range = "B2:G100")

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.

Montrer le code
df_sans_na <- na.omit(df_avec_na)
df_si_pas_na <- na.fail(df) #verification de présence de NAs

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:

Montrer le code
dataframe2 <- dataframe1[complete.cases(dataframe1),]

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.

Montrer le code
dfs_pos <- dplyr::filter(dfs, Variable4 >= 0, na.rm = T)
dfs_posv2 <- dplyr::filter(dfs, Variable4 >= 0 | Variable5 >= 0)

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
Rdata_ex <- data.frame(
  "Variable1" = c("1","2","3","...", "n", "1","2","3","...", "m"),
  "Variable2" = c("1","2","3","...", "n", "1","2","3","...", "m"),
  "Variable3" = c("1","2","3","...", "n", "1","2","3","...", "m"),
  "Facteur" = c(rep("A", 5), rep("B", 5))
)

Rdata_ex
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:

Montrer le code
df[1,]
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:

Montrer le code
df[,1]
  [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):

Montrer le code
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

À l’intérieur des [,] on peut utiliser des vecteurs pour spécifier une série de lignes ou de colonnes, comme ça:

Montrer le code
df[c(1:5),c(2,3)]
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 veut

On 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")
pan2

Échantillonnage “aléatoire”

Ceci 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ésulats
Montrer 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)

Éffet de la taille d’échantillonnage

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

Les objets dans R/RStudio ont tous une classe associée, c’est-à-dire qu’ils tombent dans une catégorie d’objet définie par R. Des exemples typiques de classes sont des valeurs numériques (ex. 1.2, 2.5, 3.6, …), des “intergers” (ex. 1, 2, 3, …), des caractères (ex. “A”, “B”, “C”, …), des booléens (Vrai ou Faux, T ou F) ou des facteurs (ex. “X”,1; “Y”,2; “Z”,3; …).

On peut vérifier la classe d’un objet ou d’une colonne d’un dataframe soit dans la fenêtre de l’environnement de la session R ou bien avec la fonction class(). Ça peut être utile pour assurer que nos variables soient du bon type pour éviter des bugs ou d’autres erreurs possibles lors des analyses.

Montrer le code
class(dfs) #dataframe
class(dfs$temps) #interger
class(dfs$Variable1) #numérique
class(dfs[,8]) #caractère
class(regdf) #modèle linéaire
[1] "data.frame"
[1] "integer"
[1] "numeric"
[1] "character"
[1] "lm"

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.

Le test de Shapiro-Wilk est un calcul de corrélation entre les données elles-mêmes qu’on teste et des valeurs pour une distribution normale. Comme on vient d’apprendre dans la Section 2.8, la valeur de p associée au test va avoir tendance à être très petite avec un plus grand n.

Les données utilisées en exemple ont un n égale à \(100\) et grâce au théorème central limite CLT, normalement des jeux de données larges (n >\(30\)~\(40\)) vont suivre une distribution normale (ou une distribution assez proche de la normale) et une vérification visuelle est plus juste (comme avec check_model()) qu’un test de significativité comme celui de Shapiro-Wilk.

Montrer le code
shapiro.test(df[,2])

    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
dftemp <- df[,-1]
for (i in seq_len(ncol(dftemp))) {
  tmp_res <- shapiro.test(dftemp[,i])
  print(paste("Valeur de p de Shapiro-Wilk, Variable",i,":", tmp_res$p.value))
}
[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
densV1 <- ggdensity(df$Variable1)
qqV1 <- ggqqplot(df$Variable1)
ggarrange(densV1, qqV1, nrow = 2)

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
hist1 <- ggplot(dfs2, aes(Variable1)) + geom_histogram(binwidth = 20)
hist1

Montrer le code
hist2 <- ggplot(dfs2, aes(Variable1, color = Condition)) + geom_histogram(binwidth = 20)
hist2

Montrer le code
box1 <- ggplot(dfs2, aes(Variable1, Traitement, color = Condition)) + geom_boxplot()
box1

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).

Montrer le code
scat1 <- ggplot(df, aes(Variable1, Variable2)) + geom_point()
scat1

Un autre exemple de loop pour faire des graphiques simples rapidement pour plusieurs variables.

Montrer le code
dftemp2 <- df[,-1]
templist <- list()
for (n in seq_len(ncol(dftemp2))) {
  templist[[n]] <- ggplot(df, aes(temps, dftemp2[,n])) + geom_point() + labs(y = paste("Variable", n))
  print(templist[[n]])
}
#ggarrange(plotlist = templist[1:6])

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 d’autres types d’ordination, comme les NMDS et les RDAs. Pour en savoir plus sur ces analyses, Bakker (2026) est une excellente ressource sur toutes les analyses multivariées dans R et sur plusieurs notions de statistiques importantes. La section sur les ordinations peut être lue ici: Ordination

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.

Montrer le code
library(factoextra)
library(ggplot2)
library(vegan)

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).

Montrer le code
pca_df <- prcomp(df, scale. = T)

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.

Montrer le code
screeplot(pca_df, bstick = TRUE, type = c("barplot", "lines"))

Screeplot avec model broken stick

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.

Montrer le code
scree

Screeplot avec variation par dimension

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.

Les modèles broken stick peuvent être super utiles dans d’autres scénarios avec des analyses différentes. C’est le cas des analyses de “cluster” (“clustering analysis”), que ce soit des hierarchecal clusters ou bien des constrained hierarchecal clusters, les broken sticks peuvent nous aider à déterminer le nombre de clusters à garder avec les mêmes principes. On veut garder les clusters qui ont une plus grande inertie ou variance explicative que le modèle de base, soit la ligne de référence. La fonction bstick() de la librairie “rioja” et “riojaPlot” fonctionne sur des objets créés par les fonctions de clustering hclust() et chclust().

Pour en savoir plus sur les analyses de clusters, je recommande ceci: Cluster Analysis (Bakker, 2026)

Et pour mes amis les paléo-océanographes, voici la galerie d’exemple et la documentation de rioja/riojaPlot qui inclut des exemples de “cluster analysis” et bien plus encore: Rioja

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.

Montrer le code
ggarrange(ind_def, var_def, bip_def, nrow = 2, ncol = 2, align = "hv")

Graphiques PCA par défaut. Gauche: Individus. Milieu: Variables. Bas: Biplot

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.

Montrer le code
biplot_simple

Biplot personnalisé simple

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]).

Montrer le code
biplot_comp

Biplot personnalisé complexe

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.

Montrer le code
biplot_sta

Biplot personnalisé avec catégorie

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”.

Montrer le code
install.packages("corrplot")
library(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.

Montrer le code
dfcor <- cor(df, method = "spear")
dfcorpv <- cor.mtest(df, conf.level = 0.95, method = "spearman")

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.

Montrer le code
corrplot(dfcor)

Matrice de corrélation par défaut

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
corrplot(dfcor[], method = "color", type = "lower", diag = F,
          tl.offset = 1, tl.col = "black",
          insig = 'n',
          addgrid.col = 'black')

Matrice de corrélation simple

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
corrplot(dfcor[], method = "square", type = "lower", diag = F,
          tl.offset = 1, tl.col = "black",
          insig = 'p-value', p.mat = dfcorpv$p[],
          addgrid.col = 'black')

Matrice de corrélation simple modifiée

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
corrplot(dfcor[], method = "color", type = "lower",
          diag = T, addCoef.col = "black",
          mar=c(0,0,0,0), tl.offset = 0.5, tl.col = "black",
          insig = 'n',
          number.digits = 2, p.mat = dfcorpv$p[],
          number.cex = 1, addgrid.col = 'black')

Matrice de corrélation simple modifiée

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')

Matrice de corrélation simple modifiée

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
corrplot(dfcor, method = "ellipse", type = "lower", diag = F,
          addCoef.col = "black", mar=c(0,0,2,0),
          title = "Matrice Complexe",
          tl.offset = 0.2, tl.col = "black",
          number.digits = 2, p.mat = dfcorpv$p,
          insig ='blank',
          number.cex = 1, addgrid.col = 'black',
          col = magma(256, begin = 0.3, end = 0.95))

Matrice de corrélation complexe

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))
          )

Matrice de corrélation avec symbole superposé
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))
          )

Matrice de corrélation avec corrplot2

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))
)

Matrice de corrélation tronquée

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.

On penserait que les ANOVAs sont des analyses super simples par rapport aux autres types de tests qu’on peut faire, mais il y a encore des complications à notre désarroi total. Il y a plusieurs types d’ANOVAs (ou plus précisément de type de calcul de sommes des carrés qui sont utilisés dans le calcul des ANOVAs). Une bonne ressource pour une explication simple, mais complète vient de nos amis à Goettingen ANOVA Types.

En voici un petit résumé:

  • Type I: par défaut, évalue les facteurs de façon séquentielle, un après l’autre dans l’ordre spécifié dans le modèle. Bon pour des données balancées ou des facteurs emboîtés, permettant aux facteurs “plus importants” d’expliquer toute la variation possible avant de laisser le reste aux facteurs “moins importants”
  • Type II: Évalue les facteurs de façon indépendante en ignorant les interactions entre les facteurs. Bien pour des systèmes sans interaction (ou des interactions non significatives).
  • Type III: Tous les facteurs évalués sont ajustés en relation avec tous les autres facteurs. Bon pour des systèmes avec des fortes interactions entre les facteurs et/ou avec plusieurs facteurs qui ont un effet ou une importance similaires dans le modèle.

Outre les ANOVAs, il existe d’autre façon de comparer des groupes entre eux.

Les versions non-paramétriques des ANOVAs sont Wilcoxon, Mann-Whitney-U et Kruskal-Wallis, qui ont toutes des applications légèrement différentes dépendant des types et du nombre de variables. Pour en lire plus sur elles, ceci est un bon point de départ: Comparaison non-paramétrique

Les ANCOVAs sont des analyses de covariance, qui combine à la fois la variance d’une variable, mais aussi d’autres variables qui covarient et influencent la variable dépendante du modèle, donc elle peut être vue comme un mélange d’une régression et d’une ANOVA (Khammar et al., 2020).

Les MANOVAs sont la version multivariée, ou multiparamétrique, des ANOVAs, donc sont utiles pour comparer des groupes avec plusieurs variables catégoriques simultanément, mais requièrent des postulats beaucoup plus étroits (Bakker, 2026). MANOVAs

Les PERMANOVAs sont des MANOVAs avec des permutations qui calculs les sommes des carrés avec une matrice de distance, donc très pratique avec des designs expérimentaux plus complexes (Bakker, 2026). PERMANOVAs

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
anova_df <- lm(Variable1 ~ Traitement, data = dfs2)
anova(anova_df)
check_model(anova_df)

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().

Montrer le code
emmeans(anova_df, tukey ~ Traitement)
$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).

Montrer le code
anop1.1

Boxplot par défaut

À 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().

Montrer le code
anop1.2

Boxplot personnalisé

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.

Montrer le code
anop1.3

Boxplot complexe

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.

Montrer le code
anop1.4

Violons

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.

Montrer le code
var_ind <- lm(Y ~ Var1 + Var2, données) #variables indépendantes
fac_dep <- lm(Y ~ Fac1*Fac2, données) #Facteur croisée (dépendant)
fac_ind<- lm(Y ~ Fac1:Fac2, données) #Juste interaction entre facteur

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”).

Montrer le code
emmeans(anova2_df, tukey ~ Traitement*Condition) |> multcomp::cld(Letters=letters)
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

Ce symbole, aussi parfois sous la forme de %>% avec le package “tidyverse”, est un pipeline. Cet opérateur permet d’enchaîner des fonctions une à la suite de l’autre sans devoir spécifier de nouveau l’objet sur lequel les fonctions vont agir. Je le présente ici, mais en aucune façon est-il nécessaire pour le fonctionnement de quelconque fonction ou manipulation dans R/RStudio. L’équivalent sans pipeline est:

Montrer le code
df_tukey <- emmeans(anova2_df, tukey ~ Traitement + Condition)
multcomp::cld(df_tukey, Letters=letters)

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.

Montrer le code
anop2

2 facteurs

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.

Les régressions simples mettent en relation une variable explicative (variable indépendante) et une variable expliquée (variable dépendante), mais il existe aussi des régressions multiples. Elles permettent d’utiliser plusieurs variables explicatives simultanément pour une seule variable expliquée. Par exemple, on pourrait utiliser la longueur totale et le poids d’un poisson pour estimer son âge (si on ne veut pas aller chercher ses otolithes). Le poids et la longueur totale sont les deux variables explicatives et l’âge est la variable expliquée. On peut avoir plus de deux variables dans un seul modèle, tout dépend du sujet de recherche.

Aussi, lorsqu’on travaille avec des régressions multiples, il arrive souvent que pas toutes nos variables sont autant importantes l’une que l’autre et, pour préserver la parcimonie de nos analyses, on peut comparer différents modèles ensemble qui ont plus ou moins de variables et évaluer leur performance. Ça se fait avec l’AIC (“Akaike’s Information Criterion”). Le meilleur modèle est celui avec la plus petite valeur d’AIC.

Le tout dans R ressemblerait à ceci:

Montrer le code
regmult1 <- lm(Variable1 ~ Variable2 + Variable3 + Variable4, data = dfs2)
summary(regmult1)
check_model(regmult1)
Montrer le code
regmult2 <- lm(Variable1 ~ Variable2 + Variable3, data = dfs2)
summary(regmult2)
check_model(regmult2)
Montrer le code
regmult3 <- lm(Variable1 ~ Variable3 + Variable4, data = dfs2)
summary(regmult3)
check_model(regmult3)
Montrer le code
regmult4 <- lm(Variable1 ~ Variable2 + Variable4, data = dfs2)
summary(regmult4)
check_model(regmult4)
Montrer le code
multmodels <- list(regmult1, regmult2, regmult3, regmult4)
for (j in seq_len(length(multmodels))) {
  AIC_res <- AIC(multmodels[[j]])
  print(paste("AIC du modèle",j,":", AIC_res))
}
[1] "AIC du modèle 1 : 4119.78237829369"
[1] "AIC du modèle 2 : 4152.70072985904"
[1] "AIC du modèle 3 : 4119.13823591734"
[1] "AIC du modèle 4 : 4273.79071955773"

Pour en savoir plus, je recommande ceci comme point de départ:

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().

Montrer le code
regdf <- lm(Variable1 ~ Variable2, data = dfs2)
summary(regdf)
check_model(regdf)


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.

Montrer le code
reg1

Régression linéaire simple

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”.

Montrer le code
p1g

Régression linéaire avec facteur
Montrer le code
ggarrange(p1g, p2g, p3g, nrow = 3, common.legend = T)

Régression linéaire avec facteur

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.

Montrer le code
reg2fac

Régression linéaire avec facteur

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
regdflog1 <- lm(Variable2 ~ Variable1, data = dflog)
summary(regdflog1)
check_model(regdflog1)


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
regdflog2 <- lm(log10(Variable2) ~ log10(Variable1), data = dflog)
summary(regdflog2)
check_model(regdflog2)


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.

Montrer le code
nolog

Régression avec données non logarithmées
Montrer le code
log

Régression avec données logarithmées

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).

Montrer le code
logfac

Régression avec données logarithmées et avec facteur

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
glm1 <- glm(Présence ~ Température, dfbin, family = "binomial")
summary(glm1)
check_model(glm1)


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:

Montrer le code
logis1

Régression logistique

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.

Montrer le code
logis2

Régression logistique avec 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.

Montrer le code
df[c(1:10),]
Annexe 1. Structure des données continues
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
Montrer le code
dfs[c(1:10, 101:110),]
Annexe 2. Structure des données continues avec catégorie
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
Montrer le code
dfs2[c(1:5,51:55, 101:105,151:155, 201:205,251:255),]
Annexe 3. Structure des données continues avec deux facteurs
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
Montrer le code
dflog[c(1:10, 51:60),]
Annexe 4. Structure des données log-normales
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
Montrer le code
dfbin2[c(1:10, 52:61),]
Annexe 5. Structure des données logistiques
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
Fdata <- data.frame(a=c('F1', 'F2', 'F3', 'F4', 'Ft'),
                    b= c(5, 5.8, 10.3, 31.4, 28.7))

Fdata$a <- factor(Fdata$a, levels = c('F1', 'F2', 'F3', 'F4', 'Ft'))
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())
pie

8.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

10 Références

Bakker, J. D. (2026). Applied Multivariate Statistics in R. University of Washington. https://uw.pressbooks.pub/appliedmultivariatestatistics/
Demortier, L. (2007). P Values and Nuisance Parameters. Rockefeller University. https://www.researchgate.net/publication/251182393_P_Values_and_Nuisance_Parameters
Gómez‑de‑Mariscal, E., Guerrero, V., Sneider, A., Jayatilaka, H., Phillip, J. M., Wirtz, D. et Muñoz‑Barrutia, A. (2021). Use of the p‑values as a size‑dependent function to address practical differences when analyzing large datasets. Nature Portfolio. https://doi.org/10.1038/s41598-021-00199-5
Halsey, L. G. (2019). The reign of the p-value is over: what alternative analyses could we employ to fill the power vacuum? Biology Letters, 15(5), 20190174. https://doi.org/10.1098/rsbl.2019.0174
Harvey, D. T. et Hanson, B. A. (2024, 26 avril). A Comparison of Functions for PCA. https://bryanhanson.github.io/LearnPCA/articles/Vig_07_Functions_PCA.html
Khammar, A., Yarahmadi, M. et Madadizadeh, F. (2020). What Is Analysis of Covariance (ANCOVA) and How to Correctly Report Its Results in Medical Research?, 49, 1016‑1017. https://pmc.ncbi.nlm.nih.gov/articles/PMC7475615/
Nakagawa, S. et Cuthill, I. C. (2007). Effect size, confidence interval and statistical significance: a practical guide for biologists. Biological Reviews, 82(4), 591‑605. https://doi.org/https://doi.org/10.1111/j.1469-185X.2007.00027.x
Nuñez, C. R. A. R., Jamie R. AND Anderton. (2018). Optimizing colormaps with consideration for color vision deficiency to enable accurate interpretation of scientific data. PLOS ONE, 13(7), 1‑14. https://doi.org/10.1371/journal.pone.0199239
PositSoftware. (2026, 4 janvier). RStudio IDE. https://posit.co/downloads/
R Core Team. (2026). R: A Language and Environment for Statistical Computing. R Foundation for Statistical Computing. https://www.R-project.org/
RTeam. (2025, 1ᵉʳ novembre). R-4.5.2 for Windows. https://cran.r-project.org/bin/windows/base/
Rudis, B., Ross, N. et Garnier, S. (2024, 28 janvier). Introduction to the viridis color maps. https://cran.r-project.org/web/packages/viridis/vignettes/intro-to-viridis.html
Wickham, H., Chang, W., Henry, L., Pedersen, T. L., Takahashi, K., Wilke, C., Woo, K., Yutani, H., Dunnington, D. et Brand, T. van den. (2026, 3 février). ggplot2. https://ggplot2.tidyverse.org/

Notes de bas de page

  1. elcha99@ulaval.ca↩︎