Test de Cochran-Mantel-Haenszel en R : association ajustée sur une variable de stratification
Tester l’association entre deux variables catégorielles tout en contrôlant une troisième — l’analyse stratifiée qui résout le paradoxe de Simpson
Apprenez à exécuter le test de Cochran-Mantel-Haenszel (CMH) en R — testez l’association entre deux variables catégorielles tout en ajustant sur une variable de stratification (de confusion), à travers une pile de tableaux 2×2. Calculez-le avec mantelhaen.test() de base, lisez l’odds ratio commun, vérifiez si les odds ratios par strate sont homogènes avec le test de Woolf, et voyez comment la stratification résout le paradoxe de Simpson.
Date de publication
23 juin 2026
Modifié
7 juillet 2026
AstucePoints clés
Le test de Cochran-Mantel-Haenszel (CMH) teste l’association entre deux variables catégorielles tout en ajustant sur une troisième (variable de stratification) — à travers une pile de tableaux 2×2, un par strate.
Exécutez-le avec mantelhaen.test() de base sur un tableau 2×2×k ; il renvoie un khi-deux, une p-value et l’ odds ratio commun (l’association après contrôle du stratificateur).
Il résout le paradoxe de Simpson — une association qui s’inverse ou disparaît dès que l’on contrôle un facteur de confusion.
Vérifiez que les odds ratios par strate sont homogènes (similaires d’une strate à l’autre) avec le test de Woolf (vcd::woolf_test()) ; s’ils diffèrent beaucoup, un odds ratio commun unique est trompeur.
Utilisez-le chaque fois qu’une variable de confusion pourrait fausser une simple association 2×2.
Introduction
Une simple association 2×2 peut être faussée par un facteur de confusion — une troisième variable liée aux deux autres. Le test de Cochran-Mantel-Haenszel gère cela en stratifiant : il découpe les données en un tableau 2×2 pour chaque niveau du facteur de confusion, puis combine l’ensemble des preuves en un seul test d’association ajusté sur le stratificateur.
L’exemple classique — et le cas d’école du paradoxe de Simpson — est le jeu de données des admissions en doctorat de Berkeley : poolés sur l’ensemble des départements, les hommes semblent admis à un taux plus élevé que les femmes ; mais dès que l’on regarde au sein de chaque département, le biais disparaît en grande partie. Cette leçon exécute le test CMH sur les données UCBAdmissions intégrées.
Note
Hypothèses du CMH.H₀ : les deux variables sont conditionnellement indépendantes sachant le stratificateur (odds ratio commun = 1). Hₐ : elles sont associées après ajustement sur le stratificateur.
Le paradoxe : poolé vs stratifié
UCBAdmissions est un tableau 2×2×6 — Admit × Gender × Department. D’abord, le tableau poolé (effondré) ignore le département :
pooled <-margin.table(UCBAdmissions, c(1, 2))pooled
Gender
Admit Male Female
Admitted 1198 557
Rejected 1493 1278
# pooled odds ratio (admitted, male vs female)(pooled["Admitted", "Male"] * pooled["Rejected", "Female"]) / (pooled["Admitted", "Female"] * pooled["Rejected", "Male"])
[1] 1.84108
L’odds ratio poolé vaut 1.84 — les chances d’admission des hommes paraissent ~84 % plus élevées. Mais cela effondre l’effet du département, et les départements diffèrent à la fois par le nombre d’hommes/femmes qui postulent et par leur sélectivité.
Exécuter le test de Cochran-Mantel-Haenszel
mantelhaen.test() garde les départements séparés (un 2×2 par département) et teste l’ association Admit × Gender ajustée sur le département :
mantelhaen.test(UCBAdmissions)
Mantel-Haenszel chi-squared test with continuity correction
data: UCBAdmissions
Mantel-Haenszel X-squared = 1.4269, df = 1, p-value = 0.2323
alternative hypothesis: true common odds ratio is not equal to 1
95 percent confidence interval:
0.7719074 1.0603298
sample estimates:
common odds ratio
0.9046968
Après ajustement sur le département, l’odds ratio commun vaut 0.90 (IC à 95 % ~0.77–1.06) et le test n’est pas significatif (p = 0.23) — le biais de genre apparent disparaît dès que l’on contrôle dans quel département les personnes ont postulé. Cette inversion entre les odds ratios poolé (1.84) et ajusté (0.90) est le paradoxe de Simpson.
Vérifier l’homogénéité des odds ratios (test de Woolf)
L’odds ratio commun ne résume bien que si les odds ratios par strate sont similaires. Le test de Woolf le vérifie :
library(vcd)woolf_test(UCBAdmissions)
Woolf-test on Homogeneity of Odds Ratios (no 3-Way assoc.)
data: UCBAdmissions
X-squared = 17.902, df = 5, p-value = 0.003072
Ici, le test de Woolf est significatif (p = 0.003) — l’odds ratio d’admission diffère réellement d’un département à l’autre (un département, de fait, favorise nettement les femmes).
Avertissement
Un test de Woolf significatif signifie que l’odds ratio commun du CMH n’est pas un résumé approprié. L’ hypothèse de Mantel-Haenszel — un odds ratio partagé unique d’une strate à l’autre — est violée, donc le 0.90 unique masque de réelles différences d’un département à l’autre. Dans ce cas, ne vous appuyez pas sur l’odds ratio commun : rapportez chaque strate, ou testez les strates individuellement (ici, avec un test exact de Fisher par département).
Lorsque les strates sont hétérogènes, exécutez le test au sein de chaque département pour localiser l’effet :
# Fisher exact test (gender vs admission) within each departmentsapply(seq_len(dim(UCBAdmissions)[3]), function(k) { f <-fisher.test(UCBAdmissions[, , k])c(odds_ratio =round(unname(f$estimate), 2), p =round(f$p.value, 4))})
Seul le département A est significatif (p < 0.001, odds ratio 0.35) — il admet les femmes à un taux plus élevé. Les cinq autres départements ne montrent aucun effet de genre significatif. La vraie histoire n’est donc pas « un léger biais global » (odds ratio commun 0.90) — c’est qu’un seul département pilote tout, ce que seule la vue stratifiée, par département, révèle.
Voir les odds ratios par strate
library(vcd)# odds ratio (male vs female admission) within each departmentor_by_dept <-sapply(seq_len(dim(UCBAdmissions)[3]), function(k) { m <- UCBAdmissions[, , k] (m["Admitted", "Male"] * m["Rejected", "Female"]) / (m["Admitted", "Female"] * m["Rejected", "Male"])})df <-data.frame(dept = LETTERS[1:6], OR =round(or_by_dept, 2))library(ggpubr)ggdotchart(df, x ="dept", y ="OR", color ="#3a86d4", dot.size =5,add ="segments", ylab ="Odds ratio (male vs female)", xlab ="Department") +geom_hline(yintercept =1, linetype ="dashed")
La plupart des départements se situent près de ou en dessous de 1 (le département A favorise nettement les femmes) — rien à voir avec le 1.84 poolé. C’est pourquoi l’analyse stratifiée est importante.
Rapport
Un test de Cochran-Mantel-Haenszel n’a trouvé aucune association significative entre le genre et l’admission après ajustement sur le département (odds ratio commun 0.90, IC à 95 % 0.77–1.06, p = 0.23), malgré un odds ratio poolé de 1.84 — un cas de paradoxe de Simpson. Un test de Woolf a indiqué que les odds ratios spécifiques aux départements étaient hétérogènes (p = 0.003), de sorte que les résultats par département sont rapportés aux côtés de l’estimation commune.
NoteLes mathématiques (optionnel)
La statistique du CMH combine les tableaux 2×2 à travers les \(k\) strates en sommant, sur les strates, la différence entre l’effectif observé et l’effectif attendu (sous indépendance conditionnelle) dans une cellule, puis en élevant le total au carré et en le divisant par la somme des variances : \(\chi^2_{CMH} = \dfrac{\left(\sum_k (a_k - E[a_k])\right)^2}{\sum_k \text{Var}(a_k)}\). L’ odds ratio commun de Mantel-Haenszel est une moyenne pondérée par strate, \(\hat{\theta}_{MH} = \dfrac{\sum_k a_k d_k / n_k}{\sum_k b_k c_k / n_k}\) — robuste même lorsque certaines strates sont clairsemées.
Essayez en direct
Exécutez le test CMH, puis effondrez l’effet du stratificateur pour voir le paradoxe. Le bac à sable démarre au premier Run (il charge vcd, laissez-lui donc un moment).
🟢 Avec un agent IA
Demandez à Prova« Je pense qu’une troisième variable est un facteur de confusion de mon association 2×2 — exécute un test de Cochran-Mantel-Haenszel stratifié dessus et donne-moi l’odds ratio ajusté » — elle répond avec du code que vous pouvez exécuter sur vos propres données stratifiées. The runtime is the judge.Demander à Prova →
Problèmes courants
Vous avez analysé le tableau poolé. Effondrer l’effet d’un facteur de confusion peut créer ou inverser une association (paradoxe de Simpson). Gardez les strates séparées et utilisez le test CMH pour obtenir l’association ajustée.
Les odds ratios sont hétérogènes. Si le test de Woolf est significatif, les strates diffèrent réellement, et un odds ratio commun unique sur-résume — rapportez aussi les estimations par strate (ou modélisez l’interaction).
Vos données ne forment pas un tableau 2×2×k.mantelhaen.test() attend un tableau tridimensionnel (lignes × colonnes × strates). Construisez-le avec xtabs(~ outcome + exposure + stratum, data = mydata) ou table().
Questions fréquentes
NoteQu’est-ce que le test de Cochran-Mantel-Haenszel ?
Il teste l’association entre deux variables catégorielles tout en ajustant sur une troisième (variable de stratification), en combinant un tableau 2×2 de chaque strate. Il renvoie un khi-deux, une p-value et l’odds ratio commun — l’association après contrôle du facteur de confusion — et c’est la façon standard de gérer une variable de confusion dans des données catégorielles.
NoteQuel est le lien entre le test CMH et le paradoxe de Simpson ?
Le paradoxe de Simpson, c’est lorsqu’une association dans les données poolées s’inverse ou disparaît dès que l’on contrôle une troisième variable. Le test CMH donne l’association ajustée (stratifiée), il révèle donc le paradoxe : dans les données de Berkeley, l’odds ratio poolé suggère un biais de genre, mais le CMH (ajusté sur le département) n’en montre aucun.
NoteÀ quoi sert le test de Woolf ?
Le test de Woolf vérifie si les odds ratios sont homogènes (similaires) d’une strate à l’autre. L’odds ratio commun du CMH n’est un résumé pertinent que dans ce cas. Si le test de Woolf est significatif, les strates diffèrent et vous devriez rapporter les odds ratios par strate plutôt que de vous fier à une unique valeur commune.
Testez vos connaissances
ImportantPratique
Exécutez-le. Dans la cellule live, exécutez le test CMH sur UCBAdmissions et le tableau poolé. Remplissez le blanc. Comment les odds ratios ajusté et poolé se comparent-ils ?
Conceptuel. Votre test de Woolf est significatif. Que vous dit-il sur le fait de rapporter un unique odds ratio commun ?
NoteIndice
Remplissez le blanc avec mantelhaen.test. Comparez son odds ratio commun (~0.90) à l’OR poolé (~1.84). Pour la question 2, rappelez-vous ce que l’odds ratio commun suppose au sujet des strates.
NoteSolution
mantelhaen.test(UCBAdmissions) #> common OR ≈ 0.90, p = 0.23 (no bias after adjustment)margin.table(UCBAdmissions, c(1, 2)) #> pooled OR ≈ 1.84 (apparent bias)
Pour la question 2 : un test de Woolf significatif signifie que les odds ratios diffèrent d’une strate à l’autre, donc un unique odds ratio commun sur-résume et peut induire en erreur — rapportez les odds ratios par strate (ou modélisez l’interaction strate × exposition) plutôt que de vous fier à la seule estimation CMH poolée.
AstuceQuel test, quand ?
Deux variables catégorielles, ajustées sur un stratificateur → Cochran-Mantel-Haenszel (cette leçon).
Vous savez désormais exécuter le test de Cochran-Mantel-Haenszel en R : construire le tableau 2×2×k, exécuter mantelhaen.test() pour l’association et l’odds ratio commun ajusté sur le stratificateur, et vérifier le test de Woolf pour l’homogénéité des odds ratios par strate. C’est l’outil pour contrôler un facteur de confusion dans des données catégorielles — et la démonstration la plus nette de pourquoi l’analyse stratifiée l’emporte sur un 2×2 poolé (paradoxe de Simpson). Pour ajuster sur de nombreuses variables à la fois, passez à la régression logistique.
Prouvez que vous savez le faire. Maîtrisez toute la série Analyse catégorielle en R — suivez votre parcours, construisez des projets et obtenez un certificat.
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 = {Test de Cochran-Mantel-Haenszel en R : association ajustée
sur une variable de stratification},
date = {2026-06-23},
url = {https://www.datanovia.com/learn/biostatistics/categorical/cochran-mantel-haenszel-test-in-r},
langid = {fr}
}