ANOVA à deux facteurs en R : deux facteurs et leur interaction
Testez deux facteurs de regroupement à la fois — leurs effets principaux et l’interaction entre eux — avec rstatix à la manière moderne, base R pour le tableau classique, en direct dans votre navigateur
Apprenez à exécuter une ANOVA à deux facteurs en R pour tester l’effet de deux facteurs et de leur interaction sur une variable numérique. Utilisez anova_test() de rstatix pour un tableau tidy avec une taille d’effet ges, et aov() + summary() de base R pour la disposition classique — avec les vérifications des conditions d’égalité des variances et de normalité, comment lire les deux effets principaux et le terme d’interaction, ce que signifie une interaction significative, les comparaisons post-hoc par effets principaux simples, et une boîte à moustaches avec les p-values dessus. Modifiez et exécutez chaque exemple en direct.
Date de publication
23 juin 2026
Modifié
7 juillet 2026
AstucePoints clés
Une ANOVA à deux facteurs teste deux facteurs de regroupement à la fois — l’effet principal de chaque facteur plus l’interaction entre eux — sur une seule variable numérique.
Utilisez anova_test() de rstatix avec une formule outcome ~ A * B pour un tableau tidy (F, p et la taille d’effet ges pour chaque terme), ou aov() + summary() de base R pour la disposition classique.
Le terme d’interaction (A:B) est le cœur d’une ANOVA à deux facteurs : une interaction significative signifie que l’effet d’un facteur dépend du niveau de l’autre — interprétez-la avant les effets principaux.
Vérifiez les deux mêmes conditions : l’homogénéité des variances (levene_test() sur les cellules) et la normalité des résidus (shapiro_test() sur les résidus du modèle).
Lorsque l’interaction est significative, poursuivez par les effets principaux simples — divisez les données selon un facteur et exécutez une analyse à un facteur dans chaque niveau — puis tracez le résultat avec les p-values dessus (stat_pvalue_manual()).
Introduction
Une ANOVA à deux facteurs (analyse de variance) répond à une question plus riche que la version à un facteur : comment deux facteurs — et leur combinaison — affectent-ils la variable ? Au lieu d’une seule variable de regroupement, les données sont classées de façon croisée selon deux facteurs (appelons- les A et B), et le test décompose la variation de la variable en un effet principal de A, un effet principal de B, et une interaction A:B.
L’interaction est la vraie raison d’exécuter une ANOVA à deux facteurs. Une interaction se produit lorsque l’effet d’un facteur change selon le niveau de l’autre — par exemple, lorsque l’éducation augmente davantage la satisfaction au travail pour un genre que pour l’autre. Cette leçon parcourt tout le flux de travail de deux manières — la moderne rstatixanova_test(), adaptée aux pipes, et le classique aov() de base R — en utilisant le jeu de données jobsatisfaction, et montre les vérifications des conditions, les relances par effets principaux simples, et comment placer les p-values sur le graphique.
Note
Hypothèses de l’ANOVA à deux facteurs. Trois hypothèses nulles : (1) les moyennes de groupe du facteur A sont égales, (2) les moyennes de groupe du facteur B sont égales, et (3) il n’y a aucune interaction entre A et B (l’effet de A est le même à chaque niveau de B). Une interaction significative signifie que l’hypothèse 3 est rejetée — les facteurs n’agissent pas indépendamment.
Les données : deux facteurs à la fois
Nous utilisons le jeu de données jobsatisfaction du package datarium — le score de satisfaction au travail pour 58 personnes, organisé par gender (homme, femme) et education_level (école, collège, université). La question de recherche : existe-t-il une interaction significative entre le genre et le niveau d’éducation sur la satisfaction au travail ? Ici education_level est la variable focale (notre préoccupation principale) et gender est le modérateur — nous demandons si l’effet de l’éducation dépend du genre.
library(rstatix)set.seed(123)data("jobsatisfaction", package ="datarium")# one random row per gender × education_level celljobsatisfaction %>%sample_n_by(gender, education_level, size =1)
# A tibble: 6 × 4
id gender education_level score
<fct> <fct> <fct> <dbl>
1 3 male school 5.07
2 12 male college 6.45
3 28 male university 8.7
4 30 female school 5.94
5 44 female college 7.1
6 53 female university 9.42
gender (2 niveaux) et education_level (3 niveaux) forment un plan factoriel 2 × 3, et la variable est score. Résumez chaque cellule avec get_summary_stats() — l’effectif, la moyenne et l’écart-type par combinaison, les chiffres derrière les graphiques qui suivent :
library(rstatix)data("jobsatisfaction", package ="datarium")jobsatisfaction %>%group_by(gender, education_level) %>%get_summary_stats(score, type ="mean_sd")
# A tibble: 6 × 6
gender education_level variable n mean sd
<fct> <fct> <fct> <dbl> <dbl> <dbl>
1 male school score 9 5.43 0.364
2 male college score 9 6.22 0.34
3 male university score 10 9.29 0.445
4 female school score 10 5.74 0.474
5 female college score 10 6.46 0.475
6 female university score 10 8.41 0.938
Regardez d’abord les données
Tracez toujours avant de tester. Une boîte à moustaches du score par gender, colorée par education_level, montre les six cellules côte à côte :
library(ggpubr)data("jobsatisfaction", package ="datarium")ggboxplot( jobsatisfaction, x ="gender", y ="score",color ="education_level", palette ="jco",xlab ="Gender", ylab ="Job satisfaction score")
Un graphique d’interaction (ggline() avec add = "mean_se", coloré par le second facteur) est la vue la plus révélatrice d’une interaction : il trace la moyenne de chaque cellule, et des lignes non parallèles suggèrent une interaction — l’écart d’éducation n’est pas identique d’un genre à l’autre :
library(ggpubr)data("jobsatisfaction", package ="datarium")ggline( jobsatisfaction, x ="gender", y ="score", color ="education_level",add ="mean_se", palette ="jco",xlab ="Gender", ylab ="Job satisfaction score")
Réaliser l’ANOVA à deux facteurs
Avec rstatix (recommandé)
anova_test() prend les données et une formule outcome ~ A * B. Le * demande à la fois les effets principaux et l’interaction (gender * education_level se développe en gender + education_level + gender:education_level). Le résultat est un tableau tidy — une ligne par terme :
Lisez-le ligne par ligne : gender (effet principal), education_level (effet principal), et gender:education_level (l’interaction). Chaque ligne donne F, DFn/DFd, p, un indicateur p<.05, et ges — la taille d’effet eta-carré généralisé. Il existe une interaction statistiquement significative entre le genre et le niveau d’éducation, F(2, 52) = 7.34, p = 0.002 — donc l’effet de l’éducation sur la satisfaction dépend du genre.
Astuce
* vs : dans la formule.gender * education_level ajuste à la fois les effets principaux et l’interaction. gender:education_level seul est le terme d’interaction uniquement. Utilisez la forme A * B pour une ANOVA à deux facteurs standard ; passez au modèle additifscore ~ gender + education_level (sans interaction) seulement lorsque l’interaction n’est pas significative.
Astuce
Exécutez-le sur vos propres données. Chargez votre fichier — mydata <- read.csv("my-file.csv") — faites de vos deux colonnes de regroupement des facteurs (mydata$A <- factor(mydata$A)), puis insérez-les dans le pipe : mydata %>% anova_test(outcome ~ A * B).
Avec base R
aov() ajuste le modèle et summary() affiche le tableau d’ANOVA classique — une ligne par terme :
Les lignes sont gender, education_level, gender:education_level et les Residuals ; F value et Pr(>F) (avec les étoiles de significativité) portent la même conclusion que l’appel rstatix. aov() affiche simplement la disposition classique et conserve le modèle ajusté pour les diagnostics et les tests post-hoc ci-dessous.
Avertissement
Pourquoi la p-value de gender diffère entre les deux tableaux.jobsatisfaction est légèrement déséquilibré (9 à 10 observations par cellule), et sur un plan déséquilibré les deux moteurs utilisent des sommes des carrés différentes : le summary(aov()) de base utilise le Type-I (séquentiel, dépendant de l’ordre), tandis qu’anova_test() utilise par défaut le Type-II. Ainsi l’effet principal de gender se lit p = 0.19 (base) vs p = 0.39 (rstatix) — tous deux non significatifs, même conclusion, nombre différent. Le terme d’interaction est identique dans les deux cas. Pour un tableau de base R qui correspond exactement à rstatix, utilisez un test de Type-II : car::Anova(res.aov.base, type = 2).
NoteLes mathématiques (optionnel)
Une ANOVA à deux facteurs partitionne la variation totale de la variable en les parts expliquées par chaque terme plus ce qu’il reste — le total (T), les deux effets principaux (A, B), leur interaction (AB) et le résidu (R) :
\[SS_T = SS_A + SS_B + SS_{AB} + SS_R\]
Chaque somme des carrés devient un carré moyen en la divisant par ses degrés de liberté, \(MS = SS / df\), et la statistique F de chaque terme est son carré moyen rapporté au carré moyen résiduel :
Il y a donc un F par terme — \(F_A\), \(F_B\) et l’interaction \(F_{AB}\) — chacun comparant la variation qu’explique ce terme à la variation inexpliquée (intra-cellule). Un grand F signifie que le terme rend compte de plus de variation que le hasard seul ne le ferait, ce que la p-value formalise.
Taille d’effet : quelle est l’ampleur de chaque terme ?
Une p-value significative dit qu’un terme compte ; la taille d’effet dit combien. anova_test() affiche déjà ges (eta-carré généralisé) par terme. Pour l’eta-carré classique, eta_squared() fonctionne sur le modèle aov() ajusté :
library(rstatix)data("jobsatisfaction", package ="datarium")eta_squared(aov(score ~ gender * education_level, data = jobsatisfaction))
education_level explique de loin la plus grande part de la variation, gender très peu, et l’interaction gender:education_level une part faible mais réelle — rapportez la taille d’effet à côté de chaque p-value, pas seulement « p < 0.05 ». Comme repère approximatif, η² ≈ 0.01 est faible, ≈ 0.06 moyen et ≥ 0.14 grand : le ges d’education_level ≈ 0.88 est très grand, celui de gender ≈ 0.01 est faible, et celui de l’interaction 0.22 est grand.
Vérifiez les hypothèses
Une ANOVA à deux facteurs repose sur les mêmes conditions que le test à un facteur (au-delà de l’indépendance des observations) : pas de valeurs aberrantes extrêmes, des résidus distribués normalement, et des cellules à variance égale.
Valeurs aberrantes
identify_outliers() signale les valeurs extrêmes dans chaque cellule — un résultat vide signifie qu’aucune ne fausserait les moyennes des cellules :
[1] gender education_level id score
[5] is.outlier is.extreme
<0 lignes> (ou 'row.names' de longueur nulle)
Il n’y avait aucune valeur aberrante extrême.
Homogénéité des variances — test de Levene
Le test de Levene demande si les six cellules partagent une variance commune. Croisez les deux facteurs dans la formule pour qu’il teste chaque cellule ; p > 0.05 signifie aucune preuve que les variances diffèrent — ce que l’on veut :
# A tibble: 1 × 4
df1 df2 statistic p
<int> <int> <dbl> <dbl>
1 5 52 2.20 0.0686
Un test de Levene non significatif signifie que l’égalité des variances tient à travers les cellules. Appuyez-le avec le graphique résidus-vs-valeurs-ajustées — une bande de points régulière à travers les moyennes ajustées des cellules (pas de forme en entonnoir) confirme une variance constante :
data("jobsatisfaction", package ="datarium")model <-aov(score ~ gender * education_level, data = jobsatisfaction)plot(model, 1) # residuals vs fitted — a flat band = equal variance
Normalité des résidus — Shapiro-Wilk + Q-Q
L’ANOVA suppose que les résidus (et non chaque cellule brute) sont normaux. Ajustez le modèle, testez les résidus avec Shapiro-Wilk (p > 0.05 → aucun écart à la normalité), et appuyez-le avec un Q-Q plot :
Avec seulement quelques groupes, vous pouvez aussi vérifier la normalité dans chaque cellule — shapiro_test() groupé selon les deux facteurs, et un Q-Q plot facetté par cellule :
# A tibble: 6 × 5
gender education_level variable statistic p
<fct> <fct> <chr> <dbl> <dbl>
1 male school score 0.980 0.966
2 male college score 0.958 0.779
3 male university score 0.916 0.323
4 female school score 0.963 0.819
5 female college score 0.963 0.819
6 female university score 0.950 0.674
Le score était distribué normalement dans chaque cellule (p > 0.05).
Note
Si les résidus s’écartent fortement de la ligne, ou si le test de Levene est significatif, les données ne correspondent pas à la classique ANOVA à deux facteurs. Consultez la leçon dédiée au test de normalité pour le flux de travail complet des hypothèses et les approches non paramétriques.
Interpréter une interaction significative
Le terme d’interaction est le cœur d’une ANOVA à deux facteurs, alors interprétez-le en premier :
Pas d’interaction significative → les facteurs agissent indépendamment. Lisez les deux effets principaux comme dans une ANOVA à un facteur, et envisagez de ré-ajuster le modèle additif plus simple score ~ gender + education_level.
Interaction significative (notre cas) → l’effet d’un facteur dépend du niveau de l’autre, donc un seul « effet principal » peut induire en erreur. Ne surinterprétez pas les effets principaux pris isolément — décomposez plutôt l’interaction en effets principaux simples : l’effet d’un facteur dans chaque niveau de l’autre.
Post-hoc : effets principaux simples
Lorsque l’interaction est significative, la bonne relance consiste en les effets principaux simples — analysez la variable focale dans chaque niveau du modérateur. Ici nous demandons : le niveau d’éducation compte-t-il dans chaque genre ? Groupez par gender, puis exécutez une anova_test() à un facteur, en passant le modèle global comme error afin qu’il utilise le terme d’erreur regroupé du modèle à deux facteurs :
L’effet principal simple du niveau d’éducation était statistiquement significatif pour les deux hommes (F(2, 52) = 132, p < 0.0001) et femmes (F(2, 52) = 62.8, p < 0.0001) — mais les statistiques F diffèrent, ce qui est l’interaction en action.
Pour voir quels niveaux d’éducation diffèrent dans chaque genre, poursuivez par des comparaisons par paires. emmeans_test() (moyennes marginales estimées, une enveloppe autour du package emmeans) exécute toutes les comparaisons par paires avec un ajustement de Bonferroni :
# A tibble: 6 × 10
gender term .y. group1 group2 df statistic p p.adj
* <fct> <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
1 male education_level score school college 52 -3.07 3.37e- 3 1.01e- 2
2 male education_level score school univer… 52 -15.3 6.87e-21 2.06e-20
3 male education_level score college univer… 52 -12.1 8.42e-17 2.53e-16
4 female education_level score school college 52 -2.94 4.95e- 3 1.49e- 2
5 female education_level score school univer… 52 -10.8 6.07e-15 1.82e-14
6 female education_level score college univer… 52 -7.90 1.84e-10 5.52e-10
# ℹ 1 more variable: p.adj.signif <chr>
Chaque ligne est une paire de niveaux d’éducation dans un genre : group1/group2 sont les niveaux, et p.adj est la p-value ajustée. Il y avait une différence significative de satisfaction au travail entre tous les groupes pour les hommes comme pour les femmes (p < 0.05).
Tracez-le avec les p-values dessus
La figure prête à publier place le résultat du test sur le graphique — l’ANOVA globale dans le sous-titre (get_test_label()) et les crochets par paires via stat_pvalue_manual(), après que add_xy_position() calcule où les crochets se placent :
C’est la figure à rapporter : le F de l’interaction, ses degrés de liberté, sa p-value et sa taille d’effet en haut, et les niveaux d’éducation qui diffèrent dans chaque genre marqués directement sur les boîtes.
Rapporter le résultat
Une rédaction de type publication mène avec l’interaction, puis les effets principaux, chacun avec son F, ses degrés de liberté, sa p-value et sa taille d’effet — par exemple :
Une ANOVA à deux facteurs a été menée pour examiner les effets du genre et du niveau d’éducation sur le score de satisfaction au travail. Il y avait une interaction statistiquement significative entre le genre et le niveau d’éducation, F(2, 52) = 7.33, p = 0.002, η² généralisé = 0.22. Une analyse des effets principaux simples pour le niveau d’éducation (ajustée par Bonferroni) a montré une différence statistiquement significative pour les hommes, F(2, 52) = 132, p < .0001, comme pour les femmes, F(2, 52) = 62.8, p < .0001. Toutes les comparaisons par paires entre niveaux d’éducation étaient significatives pour les deux genres (p < .05).
Essayez en direct
Réalisez le flux de travail complet à deux facteurs sur un jeu de données différent — warpbreaks (breaks de fil selon le type de wool et le niveau de tension). Modifiez les facteurs, la formule, ou l’étape post-hoc et réexécutez ; le bac à sable démarre au premier Run.
🟢 Avec un agent IA
Demandez à Prova« J’ai une variable numérique et deux colonnes de regroupement — réalise une ANOVA à deux facteurs sur mes données, vérifie les hypothèses, et dis-moi si les deux facteurs interagissent » — elle répond avec du code rstatix que vous pouvez exécuter sur vos propres données, puis vous aide à lire les deux effets principaux, le terme d’interaction et les suivis en effets principaux simples. The runtime is the judge.Demander à Prova →
Problèmes courants
Un facteur affiche 1 degré de liberté / est traité comme numérique. Une colonne de regroupement est encore numérique, donc l’ANOVA ajuste une pente de régression au lieu de comparer des niveaux. Faites des deux facteurs des facteurs : mydata$group <- factor(mydata$group) (dans jobsatisfaction, gender et education_level sont tous les deux déjà des facteurs).
L’interaction est significative mais je ne rapporte que les effets principaux. Lorsque A:B est significatif, les effets principaux peuvent être trompeurs à eux seuls — l’effet de A change à travers B. Interprétez d’abord l’interaction, puis décomposez-la en effets principaux simples (group_by(B) %>% anova_test(y ~ A)) plutôt que de citer une unique ligne d’effet principal.
Mes cellules ont des tailles d’échantillon inégales (plan déséquilibré). Le summary(aov()) par défaut utilise les sommes des carrés séquentielles (Type-I), qui dépendent de l’ordre des termes lorsque le plan est déséquilibré. Utilisez un test de Type-II/III — car::Anova(model, type = "II") — afin que l’ordre des termes ne change pas le résultat ; rstatix::anova_test() utilise déjà par défaut le Type-II.
Questions fréquentes
NoteQu’est-ce qu’une ANOVA à deux facteurs ?
Une ANOVA à deux facteurs teste l’effet de deux facteurs de regroupement (et de leur interaction) sur une seule variable numérique. Elle décompose la variation en un effet principal pour chaque facteur plus un terme d’interaction qui demande si les deux facteurs agissent indépendamment. En rstatix c’est mydata %>% anova_test(outcome ~ A * B) ; en base R, summary(aov(outcome ~ A * B, data = mydata)).
NoteQu’est-ce qu’un effet d’interaction dans une ANOVA à deux facteurs ?
Une interaction signifie que l’effet d’un facteur dépend du niveau de l’autre. Par exemple, l’éducation pourrait augmenter davantage la satisfaction au travail pour un genre que pour l’autre — les facteurs ne s’additionnent pas simplement. Sur un graphique d’interaction (ggline()), des lignes non parallèles sont le signe visuel d’une interaction ; la p-value de la ligne A:B est le test formel.
NoteQuelle est la différence entre une ANOVA à un facteur et une ANOVA à deux facteurs ?
Une ANOVA à un facteur compare des moyennes de groupe définies par un seul facteur. Une ANOVA à deux facteurs utilise deux facteurs à la fois, donnant un effet principal pour chacun plus l’interaction entre eux — ce qu’une analyse à un facteur ne peut pas capturer. Utilisez une ANOVA à deux facteurs lorsque chaque observation est classée selon deux variables de regroupement et que vous voulez savoir si elles interagissent.
NoteComment interpréter une interaction significative ?
Interprétez l’interaction avant les effets principaux. Un terme A:B significatif signifie qu’un seul « effet principal de A » est trompeur, car l’effet de A change à travers les niveaux de B. Décomposez-le en effets principaux simples — l’effet d’un facteur dans chaque niveau de l’autre (group_by(B) %>% anova_test(y ~ A, error = model)) — et décrivez le schéma avec des mots.
NoteQuelles sont les hypothèses d’une ANOVA à deux facteurs ?
Les mêmes qu’une ANOVA à un facteur, appliquées aux cellules : les observations sont indépendantes, il n’y a aucune valeur aberrante extrême (identify_outliers()), les résidus sont distribués normalement (shapiro_test() sur les résidus du modèle + un Q-Q plot), et les cellules ont une variance égale (levene_test(y ~ A * B)). Un plan équilibré fait aussi que le test standard se comporte le mieux ; pour un plan déséquilibré, utilisez une ANOVA de type II/III.
Testez vos connaissances
ImportantPratique
Exécutez-la. Dans la cellule en direct ci-dessous, ajustez une ANOVA à deux facteurs de la satisfaction au travail score par gender et education_levelavec leur interaction. Remplissez les blancs. Quel terme a la plus grande statistique F ? L’interaction est-elle significative ?
Conceptuel. Votre interaction gender:education_level est significative. Pourquoi est-il trompeur de ne rapporter que « l’effet principal du niveau d’éducation », et quelle analyse de relance devriez-vous exécuter à la place ?
NoteIndice
Remplissez les blancs pour que la formule soit score ~ gender * education_level — le * demande à la fois les effets principaux et l’interaction. Comparez la colonne F à travers les trois lignes. Pour la question 2, rappelez-vous qu’une interaction signifie que l’effet d’un facteur change à travers les niveaux de l’autre.
NoteSolution
library(rstatix)library(datarium)data("jobsatisfaction", package ="datarium")jobsatisfaction %>%anova_test(score ~ gender * education_level)#> education_level has the largest F (≈ 188); gender:education_level is significant (p ≈ 0.002).
education_level a la plus grande statistique F (il explique le plus de variation), et l’interaction gender:education_level est significative au seuil de 0.05.
Pour la question 2 : une interaction significative signifie que l’effet de l’éducation dépend du genre, donc un seul « effet principal de l’éducation » moyenne sur une relation qui change réellement. À la place, rapportez les effets principaux simples : divisez les données selon un facteur et exécutez une analyse à un facteur dans chaque niveau (par ex. jobsatisfaction %>% group_by(gender) %>% anova_test(score ~ education_level)), puis poursuivez par des comparaisons par paires.
Conditions violées (résidus non normaux, variances inégales) → la voie non paramétrique — voir la leçon sur le test de normalité pour le flux de travail complet.
Conclusion
Vous pouvez maintenant exécuter et interpréter une ANOVA à deux facteurs en R de deux manières : la anova_test() tidy de rstatix (avec une taille d’effet ges par terme) et le aov() + summary() classique de base R. Lisez les deux effets principaux et — surtout — l’interaction : lorsqu’elle est significative, les facteurs n’agissent pas indépendamment, donc interprétez-la en premier et décomposez-la en effets principaux simples. Vérifiez les conditions — pas de valeurs aberrantes, variance égale (levene_test) et normalité des résidus (shapiro_test) — et placez le résultat sur le graphique avec stat_pvalue_manual() pour que la figure se rapporte elle-même.
Leçons connexes
ANOVA à un facteur en R — la version à un facteur sur laquelle celle-ci s’appuie. · ANOVA à mesures répétées en R — le plan intra-sujets, lorsque les mêmes sujets sont mesurés sous chaque condition. · Test de normalité en R — la vérification Shapiro-Wilk + Q-Q des résidus sur laquelle repose l’étape des hypothèses.
Chaque résultat de cette page a été produit par le code montré, exécuté au moment du build contre un environnement R figé — modifiez n’importe quel bloc et faites Run pour le reproduire vous-même.
@online{2026,
author = {},
title = {ANOVA à deux facteurs en R : deux facteurs et leur
interaction},
date = {2026-06-23},
url = {https://www.datanovia.com/learn/biostatistics/anova/two-way-anova-in-r},
langid = {fr}
}