library(tidyverse)
library(rstatix)
library(ggpubr)Tests t multiples en R : un test par variable
Passez au format long, puis exécutez et ajustez un test t pour chaque variable réponse avec rstatix
Exécutez un test t sur de nombreuses variables réponses d’un coup en R. Passez du format large au format long avec pivot_longer(), groupez par variable et utilisez t_test() de rstatix pour obtenir un test ordonné par variable — avec des p-values ajustées sur l’ensemble du lot et une boîte à moustaches ggpubr à facettes qui affiche la significativité. Couvre le cas à deux groupes et les comparaisons par paires pour un facteur à 3 niveaux ou plus.
- L’approche par lot — passez du format large au format long avec
pivot_longer(), puis exécutez un t-test par variable réponse dans un seul pipeline. - rstatix
t_test()— un data frame ordonné de résultats (statistic, df, p) au lieu d’une pile de sortiest.test(). - Ajustez sur l’ensemble du lot —
adjust_pvalue()corrige les p-values des nombreux tests que vous venez d’exécuter, afin de ne pas surestimer la significativité. - Des graphiques de qualité publication — une boîte à moustaches
ggpubrà facettes qui affiche la significativité sur chaque panneau viastat_pvalue_manual(). - L’angle par paires — quand votre groupe compte 3 niveaux ou plus, remplacez par
pairwise_t_test()pour comparer chaque paire, variable par variable.
Vous avez un data frame comportant plusieurs variables réponses — disons quatre mesures florales — et un facteur de regroupement, et vous voulez savoir, pour chaque variable, si les deux groupes diffèrent. Exécuter t.test() à la main quatre fois fonctionne, mais c’est fastidieux, source d’erreurs, et cela vous laisse avec quatre sorties console que vous devez ensuite lire une par une. Pire, quatre tests séparés signifient quatre risques de faux positif, sans que rien ne l’ait corrigé.
La façon tidy de procéder est un flux de travail par lot : remodelez les données pour que chaque mesure vive dans une seule colonne, exécutez un t-test par variable dans un seul pipeline groupé, et récupérez un tableau ordonné que vous pouvez ajuster, trier et représenter. Ce billet illustre cette approche avec rstatix — un habillage tidy des tests classiques de R — et ggpubr pour la figure. Un t-test compare les moyennes de deux groupes ; ici, nous en exécutons simplement un pour chaque variable d’un coup.
Mise en place
Chargez le tidyverse (pour pivot_longer()), rstatix (pour les tests) et ggpubr (pour le graphique) :
Nous utiliserons le jeu de données intégré iris. Pour le premier exemple, à deux groupes, nous écartons l’espèce setosa afin de comparer exactement deux groupes — versicolor vs. virginica — sur les quatre mesures :
mydata <- iris %>%
filter(Species != "setosa") %>%
as_tibble()
head(mydata)# A tibble: 6 × 5
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
<dbl> <dbl> <dbl> <dbl> <fct>
1 7 3.2 4.7 1.4 versicolor
2 6.4 3.2 4.5 1.5 versicolor
3 6.9 3.1 4.9 1.5 versicolor
4 5.5 2.3 4 1.3 versicolor
5 6.5 2.8 4.6 1.5 versicolor
6 5.7 2.8 4.5 1.3 versicolor
Passer du format large au format long
Les quatre mesures occupent quatre colonnes distinctes — c’est le format large. Pour les tester en une seule passe, empilez-les dans une unique colonne value étiquetée par une colonne variables. tidyr::pivot_longer() fait exactement cela :
mydata.long <- mydata %>%
pivot_longer(
-Species, # keep Species as-is; pivot everything else
names_to = "variables", # the old column names go here
values_to = "value" # their numbers go here
)
head(mydata.long)# A tibble: 6 × 3
Species variables value
<fct> <chr> <dbl>
1 versicolor Sepal.Length 7
2 versicolor Sepal.Width 3.2
3 versicolor Petal.Length 4.7
4 versicolor Petal.Width 1.4
5 versicolor Sepal.Length 6.4
6 versicolor Sepal.Width 3.2
Chaque ligne représente désormais une mesure : une espèce, la variable concernée et la valeur. C’est la forme qui permet à group_by(variables) de déployer un test sur les quatre mesures d’un seul coup.
Statistiques descriptives par variable
Avant de tester, regardez les chiffres. La fonction get_summary_stats() de rstatix fournit un tableau ordonné n / moyenne / écart-type pour chaque variable × groupe — le contexte nécessaire pour interpréter n’importe quelle p-value :
mydata.long %>%
group_by(variables, Species) %>%
get_summary_stats(value, type = "mean_sd")# A tibble: 8 × 6
Species variables variable n mean sd
<fct> <chr> <fct> <dbl> <dbl> <dbl>
1 versicolor Petal.Length value 50 4.26 0.47
2 virginica Petal.Length value 50 5.55 0.552
3 versicolor Petal.Width value 50 1.33 0.198
4 virginica Petal.Width value 50 2.03 0.275
5 versicolor Sepal.Length value 50 5.94 0.516
6 virginica Sepal.Length value 50 6.59 0.636
7 versicolor Sepal.Width value 50 2.77 0.314
8 virginica Sepal.Width value 50 2.97 0.322
L’histoire est déjà lisible : les deux mesures de pétale séparent nettement les espèces (les pétales de virginica sont bien plus grands), tandis que Sepal.Width ne diffère presque pas. Les tests ci-dessous ne font que mettre des chiffres sur ce constat.
Un t-test par variable
Voici tout l’intérêt. Groupez les données au format long par variables, puis passez-les à t_test() de rstatix. Comme les données sont groupées, rstatix exécute le test une fois au sein de chaque groupe — un t-test par mesure — et renvoie un unique tableau ordonné :
stat.test <- mydata.long %>%
group_by(variables) %>%
t_test(value ~ Species) %>%
adjust_pvalue(method = "BH") %>%
add_significance()
stat.test# A tibble: 4 × 11
variables .y. group1 group2 n1 n2 statistic df p p.adj
<chr> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <dbl>
1 Petal.Length value versi… virgi… 50 50 -12.6 95.6 4.90e-22 9.80e-22
2 Petal.Width value versi… virgi… 50 50 -14.6 89.0 2.11e-25 8.45e-25
3 Sepal.Length value versi… virgi… 50 50 -5.63 94.0 1.87e- 7 2.49e- 7
4 Sepal.Width value versi… virgi… 50 50 -3.21 97.9 1.82e- 3 1.82e- 3
# ℹ 1 more variable: p.adj.signif <chr>
Lisez le pipeline de haut en bas :
t_test(value ~ Species)— pour chaque variable, comparevalueentre les deux espèces. Par défaut, il s’agit du t-test de Welch (qui ne suppose pas l’égalité des variances), le choix sûr lorsque les dispersions des groupes diffèrent.adjust_pvalue(method = "BH")— vous venez d’exécuter quatre tests, si bien que la colonnepbrute surestime vos preuves. Cela ajoute une colonnep.adjqui corrige la multiplicité des variables à l’aide de la méthode de Benjamini-Hochberg (contrôle le taux de fausses découvertes). Utilisez"bonferroni"pour la variante par famille, plus stricte.add_significance()— ajoute la colonne d’étoiles familière (p.adj.signif:****,***,**,*,ns) pour un repérage rapide et pour les étiquettes du graphique.
La sortie comporte une ligne par variable avec le sens de l’estimation (statistic), les degrés de liberté de Welch (df), le p brut, le p.adj ajusté et les étoiles. Les quatre mesures diffèrent significativement entre versicolor et virginica après ajustement — les pétales de façon écrasante (p.adj de l’ordre de 1e-22 à 1e-25), Sepal.Width le plus faiblement (p.adj ≈ 0.0018, tout de même **).
adjust_pvalue() corrige ici sur les quatre tests — une seule famille de comparaisons, une par variable réponse. C’est la bonne correction lorsque votre question est « lesquelles de ces variables diffèrent entre les deux groupes ? ». C’est une correction différente de l’ajustement à l’intérieur d’une variable sur de nombreuses paires de groupes, ce que traite la section par paires ci-dessous.
Visualiser avec une boîte à moustaches à facettes
Un tableau est précis ; une figure est persuasive. Représentez les quatre variables sous forme de boîtes à moustaches à facettes et affichez la significativité ajustée sur chaque panneau. Appelez d’abord add_xy_position() pour que rstatix calcule où chaque crochet doit se placer, puis transmettez le résultat à stat_pvalue_manual() :
set.seed(123) # deterministic jitter positions across renders
stat.test <- stat.test %>%
add_xy_position(x = "Species")
ggboxplot(
mydata.long, x = "Species", y = "value",
fill = "Species", palette = "npg", legend = "none",
add = "jitter", add.params = list(size = 0.6, alpha = 0.4)
) +
facet_wrap(~variables) +
stat_pvalue_manual(stat.test, label = "p.adj.signif", tip.length = 0.01)
facet_wrap(~variables) donne à chaque mesure son propre panneau ; la palette npg (Nature Publishing Group) est une palette de revue adaptée au daltonisme ; les points dispersés (jitter) montrent les données brutes derrière chaque boîte ; et stat_pvalue_manual() dépose les étoiles ajustées exactement là où add_xy_position() a placé le crochet. Une figure, quatre tests, entièrement annotée.
Un graphique par variable
Vous préférez une figure distincte, avec son propre titre, par variable (pour un rapport ou un diaporama) ? La fonction doo() de rstatix applique une fonction au sein de chaque groupe et stocke le résultat — ici un graphique — dans une colonne-liste que vous pouvez parcourir en boucle :
graphs <- mydata.long %>%
group_by(variables) %>%
doo(
~ ggboxplot(
data = ., x = "Species", y = "value",
fill = "Species", palette = "npg", legend = "none"
),
result = "plots"
)
# Add the matching p-value to each and print
for (i in seq_along(graphs$variables)) {
g <- graphs$plots[[i]] +
labs(title = graphs$variables[i]) +
stat_pvalue_manual(stat.test[i, ], label = "p.adj.signif")
print(g)
}Chaque élément de graphs$plots est un ggplot autonome que vous pouvez titrer, annoter avec sa propre ligne de test et exporter séparément — utile lorsque la grille à facettes est trop petite ou que vous avez besoin d’une figure par fichier.
Comparaisons par paires pour 3 groupes ou plus
L’exemple ci-dessus comptait exactement deux groupes. Quand votre facteur a trois niveaux ou plus, un seul t-test ne peut pas les comparer tous — vous voulez chaque paire de groupes, variable par variable. Remplacez t_test() par pairwise_t_test() et gardez le reste de l’approche par lot à l’identique. Cette fois, nous utilisons les trois espèces d’iris :
iris.long <- iris %>%
as_tibble() %>%
pivot_longer(-Species, names_to = "variables", values_to = "value")
pwc <- iris.long %>%
group_by(variables) %>%
pairwise_t_test(value ~ Species, p.adjust.method = "bonferroni")
pwc# A tibble: 12 × 10
variables .y. group1 group2 n1 n2 p p.signif p.adj
* <chr> <chr> <chr> <chr> <int> <int> <dbl> <chr> <dbl>
1 Petal.Length value setosa versico… 50 50 5.25e-69 **** 1.58e-68
2 Petal.Length value setosa virgini… 50 50 4.11e-91 **** 1.23e-90
3 Petal.Length value versicolor virgini… 50 50 1.81e-31 **** 5.43e-31
4 Petal.Width value setosa versico… 50 50 1.25e-57 **** 3.76e-57
5 Petal.Width value setosa virgini… 50 50 7.95e-86 **** 2.39e-85
6 Petal.Width value versicolor virgini… 50 50 8.82e-37 **** 2.65e-36
7 Sepal.Length value setosa versico… 50 50 8.77e-16 **** 2.63e-15
8 Sepal.Length value setosa virgini… 50 50 2.21e-32 **** 6.64e-32
9 Sepal.Length value versicolor virgini… 50 50 2.77e- 9 **** 8.30e- 9
10 Sepal.Width value setosa versico… 50 50 1.83e-17 **** 5.50e-17
11 Sepal.Width value setosa virgini… 50 50 4.54e-10 **** 1.36e- 9
12 Sepal.Width value versicolor virgini… 50 50 3.15e- 3 ** 9.44e- 3
# ℹ 1 more variable: p.adj.signif <chr>
Pour chacune des quatre variables, vous obtenez maintenant trois lignes — setosa vs. versicolor, setosa vs. virginica, versicolor vs. virginica — avec p.adjust.method = "bonferroni" qui corrige au sein de chaque variable sur ses trois comparaisons par paires. Le graphique suit la même recette ; add_xy_position() empile automatiquement les trois crochets par panneau :
pwc <- pwc %>% add_xy_position(x = "Species")
ggboxplot(
iris.long, x = "Species", y = "value",
fill = "Species", palette = "npg", legend = "none"
) +
facet_wrap(~variables) +
stat_pvalue_manual(
pwc, label = "p.adj.signif",
tip.length = 0.01, step.increase = 0.06
)
Chaque paire d’espèces diffère sur chaque mesure (toutes ****) sauf versicolor vs. virginica sur Sepal.Width, qui n’est que ** — précisément le quasi-recouvrement que laissaient présager les statistiques descriptives.
Ce billet exécute un t-test par paires sur de nombreuses variables — un lot de résultats indépendants. C’est différent des comparaisons par paires entre les niveaux d’un même facteur en post-hoc après une ANOVA (Tukey HSD et consorts), qui est un sujet de cursus à part entière. Si vous avez un seul résultat et un facteur à plusieurs groupes, faites d’abord l’ANOVA, puis son post-hoc — voyez la leçon sur le t-test par paires (et la leçon ANOVA en R pour le test omnibus). Ici, pairwise_t_test() n’est que l’extension multi-niveaux de l’approche par lot.
Questions fréquentes
Remodelez vos données du format large au format long avec tidyr::pivot_longer() pour que chaque mesure occupe une unique colonne value étiquetée par une colonne variables, puis enchaînez avec group_by(variables) %>% rstatix::t_test(value ~ group). Comme les données sont groupées, rstatix exécute un t-test par variable et renvoie un unique data frame ordonné de résultats — sans boucle.
Oui. Exécuter un t-test par variable revient à exécuter une famille de tests, chacun portant son propre risque de faux positif. Ajoutez adjust_pvalue(method = "BH") (Benjamini-Hochberg, contrôle le taux de fausses découvertes) ou method = "bonferroni" (plus strict, contrôle le taux d’erreur par famille) à votre pipeline et rapportez la colonne p.adj obtenue plutôt que le p brut.
t_test() compare exactement deux groupes. pairwise_t_test() compare chaque paire des niveaux d’un facteur ; utilisez-la donc quand votre variable de regroupement a trois groupes ou plus. Les deux s’insèrent dans la même approche par lot group_by(variables) %>% ... ; pairwise_t_test() renvoie simplement plusieurs lignes de comparaison par variable au lieu d’une seule, avec un argument p.adjust.method intégré.
Non — par défaut, t_test() exécute le t-test de Welch, qui ne suppose pas que les deux groupes ont des variances égales (c’est aussi le comportement par défaut de la fonction t.test() de R). Passez var.equal = TRUE si vous voulez spécifiquement le t-test de Student classique, qui met en commun la variance.
Appelez add_xy_position(x = "Species") sur votre résultat rstatix pour calculer les coordonnées des crochets, puis ajoutez stat_pvalue_manual(stat.test, label = "p.adj.signif") à un ggpubr::ggboxplot() mis en facettes avec facet_wrap(~variables). rstatix place automatiquement le crochet de chaque variable dans le bon panneau ; utilisez label = "p.adj" pour afficher la p-value ajustée numérique au lieu des étoiles.
Conclusion
Tester de nombreuses variables réponses en R ne se résume pas à quatre appels t.test() copiés-collés — c’est un seul pipeline ordonné : pivot_longer() pour passer au long, group_by(variables) %>% t_test() (ou pairwise_t_test() pour 3 groupes ou plus) pour déployer le test, adjust_pvalue() pour corriger le lot, et une boîte à moustaches ggpubr à facettes pour le montrer. Le résultat est reproductible, ajusté et prêt à publier — et le même motif passe de quatre variables à quarante.
Pour aller plus loin dans /learn
Pour les tutoriels pas à pas — soumis au contrôle de reproductibilité et vérifiant les hypothèses — qui sous-tendent cette approche par lot :
- t-test en R — le t-test à un échantillon, indépendant et apparié en entier, avec les contrôles de normalité et d’égalité des variances et la taille d’effet d de Cohen.
- ANOVA en R — le bon outil pour un résultat sur 3 groupes ou plus, ainsi que les comparaisons par paires post-hoc de Tukey.
- Biostatistique — le pilier complet, de la comparaison de deux groupes aux modèles mixtes.
Sur le même sujet
- t-test en R — le test à deux groupes en profondeur. · ANOVA en R — comparer 3 groupes ou plus. · Biostatistique — le hub du pilier.
Demandez à Prova « exécute un t-test sur chaque colonne numérique de mon data frame, groupée par traitement, et ajuste les p-values » — elle répond avec du code que vous pouvez exécuter sur vos propres données. The runtime is the judge. Demander à Prova →
Citation
@online{kassambara2026,
author = {Kassambara, Alboukadel},
title = {Tests t multiples en R : un test par variable},
date = {2026-07-13},
url = {https://www.datanovia.com/blog/multiple-t-tests-in-r-across-variables},
langid = {fr}
}