{"id":227,"date":"2014-10-27T11:43:54","date_gmt":"2014-10-27T10:43:54","guid":{"rendered":"http:\/\/perso.ens-lyon.fr\/lise.vaudor\/?p=227"},"modified":"2026-04-02T14:11:28","modified_gmt":"2026-04-02T12:11:28","slug":"test-de-wilcoxon-mann-whitney","status":"publish","type":"post","link":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/test-de-wilcoxon-mann-whitney\/","title":{"rendered":"Test de Wilcoxon-Mann-Whitney"},"content":{"rendered":"<p><img decoding=\"async\" src=\"..\/..\/lise.vaudor\/Rfigures\/Mann_Whitney_U_test\/Lise_Vaudor_headband-1.png\" alt=\"\" \/><br \/>\n<small> Mise \u00e0 jour de ce billet: novembre 2020. =&gt; passage au<br \/>\ntidyverse pour la manipulation des tables de donn\u00e9es et les graphiques.<br \/>\n<\/small><\/p>\n<h1>A quoi sert-il?<\/h1>\n<p>Le <strong>test U de Mann-Whitney<\/strong> (aussi appel\u00e9 <strong>test de la somme des rangs<br \/>\nde Wilcoxon<\/strong> ou plus simplement <strong>test de Wilcoxon<\/strong>) sert \u00e0 tester<br \/>\nl\u2019hypoth\u00e8se selon laquelle <strong>la distribution des donn\u00e9es est la m\u00eame<br \/>\npour deux groupes<\/strong>.<\/p>\n<p>La <strong>p-value<\/strong> associ\u00e9e \u00e0 ce test va ainsi r\u00e9pondre \u00e0 la question<br \/>\nsuivante:<\/p>\n<p>Si les donn\u00e9es pour les deux groupes \u00e9taient issues d\u2019une <strong>m\u00eame<br \/>\npopulation<\/strong>, quelle serait la <strong>probabilit\u00e9 que l\u2019on observe par hasard<br \/>\nune diff\u00e9rence de rangs(ou localisations) entre les deux groupes aussi<br \/>\nforte que celle observ\u00e9e sur les donn\u00e9es<\/strong>?<\/p>\n<p>Le test U de Mann-Whitney est souvent utilis\u00e9 comme solution alternative<br \/>\n\u00e0 l\u2019utilisation d\u2019un <strong>test de Student (t-test)<\/strong> dans le cas o\u00f9 les<br \/>\ndonn\u00e9es ne sont pas distribu\u00e9es selon une loi normale et\/ou dans le cas<br \/>\no\u00f9 les donn\u00e9es sont peu nombreuses. Il s\u2019agit en effet d\u2019un <strong>test<br \/>\nnon-param\u00e9trique<\/strong>, i.e.\u00a0un test qui ne repose pas sur une hypoth\u00e8se de<br \/>\ndistribution des donn\u00e9es.<\/p>\n<h1>Un exemple<\/h1>\n<p>Consid\u00e9rons les donn\u00e9es suivantes:<\/p>\n<pre><code>library(tidyverse)\n\ntib=tibble(x=c(\"A\",\"A\",\"A\",\"A\",\"A\",\"A\",\"A\", \"A\" ,\n               \"B\",\"B\",\"B\",\"B\",\"B\",\"B\"),\n           y=c(1.5,6.3,2.4,4.1,1.2,5.3,15.2,10.6,\n               2.5,3.3,1.3,2.1,5.7,1.1))\nggplot(tib, aes(x=x, y=y))+\n  geom_boxplot(aes(fill=x))+\n  scale_fill_manual(values=c(\"A\"=\"pink\",\n                             \"B\"=\"lightsteelblue3\"))\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"..\/..\/lise.vaudor\/Rfigures\/Mann_Whitney_U_test\/distribs_simples-1.png\" alt=\"\" \/><\/p>\n<p>On a ici des donn\u00e9es qui ne sont ni franchement nombreuses, ni<br \/>\nfranchement normales.<\/p>\n<h1>Comment faire un test U de Mann-Whitney sous R?<\/h1>\n<pre><code>montest=wilcox.test(y~x, data=tib)\nmontest\n\n## \n##  Wilcoxon rank sum test\n## \n## data:  y by x\n## W = 34, p-value = 0.2284\n## alternative hypothesis: true location shift is not equal to 0\n<\/code><\/pre>\n<p>Ici, la p-value est plus grande que 0.05: on ne parvient pas \u00e0 rejeter<br \/>\nl\u2019hypoth\u00e8se selon laquelle les donn\u00e9es des deux groupes proviennent<br \/>\nd\u2019une m\u00eame distribution au seuil <em>\u03b1<\/em>\u2004=\u20040.05.<\/p>\n<h1>Sur quelle m\u00e9trique le test de Mann-Whitney se base-t-il?<\/h1>\n<p>Le test U de Mann-Whitney calcule une p-value qui se base non pas sur<br \/>\nles donn\u00e9es brutes, mais sur leurs <strong>rangs<\/strong>. Les rangs en question<br \/>\ncorrespondent \u00e0 l\u2019<strong>emplacement de chaque donn\u00e9e au sein de la s\u00e9rie<\/strong><br \/>\nlorque cette s\u00e9rie est <strong>ordonn\u00e9e<\/strong> par ordre croissant.<\/p>\n<pre><code>tib=tib %&gt;%\n  mutate(rangs=rank(y))\ntib\n\n## # A tibble: 14 x 3\n##    x         y rangs\n##    &lt;chr&gt; &lt;dbl&gt; &lt;dbl&gt;\n##  1 A       1.5     4\n##  2 A       6.3    12\n##  3 A       2.4     6\n##  4 A       4.1     9\n##  5 A       1.2     2\n##  6 A       5.3    10\n##  7 A      15.2    14\n##  8 A      10.6    13\n##  9 B       2.5     7\n## 10 B       3.3     8\n## 11 B       1.3     3\n## 12 B       2.1     5\n## 13 B       5.7    11\n## 14 B       1.1     1\n<\/code><\/pre>\n<p>Les distributions des rangs sont beaucoup moins affect\u00e9es par<br \/>\nl\u2019existence de valeurs extr\u00eames que ne le sont les distributions des<br \/>\nvaleurs brutes:<\/p>\n<pre><code>ggplot(tib, aes(x=x, y=rangs))+\n  geom_boxplot(aes(fill=x))+\n  scale_fill_manual(values=c(\"A\"=\"pink\",\n                             \"B\"=\"lightsteelblue3\"))\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"..\/..\/lise.vaudor\/Rfigures\/Mann_Whitney_U_test\/distribs_rangs-1.png\" alt=\"\" \/><\/p>\n<p>Repr\u00e9sentons les rangs des individus ainsi que l\u2019appartenance de ces<br \/>\nindividus aux deux groupes. Les individus du groupe A sont repr\u00e9sent\u00e9s<br \/>\nen rose, les individus du groupe B en bleu. Les pointill\u00e9s repr\u00e9sentent<br \/>\nla moyenne des rangs pour chacun des groupes<\/p>\n<pre><code>tib_summary=tib %&gt;% \n  group_by(x) %&gt;% \n  summarise(loc=mean(rangs),\n            .groups=\"drop\")\n\nggplot(tib %&gt;% mutate(xx=0),\n  aes(x=xx,y=rangs))+\n  geom_point(aes(col=x), pch=15, size=4)+\n  geom_hline(data=tib_summary,\n             aes(yintercept=loc, col=x))+\n  scale_color_manual(values=c(\"A\"=\"pink\",\n                              \"B\"=\"lightsteelblue3\"))+\n  guides(x=\"none\")+xlab(\"\")\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"..\/..\/lise.vaudor\/Rfigures\/Mann_Whitney_U_test\/rangs-1.png\" alt=\"\" \/><\/p>\n<p>Le test de Mann-Whitney peut se baser sur une m\u00e9trique <em>W<\/em> (en lien avec<br \/>\nla d\u00e9nomination \u201ctest de Wilcoxon\u201d) qui correspond \u00e0<br \/>\n<code><span class=\"katex-eq\" data-katex-display=\"false\">\n\nW=W_A=\\sum_{i=1}^{n}\\mathbf{1}_A R_i-n_A(n_A+1)\/2\n\n<\/span><\/code><br \/>\nOn peut aussi d\u00e9finir <em>W<\/em><sub><em>B<\/em><\/sub> :<br \/>\n<code><span class=\"katex-eq\" data-katex-display=\"false\">\n\nW_B=\\sum_{i=1}^{n}\\mathbf{1}_B R_i-n_B(n_B+1)\/2\n\n<\/span><\/code><br \/>\n<em>n<\/em> correspond \u00e0 l\u2019effectif total, <em>n<\/em><sub><em>A<\/em><\/sub> l\u2019effectif du<br \/>\ngroupe A, <em>n<\/em><sub><em>B<\/em><\/sub> l\u2019effectif du groupe <em>B<\/em>, et<br \/>\n<em>R<\/em><sub><em>i<\/em><\/sub> correspond au rang du i-i\u00e8me individu.<\/p>\n<p>Les nombres <em>n<\/em><sub><em>A<\/em><\/sub>(<em>n<\/em><sub><em>A<\/em><\/sub>\u2005+\u20051)\/2 et<br \/>\n<em>n<\/em><sub><em>B<\/em><\/sub>(<em>n<\/em><sub><em>B<\/em><\/sub>\u2005+\u20051)\/2 correspondent en fait \u00e0 ce<br \/>\nque serait la somme des rangs si tous les individus du groupe A<br \/>\n(respectivement B) avaient les rangs 1,2,3,\u2026.,<em>n<\/em><sub><em>A<\/em><\/sub><br \/>\n(respectivement 1,2,3,\u2026,<em>n<\/em><sub><em>B<\/em><\/sub>).<\/p>\n<p><em>W<\/em> est ainsi d\u2019autant plus grand que les individus du groupe A pr\u00e9sente<br \/>\ndes rangs \u00e9lev\u00e9s au sein de l\u2019ensemble des individus.<\/p>\n<p>Alternativement, on pourrait consid\u00e9rer la m\u00e9trique <em>U<\/em> (en lien avec la<br \/>\nd\u00e9nomination \u201ctest U de Mann-Whitney\u201d) qui correspond \u00e0:<br \/>\n<code><span class=\"katex-eq\" data-katex-display=\"false\">\n\nU=min(W_A,W_B)<\/span><br \/>\n<\/code><br \/>\nCette m\u00e9trique est quant \u00e0 elle d\u2019autant plus faible que l\u2019un ou l\u2019autre<br \/>\ndes groupes pr\u00e9sente des rangs bas.<\/p>\n<p>Calculons la m\u00e9trique <em>W<\/em> pour nos donn\u00e9es:<\/p>\n<pre><code>tib_summary=tib %&gt;% \n  group_by(x)%&gt;% \n  summarise(n=n(),\n            loc=mean(rangs),\n            SR_0=n*(n+1)\/2,\n            SR=sum(rangs),\n            W=SR-SR_0,\n            .groups=\"drop\")\ntib_summary\n\n## # A tibble: 2 x 6\n##   x         n   loc  SR_0    SR     W\n##   &lt;chr&gt; &lt;int&gt; &lt;dbl&gt; &lt;dbl&gt; &lt;dbl&gt; &lt;dbl&gt;\n## 1 A         8  8.75    36    70    34\n## 2 B         6  5.83    21    35    14\n<\/code><\/pre>\n<p>On retrouve bien la valeur de <em>W<\/em> (34) qui \u00e9tait indiqu\u00e9e en sortie du<br \/>\ntest de Mann-Whitney r\u00e9alis\u00e9 ci-dessus.<\/p>\n<p>En l\u2019occurence, par construction on a toujours<br \/>\n<code><span class=\"katex-eq\" data-katex-display=\"false\">\n\nW_A+W_B=n_An_B\n\n<\/span><\/code><br \/>\nOn peut le v\u00e9rifier ici:<\/p>\n<pre><code>tib_summary %&gt;% \n  summarise(sum(W),\n            prod(n),\n            .groups=\"drop\")\n\n## # A tibble: 1 x 2\n##   `sum(W)` `prod(n)`\n##      &lt;dbl&gt;     &lt;dbl&gt;\n## 1       48        48\n<\/code><\/pre>\n<h1>A quoi la p-value correspond-elle?<\/h1>\n<p>Supposons que <strong>le groupe A ne corresponde pas \u00e0 des rangs<br \/>\nparticuli\u00e8rement \u00e9lev\u00e9s dans la s\u00e9rie<\/strong>. Dans ce cas, les rangs observ\u00e9s<br \/>\npour A sont comme \u201cattribu\u00e9s au hasard\u201d. Quelle est alors la<br \/>\ndistribution de <em>W<\/em>?<\/p>\n<p>Pour r\u00e9pondre \u00e0 cette question nous allons <strong>simuler un grand nombre<br \/>\nd\u2019\u00e9chantillons au hasard<\/strong><\/p>\n<ul>\n<li>correspondant \u00e0 des rangs entre 1 et<br \/>\n<em>n<\/em><sub><em>A<\/em><\/sub>\u2005+\u2005<em>n<\/em><sub><em>B<\/em><\/sub>\u2004=\u200414<\/li>\n<li>tels que <em>n<\/em><sub><em>A<\/em><\/sub>\u2004=\u20048 des individus soient \u00e9tiquet\u00e9s comme<br \/>\nappartenant au groupe A<\/li>\n<li>tels que <em>n<\/em><sub><em>B<\/em><\/sub>\u2004=\u20046 des individus soient \u00e9tiquet\u00e9s comme<br \/>\nappartenant au groupe B<\/li>\n<\/ul>\n<p>Nous calculerons pour chaque simulation la valeur de <em>W<\/em>.<\/p>\n<pre><code>niter=10000\nvecteur_W=rep(NA,niter)\nfor (i in 1:niter){\n  tib_sim=tib %&gt;% \n    # On r\u00e9attribue au hasard les rangs aux donn\u00e9es\n    # (i.e. aux diff\u00e9rents groupes):\n    mutate(r_sim=sample(rangs,n(),replace=F)) %&gt;% \n    group_by(x) %&gt;% \n    # On calcule la statistique correspondant \u00e0\n    # la somme des rangs observ\u00e9s SR_i\n    summarise(n=n(),\n              SR_0=n*(n+1)\/2,\n              SR_i=sum(r_sim),\n            .groups=\"drop\") %&gt;%\n    # On calcule la statistique W\n    mutate(Wsim=SR_i-SR_0)\n    # On r\u00e9cup\u00e8re W_A pour l'it\u00e9ration,\n    # et on la stocke dans vecteur_W\n  vecteur_W[i]=tib_sim %&gt;% filter(x==\"A\") %&gt;% pull(Wsim)\n}\n\nhist(vecteur_W,freq=F,\n     col=\"lemonchiffon\",\n     main=\"distrib. de W sous hypoth\u00e8se nulle\")\nabline(v=tib_summary %&gt;% filter(x==\"A\") %&gt;% pull(W), lty=3,lwd=3, col=\"red\")\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"..\/..\/lise.vaudor\/Rfigures\/Mann_Whitney_U_test\/hist_W-1.png\" alt=\"\" \/><\/p>\n<p>La distribution empirique de W nous permet de calculer la p-value<br \/>\ncorrespondant au test de l\u2019hypoth\u00e8se \u201cA n\u2019a pas une localisation<br \/>\nparticuli\u00e8rement \u00e9lev\u00e9e\u201d.<\/p>\n<pre><code>wilcox.test(y~x,alternative=\"less\", data=tib)\n\n## \n##  Wilcoxon rank sum test\n## \n## data:  y by x\n## W = 34, p-value = 0.9094\n## alternative hypothesis: true location shift is less than 0\n\nprint(length(which(vecteur_W&gt;=montest$statistic))\/niter)\n\n## [1] 0.1167\n<\/code><\/pre>\n<p>Ici on veut en fait faire un test <strong>bilat\u00e9ral<\/strong> : notre hypoth\u00e8se nulle<br \/>\n\u201cla distribution des donn\u00e9es est la m\u00eame pour les deux groupes\u201d<br \/>\ncorrespond en fait \u00e0 deux sous-hypoth\u00e8ses:<\/p>\n<ul>\n<li>\u201cA n\u2019a pas une localisation particuli\u00e8rement \u00e9lev\u00e9e\u201d ET<\/li>\n<li>\u201cA n\u2019a pas une localisation particuli\u00e8rement basse\u201d (i.e.\u00a0\u201cB n\u2019a pas<br \/>\nune localisation particuli\u00e8rement \u00e9lev\u00e9e\u201d)<\/li>\n<\/ul>\n<p>On s\u2019interroge ainsi non seulement sur la distribution de<br \/>\n<em>W<\/em><sub><em>A<\/em><\/sub> mais aussi sur la distribution de <em>W<\/em><sub><em>B<\/em><\/sub>.<\/p>\n<p>Or ces deux distributions sont en fait les m\u00eames\u2026 Vous pouvez le<br \/>\nv\u00e9rifier comme suit:<\/p>\n<pre><code>layout(matrix(1:2,nrow=1))\nvecteur_W_A=vecteur_W\nvecteur_W_B=tib_summary %&gt;% mutate(prodn=prod(n)) %&gt;% pull(prodn)-vecteur_W_A\n\nhist(vecteur_W_A,freq=F,\n     col=\"lemonchiffon\",\n     main=\"distrib. de W_A\")\nhist(vecteur_W_B,freq=F,\n     col=\"lemonchiffon\",\n     main=\"distrib. de W_B\")\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"..\/..\/lise.vaudor\/Rfigures\/Mann_Whitney_U_test\/hist_W_A_W_B-1.png\" alt=\"\" \/><\/p>\n<p>On peut ainsi retrouver la p-value fournie par le test:<\/p>\n<pre><code>print(2*length(which(vecteur_W&gt;=montest$statistic))\/niter)\n\n## [1] 0.2334\n\nprint(montest$p.value)\n\n## [1] 0.2284382\n<\/code><\/pre>\n<h1>Comment R calcule-t-il la p-value?<\/h1>\n<p>Ci-dessus, j\u2019ai montr\u00e9 comment on peut recalculer \u201c\u00e0 la main\u201d la p-value<br \/>\nfournie par le test. En fait, pour des valeurs de <em>n<\/em><sub><em>A<\/em><\/sub> et<br \/>\n<em>n<\/em><sub><em>B<\/em><\/sub> assez \u00e9lev\u00e9es, la distribution de W est<br \/>\napproximativement normale (R n\u2019a pas besoin d\u2019effectuer des simulations,<br \/>\ncomme nous l\u2019avons fait, pour calculer la p-value).<\/p>\n<p>Pour des valeurs de <em>n<\/em><sub><em>A<\/em><\/sub> et <em>n<\/em><sub><em>B<\/em><\/sub> relativement<br \/>\nfaibles, les p-values sont <strong>tabul\u00e9es<\/strong> (c\u2019est-\u00e0-dire que pour des<br \/>\nvaleurs <em>n<\/em><sub><em>A<\/em><\/sub> et <em>n<\/em><sub><em>B<\/em><\/sub> faibles, R a en m\u00e9moire<br \/>\nles quantiles de la distribution de W). Cependant, de la m\u00eame mani\u00e8re<br \/>\nque dans nos simulations ci-dessus, ces p-values ont \u00e9t\u00e9 calcul\u00e9es en<br \/>\nsupposant qu\u2019il n\u2019y avait <strong>pas d\u2019ex-aequos<\/strong> (i.e.\u00a0pour calculer ces<br \/>\nquantiles, il a \u00e9t\u00e9 suppos\u00e9 que les rangs \u00e9taient 1,2,3,\u2026.,n, et non,<br \/>\npar exemple, 2,2,2,3,4,5,\u2026,n). C\u2019est la raison pour laquelle R affiche<br \/>\ndes Warnings dans le cas o\u00f9<\/p>\n<ul>\n<li>les donn\u00e9es sont peu nombreuses ET<\/li>\n<li>il y a des ex-aequos.<\/li>\n<\/ul>\n<p><!-- --><\/p>\n<pre><code>tib=tibble(x=c(\"A\",\"A\",\"A\",\"A\",\n               \"B\",\"B\",\"B\",\"B\",\"B\",\"B\"),\n           y=c(1.5,6.3,6.3,2.7,\n               2.5,3.3,1.3,2.1,5.7,1.1))\n\nwilcox.test(y~x, data=tib)\n\n## Warning in wilcox.test.default(x = c(1.5, 6.3, 6.3, 2.7), y = c(2.5, 3.3, : cannot compute exact p-value with ties\n\n## \n##  Wilcoxon rank sum test with continuity correction\n## \n## data:  y by x\n## W = 18, p-value = 0.2395\n## alternative hypothesis: true location shift is not equal to 0\n<\/code><\/pre>\n<p>Pour des \u00e9chantillons plus grands, on n\u2019a pas ce m\u00eame message d\u2019erreur<br \/>\ncar la p-value est calcul\u00e9e en se basant sur l\u2019approximation normale:<\/p>\n<pre><code>tib=tibble(x=c(rep(\"A\",50)   , rep(\"B\",50)),\n           y=c(rlnorm(50,3,2), rlnorm(50,4,2))) %&gt;% \n  # repetition des 10 premieres valeurs =&gt; ex-aequos\n  mutate(y=c(y[11:20],y[11:100])) \nwilcox.test(y~x, data=tib)\n\n## \n##  Wilcoxon rank sum test with continuity correction\n## \n## data:  y by x\n## W = 1045, p-value = 0.1586\n## alternative hypothesis: true location shift is not equal to 0\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Mise \u00e0 jour de ce billet: novembre 2020. =&gt; passage au tidyverse pour la manipulation des tables de donn\u00e9es et les graphiques. A quoi sert-il? Le test U de Mann-Whitney (aussi appel\u00e9 test de la somme des rangs de Wilcoxon ou plus simplement test de Wilcoxon) sert \u00e0 tester l\u2019hypoth\u00e8se selon laquelle la distribution des donn\u00e9es est la m\u00eame pour deux groupes. La p-value associ\u00e9e \u00e0 ce test va ainsi.. <a href=\"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/test-de-wilcoxon-mann-whitney\/\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-227","post","type-post","status-publish","format-standard","hentry","category-tous-les-posts"],"_links":{"self":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts\/227","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/comments?post=227"}],"version-history":[{"count":35,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts\/227\/revisions"}],"predecessor-version":[{"id":1540,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts\/227\/revisions\/1540"}],"wp:attachment":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/media?parent=227"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/categories?post=227"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/tags?post=227"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}