{"id":2933,"date":"2017-01-09T21:35:37","date_gmt":"2017-01-10T02:35:37","guid":{"rendered":"http:\/\/bioinfo.iric.ca\/?p=2933\/"},"modified":"2017-04-29T17:50:55","modified_gmt":"2017-04-29T21:50:55","slug":"une-implementation-en-javascript-de-la-version-non-centree-du-test-exact-de-fisher","status":"publish","type":"post","link":"https:\/\/bioinfo.iric.ca\/fr\/une-implementation-en-javascript-de-la-version-non-centree-du-test-exact-de-fisher\/","title":{"rendered":"Une impl\u00e9mentation en javascript de la version non centr\u00e9e du test exact de Fisher"},"content":{"rendered":"<p class=\"p1\">Mon <a href=\"https:\/\/bioinfo.iric.ca\/fr\/trafiquer-le-test-exact-de-fisher-pour-les-besoins-du-biologiste\/\">article pr\u00e9c\u00e9dent<\/a> expliquait pourquoi la version non-centr\u00e9e du test exact de Fisher est plus appropri\u00e9e dans la plupart des cas rencontr\u00e9s en bio-informatique. Je poursuis en pr\u00e9sentant maintenant une impl\u00e9mentation de ce test en Javascript qui pourrait\u00a0facilement \u00eatre int\u00e9gr\u00e9e \u00e0 une interface web.<\/p>\n<p class=\"p1\">M\u00eame si le Javascript est un\u00a0langage tr\u00e8s mal adapt\u00e9 \u00e0 l&rsquo;impl\u00e9mentation\u00a0de\u00a0m\u00e9thodes statistiques, j&rsquo;esp\u00e8re que cet article pr\u00e9sentera tous les d\u00e9tails n\u00e9cessaires pour simplifier\u00a0l&rsquo;impl\u00e9mentation de ce test dans d&rsquo;autres langages, selon les besoins. \u00c0 tout le moins, cet exemple\u00a0devrait d\u00e9mystifier le fonctionnement interne de ce test tr\u00e8s utile. \u00c0 noter que je me limiterai seulement aux tables de contingence $2\\times 2$. Avant de plonger, je dois admettre avoir \u00e9t\u00e9 tr\u00e8s agr\u00e9ablement surpris de\u00a0la performance de ce code!<\/p>\n<p class=\"p1\">Les premi\u00e8res fonctions ci-dessous calculent diff\u00e9rentes expressions requises par la <a href=\"http:\/\/en.wikipedia.org\/wiki\/Fisher's_noncentral_hypergeometric_distribution\">distribution hyperg\u00e9om\u00e9trique non-centr\u00e9e<\/a>. Plus pr\u00e9cis\u00e9ment, elles utilisent des log-probabilit\u00e9s pour \u00e9viter la manipulation de petits nombres ce qui risquerait de produire un <em><a href=\"https:\/\/en.wikipedia.org\/wiki\/Arithmetic_underflow\">underflow<\/a><\/em>.<\/p>\n<pre><code class='javascript'>\u00a0\u00a0function <strong>lngamm<\/strong> (z) {\r\n     \/\/ Reference: \"Lanczos, C. 'A precision approximation\r\n  \u00a0 \u00a0\/\/ of the gamma function', J. SIAM Numer. Anal., B, 1, 86-96, 1964.\"\r\n  \u00a0 \u00a0\/\/ Translation of\u00a0 Alan Miller's FORTRAN-implementation\r\n  \u00a0 \u00a0\/\/ See http:\/\/lib.stat.cmu.edu\/apstat\/245\r\n \u00a0 \u00a0 \r\n \u00a0 \u00a0 var x = 0;\r\n  \u00a0 \u00a0x += 0.1659470187408462e-06 \/ (z + 7);\r\n  \u00a0 \u00a0x += 0.9934937113930748e-05 \/ (z + 6);\r\n  \u00a0 \u00a0x -= 0.1385710331296526 \u00a0 \u00a0 \/ (z + 5);\r\n  \u00a0 \u00a0x += 12.50734324009056\u00a0 \u00a0 \u00a0 \/ (z + 4);\r\n  \u00a0 \u00a0x -= 176.6150291498386\u00a0 \u00a0 \u00a0 \/ (z + 3);\r\n  \u00a0 \u00a0x += 771.3234287757674\u00a0 \u00a0 \u00a0 \/ (z + 2);\r\n  \u00a0 \u00a0x -= 1259.139216722289\u00a0 \u00a0 \u00a0 \/ (z + 1);\r\n  \u00a0 \u00a0x += 676.5203681218835\u00a0 \u00a0 \u00a0 \/ (z);\r\n  \u00a0 \u00a0x += 0.9999999999995183;\r\n  \u00a0 \u00a0return (Math.log (x) - 5.58106146679532777 - z + (z - 0.5) * Math.log (z + 6.5));\r\n  }<\/code><\/pre>\n<pre><code class='javascript'> \u00a0function <strong>lnfact<\/strong> (n) {\r\n  \u00a0 \u00a0if (n &lt;= 1) return (0);\r\n  \u00a0 \u00a0return (lngamm (n + 1));\r\n  }\r\n \u00a0 \r\n \u00a0function <strong>lnbico<\/strong> (n, k) {\r\n  \u00a0 \u00a0return (lnfact (n) - lnfact (k) - lnfact (n - k));\r\n  }<\/code><\/pre>\n<p class=\"p1\">La fonction \u00ab\u00a0lnbico\u00a0\u00bb (<em><span style=\"text-decoration: underline;\">ln<\/span> of the <span style=\"text-decoration: underline;\">bi<\/span>nomial <span style=\"text-decoration: underline;\">co<\/span>efficient<\/em>) retourne le log du nombre de combinaisons possibles pour choisir<br \/>\n$k$ dans $n$:<\/p>\n<p class=\"p1\"><div class=\"fusion-fullwidth fullwidth-box fusion-builder-row-1 hundred-percent-fullwidth non-hundred-percent-height-scrolling\" style=\"--awb-border-radius-top-left:0px;--awb-border-radius-top-right:0px;--awb-border-radius-bottom-right:0px;--awb-border-radius-bottom-left:0px;--awb-overflow:visible;--awb-flex-wrap:wrap;\" ><div class=\"fusion-builder-row fusion-row\"><div class=\"fusion-layout-column fusion_builder_column fusion-builder-column-0 fusion_builder_column_1_1 1_1 fusion-one-full fusion-column-first fusion-column-last fusion-column-no-min-height\" style=\"--awb-bg-size:cover;--awb-margin-bottom:0px;\"><div class=\"fusion-column-wrapper fusion-flex-column-wrapper-legacy\">\\begin{eqnarray*}<br \/>\n\\binom{n}{k} &amp; = &amp; \\frac{n!}{k!(n-k)!}\\\\<br \/>\n\\mbox{lnfact}(n) &amp; = &amp; \\ln(n!)\\\\<br \/>\n\\mbox{lnbico}(n,k) &amp; = &amp; \\ln\\binom{n}{k}\\\\<br \/>\n&amp; = &amp; \\mbox{lnfact}(n) &#8211; (\\mbox{lnfact}(k) + \\mbox{lnfact}(n &#8211; k))<br \/>\n\\end{eqnarray*}<\/p>\n<p class=\"p1\">La distribution de probabilit\u00e9s de la loi hyperg\u00e9om\u00e9trique non-centr\u00e9e est la suivante (o\u00f9 $\\omega$ est le seuil du odds-ratio):<\/p>\n<p class=\"p1\">\\[<br \/>\n\\frac{\\binom{m_1}{x} \\binom{m_2}{n-x} \\omega^x}{<br \/>\n\\sum_{y=x_{\\min}}^{x_{\\max}} \\binom{m_1}{y} \\binom{m_2}{n &#8211; y} \\omega^y<br \/>\n}\\]\n<p class=\"p1\">O\u00f9<\/p>\n<p class=\"p1\">\\[\\begin{eqnarray*}<br \/>\nx_{\\min} &amp; = &amp; \\max(0, n &#8211; m_2)\\\\<br \/>\nx_{\\max} &amp; = &amp; \\min(n, m_1)<br \/>\n\\end{eqnarray*}\\]\n<p class=\"p1\">Notation utilis\u00e9e dans le code pour la matrice de contingence et les totaux:<\/p>\n<p class=\"p1\">\\[\\begin{array}{|cc||c}\\hline<br \/>\n\\bf n_{11} &amp; \\bf n_{12} &amp; n \\\\<br \/>\n\\bf n_{21} &amp; \\bf n_{22} &amp;\u00a0 \\\\\\hline\\hline<br \/>\nm_1 &amp; m_2 &amp;\u00a0 \\\\<br \/>\n\\end{array}\\]\n<p class=\"p1\">Pour calculer une p-value pour le test, les comptes doivent \u00eatre r\u00e9arrang\u00e9s et j&rsquo;ai utilis\u00e9 la notation suivante:<\/p>\n<p class=\"p1\">\\[\\begin{array}{|cc||c}\\hline<br \/>\nx &amp; ? &amp; n \\\\<br \/>\n? &amp; ? &amp;\u00a0 \\\\\\hline\\hline<br \/>\nm_1 &amp; m_2 &amp;\u00a0 \\\\<br \/>\n\\end{array}\\]\n<p class=\"p1\">Ici, d\u00e9cider d&rsquo;un $x$ permet de remplir la table en utilisant les totaux. La p-value du test exact de Fisher est ensuite calcul\u00e9e en additionnant les probabilit\u00e9s pour le sc\u00e9nario o\u00f9 $x$ est plus grand que la valeur observ\u00e9e $n_{11}$. Ceci est gard\u00e9 dans \u00ab\u00a0den_sum\u00a0\u00bb et est calcul\u00e9 par la derni\u00e8re boucle \u00ab\u00a0for\u00a0\u00bb de la fonction. Notez que toutes les sommes proviennent de probabilit\u00e9s ajust\u00e9es ( &#8211; max_l en espace log). Cela \u00e9vite de faire la somme de tr\u00e8s petits nombres, ce qui pourrait conduire \u00e0 un <em>underflow<\/em>. Comme la p-value finale est le r\u00e9sultat d&rsquo;un ratio, le facteur d&rsquo;ajustement s&rsquo;annule de lui-m\u00eame dans Math.exp (den_sum &#8211; sum_l). Finalement, \u00ab\u00a0w\u00a0\u00bb est utilis\u00e9 pour passer le seuil requis pour le odds-ratio ($\\omega$).<\/p>\n<pre class=\"p1\"> <code class='javascript'>function <strong>exact_nc<\/strong> (n11, n12, n21, n22, w) {\r\n   var x = n11;\r\n   var m1 = n11 + n21;\r\n   var m2 = n12 + n22;\r\n   var n = n11 + n12;\r\n   var x_min = Math.max (0, n - m2);\r\n   var x_max = Math.min (n, m1);\r\n   var l = [];\r\n\r\n   for (var y = x_min; y &lt;= x_max; y++) {\r\n     l[y - x_min] = (lnbico (m1, y) + lnbico (m2, n - y) + y * Math.log (w));\r\n   }\r\n   var max_l = Math.max.apply (Math, l);\r\n \r\n   var sum_l = l.map (function (x) { return Math.exp (x - max_l); }).reduce (function (a, b) {\r\n     return a + b; }, 0);\r\n   sum_l = Math.log (sum_l);\r\n \r\n   var den_sum = 0;\r\n   for (var y = x; y &lt;= x_max; y++) {\r\n     den_sum += Math.exp (l[y - x_min] - max_l);\r\n   }\r\n   den_sum = Math.log (den_sum);\r\n   return Math.exp (den_sum - sum_l);\r\n };<\/code><\/pre>\n<div class=\"fusion-clearfix\"><\/div><\/div><\/div><\/div><\/div><\/p>\n<p>Veuillez noter que ce code a \u00e9t\u00e9 test\u00e9, mais pas de fa\u00e7on extensive. J&rsquo;ai confirm\u00e9 qu&rsquo;il retournait des r\u00e9sultats identiques \u00e0 l&rsquo;impl\u00e9mentation trouv\u00e9e dans R (fisher.exact) sur un nombre limit\u00e9 de cas non triviaux. Si vous tombez sur des probl\u00e8mes ou sur des erreurs, je serai heureux de les investiguer!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Mon article pr\u00e9c\u00e9dent expliquait pourquoi la version non-centr\u00e9e du test exact de Fisher est plus appropri\u00e9e dans la plupart des cas rencontr\u00e9s en bio-informatique. Je poursuis en pr\u00e9sentant maintenant une impl\u00e9mentation de ce test en Javascript qui pourrait\u00a0facilement \u00eatre int\u00e9gr\u00e9e \u00e0 une interface web. M\u00eame si le Javascript est un\u00a0langage tr\u00e8s mal adapt\u00e9 \u00e0 l&rsquo;impl\u00e9mentation\u00a0de\u00a0m\u00e9thodes statistiques, j&rsquo;esp\u00e8re que cet article pr\u00e9sentera tous les d\u00e9tails n\u00e9cessaires pour simplifier\u00a0l&rsquo;impl\u00e9mentation de ce test dans d&rsquo;autres langages, selon les besoins. \u00c0 tout le moins, <a href=\"https:\/\/bioinfo.iric.ca\/fr\/une-implementation-en-javascript-de-la-version-non-centree-du-test-exact-de-fisher\/\"> [&#8230;]<\/a><\/p>\n","protected":false},"author":5,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[69,27],"tags":[102,101],"class_list":["post-2933","post","type-post","status-publish","format-standard","hentry","category-analyse-de-donnees","category-statistiques","tag-javascript","tag-test"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts\/2933","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/comments?post=2933"}],"version-history":[{"count":10,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts\/2933\/revisions"}],"predecessor-version":[{"id":3279,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts\/2933\/revisions\/3279"}],"wp:attachment":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/media?parent=2933"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/categories?post=2933"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/tags?post=2933"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}