{"id":209,"date":"2015-06-07T09:00:04","date_gmt":"2015-06-07T09:00:04","guid":{"rendered":"http:\/\/cms04397.apps-1and1.net\/?p=209"},"modified":"2015-06-07T09:00:04","modified_gmt":"2015-06-07T09:00:04","slug":"statistiques-descriptives-avec-dbms_stat_funcs","status":"publish","type":"post","link":"https:\/\/blog.tiran.stream\/?p=209","title":{"rendered":"Statistiques descriptives avec DBMS_STAT_FUNCS"},"content":{"rendered":"<p style=\"text-align: justify;\">Lors de l&rsquo;analyse de donn\u00e9es, il est commun d&rsquo;afficher les principales statistiques d&rsquo;un \u00e9chantillon.\u00a0C&rsquo;est ce que permet de faire la proc\u00e9dure SUMMARY du package <a href=\"https:\/\/docs.oracle.com\/database\/121\/ARPLS\/d_stat_f.htm#ARPLS68480\" target=\"_blank\">DBMS_STAT_FUNCS<\/a>.<\/p>\n<p style=\"text-align: justify;\">Celle-ci balaye toutes les donn\u00e9es d&rsquo;un champ num\u00e9rique pass\u00e9 en argument pour restituer les principales caract\u00e9ristiques descriptives (min\/max, variance, quantiles&#8230;).<\/p>\n<p style=\"text-align: justify;\">La proc\u00e9dure renvoie un objet de type DBMS_STAT_FUNCS.summarytype et il est donc n\u00e9cessaire de coder un wrapper en PL\/SQL pour afficher les informations. C&rsquo;est ce que fait la fonction STAT_SUMMARY que voici:\u00a0<a href=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2015\/05\/stat_summary_func.txt\">stat_summary_func<\/a>.<\/p>\n<p style=\"text-align: justify;\">Elle renvoie un rapport sous la forme d&rsquo;un CLOB qu&rsquo;il est alors possible d&rsquo;afficher sous SQL*Plus:<\/p>\n<pre>SQL&gt; DESC duree_vie\n Name                                      Null?    Type\n ----------------------------------------- -------- ----------------------------\n PAYS                                               VARCHAR2(70)\n ESP                                                NUMBER\n\nSQL&gt; SET HEAD OFF\nSQL&gt; SET PAGES 100\nSQL&gt; SET LONG 10000 LONGC 10000\nSQL&gt;\nSQL&gt; SELECT stat_summary ('duree_vie', 'esp') FROM DUAL;\n\n\nRAFA.DUREE_VIE [ESP]\n----------------------\n\nN: 235\nMin\/Max: 45.3\/83.5 - Delta: 38.2\nVar.: 79.586925 - e.t.: 8.92115\n\nQuantiles\n----------------------\n     5%: 52.72\n    25%: 65.8\nMediane: 73.3\n    75%: 77.05\n    95%: 81.49\n\nPrincipale(s) modalite(s):\n   [1]: 79.8\n\nCinq valeurs les plus grandes [Outliers (*) &gt;93.925]:\n   [1]: 83.5\n   [2]: 83.3\n   [3]: 82.5\n   [4]: 82.4\n   [5]: 82.3\n\nCinq valeurs les plus petites [Outliers (*) &lt;48.925]: \n   [1]: 45.3 (*) \n   [2]: 47.4 (*) \n   [3]: 49.2 \n   [4]: 49.5 \n   [5]: 49.8 \n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">Le probl\u00e8me de DBMS_STAT_FUNCS.summary est que la proc\u00e9dure analyse la totalit\u00e9 des donn\u00e9es du champ cibl\u00e9. Or, bien souvent, c&rsquo;est uniquement sur un sous-ensemble des donn\u00e9es que l&rsquo;on souhaite travailler.<\/p>\n<p style=\"text-align: justify;\">Dans ce cas, je passe par la cr\u00e9ation d&rsquo;une vue qui op\u00e8re (de mani\u00e8re plus ou moins complexe) le filtrage souhait\u00e9. Dans l&rsquo;exemple ci-dessous je m&rsquo;int\u00e9resse uniquement aux donn\u00e9es d&rsquo;esp\u00e9rance de vie relatives aux pays de l&rsquo;UE (ces derniers sont list\u00e9s dans la table EUROPE). Je cr\u00e9\u00e9e donc une vue DUREE_VIE_EUROPE qui r\u00e9alise la jointure sur ces deux tables:<\/p>\n<pre>SQL&gt; CREATE OR REPLACE VIEW duree_vie_europe\n  2  AS\n  3     SELECT pays, esp\n  4       FROM duree_vie JOIN europe USING (pays);\n\nView created.\n\nSQL&gt;<\/pre>\n<p style=\"text-align: justify;\">Je peux alors invoquer DBMS_STAT_FUNCS.summary sur cette vue (au m\u00eame titre que si c&rsquo;\u00e9tait une table) via ma fonction STAT_SUMMARY:<\/p>\n<pre>SQL&gt; SELECT stat_summary ('duree_vie_europe', 'esp') FROM DUAL;\n\n\nRAFA.DUREE_VIE_EUROPE [ESP]\n----------------------\n\nN: 28\nMin\/Max: 72.1\/82.3 - Delta: 10.2\nVar.: 10.247765 - e.t.: 3.201213\n\nQuantiles\n----------------------\n     5%: 72.59\n    25%: 76.05\nMediane: 79.8\n    75%: 80.7\n    95%: 81.895\n\nPrincipale(s) modalite(s):\n   [1]: 72.1\n   [2]: 79.8\n   [3]: 81.7\n   [4]: 80.7\n   [5]: 80.4\n   [6]: 80.5\n\nCinq valeurs les plus grandes [Outliers (*) &gt;87.675]:\n   [1]: 82.3\n   [2]: 82\n   [3]: 81.7\n   [4]: 81.7\n   [5]: 81\n\nCinq valeurs les plus petites [Outliers (*) &lt;69.075]: \n   [1]: 72.1 \n   [2]: 72.1 \n   [3]: 73.5 \n   [4]: 73.7 \n   [5]: 74.3 \n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">Cela-dit, j&rsquo;utilise assez peu souvent cette approche\u00a0directe en SQL. En pratique, j&rsquo;invoque la fonction STAT_SUMMARY depuis SQL*Plus via un script \u00ab\u00a0stat_summary.sql\u00a0\u00bb qui permet de g\u00e9n\u00e9rer directement la sortie au format HTML et de l&rsquo;ouvrir dans mon navigateur.<\/p>\n<p style=\"text-align: justify;\">Le script est disponible ici:\u00a0<a href=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2015\/05\/stat_summary.txt\">stat_summary<\/a>. A noter qu&rsquo;il faut changer son extension en \u00ab\u00a0.sql\u00a0\u00bb apr\u00e8s le t\u00e9l\u00e9chargement.<\/p>\n<p style=\"text-align: justify;\">Cerise sur le g\u00e2teau: un boxplot est affich\u00e9 via Google Chart Image ce qui facilite grandement la compr\u00e9hension visuelle des informations!<\/p>\n<pre style=\"text-align: justify;\">SQL&gt; @stat_summary.sql duree_vie esp\nSQL&gt;<\/pre>\n<p style=\"text-align: justify;\"><a href=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2015\/05\/stat_summary.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-212 size-full\" src=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2015\/05\/stat_summary.png\" alt=\"stat_summary\" width=\"792\" height=\"543\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Lors de l&rsquo;analyse de donn\u00e9es, il est commun d&rsquo;afficher les principales statistiques d&rsquo;un \u00e9chantillon.\u00a0C&rsquo;est ce que permet de faire la<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"colormag_page_container_layout":"default_layout","colormag_page_sidebar_layout":"default_layout","footnotes":""},"categories":[6,14],"tags":[],"class_list":["post-209","post","type-post","status-publish","format-standard","hentry","category-oracle","category-statistique"],"_links":{"self":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/posts\/209","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=209"}],"version-history":[{"count":0,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/posts\/209\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=209"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=209"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=209"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}