Dans de nombreuses études, il est courant de procéder à des mesures répétitives d’une variables, sur les mêmes individus, à différents moments. La visualisation de telles données nécessite de réaliser des graphiques permettant de mettre en évidence les changements individuels au fil du temps (autrement dit : les trajectoires individuelles). À cet égard, les “spaghetti plots”se révèlent être un choix judicieux.
Cependant, il est souvent également intéressant d’explorer l’évolution collective des données pour l’ensemble des participants, ainsi que de comprendre la variabilité des réponses. Pour répondre à ces besoins, les boxplots appariés, également connus sous le nom de paired boxplots, offrent une solution particulièrement efficace.
Dans ce tutoriel, je vous montre en pas à pas, 3 solutions pour réaliser facilement ces paired boxplots avec R.
La première consiste à les créer de toutes parts avec le package ggplot2
, alors que les deux suivantes consistent à utiliser des packages facilitant leur réalisation ggpubr
etggstatsplots
En bonus, vous montre également comment visualiser vos données appariées avec le logiciel d’analyses JASP.
Table des matières
Les données
Pour ce tutoriel, nous allons employer une partie des donnéesChickWeight
du packagedataset
(chargé par défaut à chaque session R). Pour cela, nous allons filter les données pour :
- ne conserver qu’un seul régime : la Diet 1
- ne conserver que les temps de mesure 6, 14 et 21
- ne conserver que les animaux ayant des données complètes (3 mesures)
Les boxplot appariés que nous allons réaliser permetront de visualiser l’évolution individuelle et globale du poids des poulets au cours du temps.
library(dplyr)CW <- ChickWeight %>% filter(Diet==1 & Time %in% c(6,14, 21)) %>% filter(! Chick %in% c(16,15,8 )) %>% mutate(Time = as.factor(Time))%>% droplevels() %>% as_tibble() head(CW)# A tibble: 6 × 4 weight Time Chick Diet <dbl> <fct> <ord> <fct>1 64 6 1 1 2 125 14 1 1 3 205 21 1 1 4 72 6 2 1 5 138 14 2 1 6 215 21 2 1
Ici les données sont en format “long”, puisque les poids observés aux différents temps sont dans la même colonne.
Dans le format wide les poids observés aux temps 6, 14 et 21 seraient dans 3 colonnes différentes (voir plus loin).
Pour en savoir plus sur ces formatlong
etwide
, vous pouvez consulter l’articleFormat wide et long : pourquoi, et comment ?:
A noter que les fonctions décrites dans l’article ont été remplacées par les fonctionspivot_longer()
etpivot_wider()
.
Réaliser des boxplots appariés avec ggplot2
Le code ci-dessous emploi des données au format long
:
library(ggplot2)ggplot(CW, aes(x=Time, y=weight, colour=Time))+ geom_point()+ theme(legend.position="none")+ geom_boxplot(alpha=0)+ geom_line(aes(group=Chick), colour="grey70")+ theme_classic()
ggplot(CW, aes(x=Time, y=weight, colour=Time))
: Cette instruction crée l’objet de base du graphique ggplot. La fonctionaes()
définit les esthétiques du graphique, en indiquant queTime
sera sur l’axe des x,weight
sur l’axe des y, et que la couleur des points sera également déterminée parTime
`. Cela signifie que les points seront colorés différemment en fonction de leur valeur Time.geom_point()
: Ajoute des points au graphique, chaque point représentant une observation dans le dataframe CW.theme(legend.position="none")
: Supprime la légende du graphique.geom_boxplot(alpha=0)
: Ajoute un boxplot au graphique, mais le rend entièrement transparent (alpha=0).geom_line(aes(group=Chick), colour="grey70")
: Trace des lignes pour connecter les points, avec les lignes groupées par la variable Chick. La couleur des lignes est définie comme un gris clair (“grey70”).theme_classic()
: Applique un thème classique au graphique, qui modifie l’apparence générale en éliminant l’arrière-plan gris et en mettant en place des axes et des polices plus traditionnels.
Réaliser des boxplots appariés avec ggpubr
La fonction ggpaired()
permet de réaliser des boxplots appariés avec des données au format long et au format wide (mais uniquement avec 2 modalités pour le format wide)
Boxplots appariés avec ggpubr sur des données au format long
library(ggpubr)ggpaired(CW, x = "Time", y = "weight", id="Chick", color = "Time", line.color = "gray80", line.size = 0.4, palette = "npg")
Boxplots appariés avec ggpubr sur des données au format wide
La fonctionggpaired()
du packageggpubr
peut également être employée pour réaliser des boxplots appariés lorsque les données sont au format wide
. Néanmoins, dans cette situation, à ma connaissance, seulement deux conditions peuvent être représentées.
library(tidyverse)# création d'un dataset avec uniquement 2 temps d'observations (on retire le temps 6)CW2 <- CW %>% filter(Time != 6)# passage en format wide avec la fonction pivot_wider()CW2.wide <- pivot_wider(CW2, id_cols= Chick, names_from = Time, values_from = weight)head(CW2.wide)# A tibble: 6 × 3 Chick `14` `21` <ord> <dbl> <dbl>1 1 125 2052 2 138 2153 3 138 2024 4 108 1575 5 164 2236 6 148 157# boxplot appariéggpaired(CW2.wide, cond1 = "14", cond2="21", fill="condition", palette="jco", line.color="grey50")
L’argumentfill="condition"
permet d’appliquer une couleur par condition. Pour plus d’information sur les arguments de cette fonction, consultez l’aide.
Réaliser des boxplots appariés avec ggstatsplot
Pour cela, nous allons employer la fonctionggwithinstats()
. Cette fonction emploi des données au format long, et à ma connaissance seules 2 conditions peuvent être représentées.
ici, j’aurai pu directement employer les donnéesCW2
qui ne contiennent que 2 temps de mesure, mais j’ai préféré vous montrer comment réaliser un filtre à l’intéreur de la fonction.
library(ggstatsplot)ggwithinstats( data = filter(CW,Time %in% c("14","21")), x = Time, y = weight, results.subtitle=FALSE,)
data = filter(CW, Time %in% c("14", "21"))
: Cette ligne filtre le jeu de données CW pour inclure seulement les observations pour lesquelles la variableTime
est égale à “14” ou “21”. Cela signifie que le graphique qui sera généré se basera uniquement sur les données filtrées.x = Time
: Spécifie que la variableTime
sera utilisée sur l’axe des abscisses (axe X) du graphique.y =
weight
: Indique que la variable weight (poids) sera utilisée sur l’axe des ordonnées (axe Y) du graphique.results.subtitle=FALSE
, : Indique que le sous-titre affichant les résultats des tests statistiques (comme la valeur p) ne devrait pas être affiché sur le graphique. Cela peut être utile pour des raisons esthétiques ou si l’on préfère interpréter les résultats séparément.
Si vous le souhaitez, vous pouvez associer un test statistique et afficher les résultats sur le boxplot apparié. Pour cela, vous devez utiliser les arguments suivants de la fonctionggwithinstats()
:
type
qui permet de spécifier le type de comparaison appariée. Vous avez le choix entre “parametric”, “nonparametric”, “robust” et “bayesconf.level = 0.95
qui permet de spécifier le niveau de confiance de l’intervalle associé aux paramètres qui seront affichés.results.subtitle = TRUE
: ce qui permet d’afficher les résultats associés à la comparaisons (statistique du test, p-value etc…).
ggwithinstats( data = filter(CW, Time %in% c("14", "21")), x = Time, y = weight, type = "parametric", conf.level = 0.95, results.subtitle = TRUE,)
A propos de l'ordre des données
Pour la fonction ggwithinstats()
Dans la fonctionggwithinstats()
de ggstatsplot
, il n’y a pas d’argument permettant d’indiquer comment relier les points entre eux. Malgré cela, l’ordre des données n’a pas d’influence. Cela m’a intrigué alors j’ai vérifié.
Dans le fichier CW2, les données sont ordonnées selon les numéros d’identification des animaux, avec alors une alternance des mesures à J14 puis à J21.
CW2# A tibble: 32 × 4 weight Time Chick Diet <dbl> <fct> <ord> <fct> 1 125 14 1 1 2 205 21 1 1 3 138 14 2 1 4 215 21 2 1 5 138 14 3 1 6 202 21 3 1 7 108 14 4 1 8 157 21 4 1 9 164 14 5 1 10 223 21 5 1 # ℹ 22 more rows
Voici le boxplot apparié obtenu :
ggwithinstats( data = CW2, x = Time, y = weight, results.subtitle=FALSE,)
J’ai alors créé un fichierCW3
, en l’ordonnant en fonction du temps. Ainsi on retrouve dans la première partie toutes les données de J14, puis, dans la seconde partie, toutes celles de J21 :
CW3 <- CW2 %>% arrange(Time)CW3# A tibble: 32 × 4 weight Time Chick Diet <dbl> <fct> <ord> <fct> 1 125 14 1 1 2 138 14 2 1 3 138 14 3 1 4 108 14 4 1 5 164 14 5 1 6 148 14 6 1 7 174 14 7 1 8 92 14 9 1 9 96 14 10 1 10 177 14 11 1 # ℹ 22 more rows
Comme vous pouvez le voir, les boxplots appariés obtenus sont identiques.
ggwithinstats( data = CW3, x = Time, y = weight, results.subtitle=FALSE,)
Pour la fonction t.test()
J’ai alors voulu explorer si l’ordre des données avait un impact sur les résultats du test de student apparié, lorsque les données sont en format long. Il apparait que quel que soit l’ordre des données, les résultats du test appariés sont identiques, et identique à ceux obtenus avec le format wide. OUF !!
t.test(CW3$weight~CW3$Time, paired=TRUE) Paired t-testdata: CW3$weight by CW3$Timet = -5.8586, df = 15, p-value = 3.145e-05alternative hypothesis: true mean difference is not equal to 095 percent confidence interval: -68.78734 -32.08766sample estimates:mean difference -50.4375
t.test(CW2$weight~CW2$Time, paired=TRUE) Paired t-testdata: CW2$weight by CW2$Timet = -5.8586, df = 15, p-value = 3.145e-05alternative hypothesis: true mean difference is not equal to 095 percent confidence interval: -68.78734 -32.08766sample estimates:mean difference -50.4375
t.test(CW2.wide$'14' , CW2.wide$'21', paired=TRUE) Paired t-testdata: CW2.wide$"14" and CW2.wide$"21"t = -5.8586, df = 15, p-value = 3.145e-05alternative hypothesis: true mean difference is not equal to 095 percent confidence interval: -68.78734 -32.08766sample estimates:mean difference -50.4375
BONUS : Visualiser des données appariées avec le logiciel JASP
Si vous travaillez avec JASP, vous pouvez également obtenir un graphique permettant de visualiser vos données appariées. Pour cela, vos données doivent être au format wide.
Dans l’exemple ci dessous, j’ai importé sous JASP les données CW2.wide, puis j’ai choisiTest t
(dans le menu du haut) puisTest t pour échantillons appariés
etGraphique Rainclound
Je n’ai pas trouvé comment obtenir un graphqiue similaire sous Jamovi
RemarqueJASP est un logiciel statistique open source, qui représente, à mon avis, une alternative intéressante à R, notamment pour celles et ceux qui réalisent des analyses statistiques de temps en temps. Le logiciel dispose d’une interface intuitive qui permet d’importer des données, de renommer des variables, de filtrer des lignes, etc…et de faire les principales analyses statistqiues Vous pouvez le télécharger ici :https://jasp-stats.org/download/
Conclusion
Les boxplots appariés sont très efficaces pour visualiser des données répétées sur les mêmes sujets ou entités à travers différents moments ou conditions. Ils offrent une vue claire des variations individuelles, des tendances centrales mais aussi de la dispersion au sein d’un ensemble de données.
Plusieurs approches sont disponibles sous R pour créer ces boxplots appariés, notamment avec les packages ggplot2
,ggpubr
et ggstatsplot:
ggplot2
se distingue par sa flexibilité et sa capacité à superposer différentes couches de données, permettant une visualisation détaillée et personnalisée.ggpubr
simplifie le processus en fournissant une fonction dédiée aux boxplots appariés, et en permettant d’employer des données au format long ou wideggstatsplot
, permet, quant à lui, d’intégrer des éléments statistiques aux boxplots appariés, mais en se limitant à deux conditions.
En outre, l’utilisation de JASP pour les analyses statistiques et la visualisation offre une alternative conviviale pour ceux qui préfèrent une interface graphique à la ligne de commande.
Chaque méthode a ses avantages et ses inconvénients, et le choix entre elles dépendra du nombre de conditions à comparer , du format de vos données et du niveau de détail souhaité dans vos visualisations.
Voici un récapitualif des packages utilisables en fonction du nombre de conditions à comparer, et du format des données.
2 conditions | Plus de 2 conditions | |
---|---|---|
Format Long | ggplot2 ggpubr ggstats plot | ggplot2 ggpubr |
Format Wide | ggpubrr |
N’oubliez pas que votre feedback est très important ! Si vous avez des questions, des suggestions, ou si vous souhaitez partager vos propres expériences et astuces sur l’utilisation des boxplots appariés, n’hésitez pas à laisser un commentaire ci-dessous. Vos contributions enrichiront la discussion et aideront le plus grand nombre !
5 Responses
Merci encore pour ce beau tutoriel Claire.
Répondre
Bonjour Claire,
Je vous remercie pour billet de blog, une fois encore très éclairant. J’aurais quelques questions.
– jusqu’à quel effectif pensez-vous qu’il soit pertinent de faire ce type de graphique ?
– quel méthode utiliser pour tester la normalité lorsque les données répétées sont appariées (3 mesures de pression artérielle avant/après une intervention)Merci beaucoup par avance
Répondre
Bonjour Jérôme,
Tant que ça reste lisible, ça me semble pertinent de faire ce graphique.
Pour ce qui concerne la normalité, j’ai l’habitude de faire un test de Shapiro-Wilks sur les résidus. Je réalise aussi une évaluation de la sphéricié (variance des différences entre chaque paires) par un test de Mauchly.
J’espère que cela vous aide.
Bonne continuationRépondre
Bravo pour cet article très bien détaillé.
Pour avoir qui la formation remise à niveau en biostatistics sous JASP je ne peux que la recommander !Répondre
Merci François pour ce retour sur la formation !
Répondre
Laisser un commentaire
Vous souhaitez vous former à R, ou aux statistiques ?
Retrouver le planning et les programmes de mes formations ici 👇👇👇
Vous avez besoin d'un assitance pour analyser vos données ?
Retrouver mes propositions de services ici 👇👇👇
Vous souhaitez soutenir mon travail ?
C’est possible en faisant un don sur la page Tipeee du blog