{"id":357,"date":"2015-09-25T06:30:06","date_gmt":"2015-09-25T06:30:06","guid":{"rendered":"http:\/\/blog.tiran.info\/?p=357"},"modified":"2015-09-25T06:30:06","modified_gmt":"2015-09-25T06:30:06","slug":"partitionnement-via-k-means-avec-oracle","status":"publish","type":"post","link":"https:\/\/blog.tiran.stream\/?p=357","title":{"rendered":"Partitionnement via k-means avec Oracle"},"content":{"rendered":"<p style=\"text-align: justify;\">Depuis le <a href=\"http:\/\/www2.assemblee-nationale.fr\/scrutins\/liste\/%28legislature%29\/14\" target=\"_blank\">site web de l&rsquo;Assembl\u00e9e Nationale<\/a>, il est possible d&rsquo;acc\u00e9der aux r\u00e9sultats des tous les scrutins l\u00e9gislatifs.\u00a0<span style=\"line-height: 1.5;\">On peut aussi visualiser le d\u00e9tail des votes par d\u00e9put\u00e9s. <\/span><\/p>\n<p style=\"text-align: justify;\"><span style=\"line-height: 1.5;\">Les scrutins solennels sont les plus int\u00e9ressants car tous les d\u00e9put\u00e9s sont invit\u00e9s \u00e0 voter et la participation y est relativement importante.\u00a0<\/span>Avec un peu de web-scrapping, on peut r\u00e9cup\u00e9rer les r\u00e9sultats pour les analyser.<\/p>\n<p style=\"text-align: justify;\">Dans ce billet, j&rsquo;ai entreprit de v\u00e9rifier s&rsquo;il \u00e9tait possible de r\u00e9aliser un <a href=\"https:\/\/fr.wikipedia.org\/wiki\/Partitionnement_de_donn%C3%A9es\" target=\"_blank\">partitionnement<\/a>\u00a0de ces donn\u00e9es via un algorithme d&rsquo;<a href=\"https:\/\/fr.wikipedia.org\/wiki\/Apprentissage_non_supervis%C3%A9\" target=\"_blank\">apprentissage non-supervis\u00e9<\/a>.<\/p>\n<p style=\"text-align: justify;\">En effet, on devrait observer une relative homog\u00e9n\u00e9it\u00e9 des votes au sein d&rsquo;un groupe parlementaire (en raison des consignes de vote). Cet aspect devrait donc permettre \u00e0 un algorithme de partitionnement comme le <a href=\"https:\/\/fr.wikipedia.org\/wiki\/K-moyennes\" target=\"_blank\">k-means<\/a> de diviser la population en sous-ensembles correspondants aux groupes parlementaires.<\/p>\n<p style=\"text-align: justify;\">Oracle met \u00e0 disposition une <a href=\"http:\/\/docs.oracle.com\/cd\/B28359_01\/datamine.111\/b28129\/algo_kmeans.htm\" target=\"_blank\">version am\u00e9lior\u00e9e<\/a> de cet algorithme.\u00a0N\u00e9anmoins, le d\u00e9tail des am\u00e9liorations n&rsquo;est pas document\u00e9 et le <a href=\"http:\/\/docs.oracle.com\/database\/121\/ARPLS\/d_datmin.htm#ARPLS608\" target=\"_blank\">nombre de variable<\/a> sur lesquelles il est possible de jouer reste limit\u00e9.\u00a0A noter que l&rsquo;utilisation du package DBMS_DATA_MINING n\u00e9cessite la licence Oracle Advanced Analytics.<\/p>\n<p style=\"text-align: justify;\">Pour mener \u00e0 bien mes tests (sans \u00eatre p\u00e9nalis\u00e9 par l&rsquo;absent\u00e9isme parlementaire!), je me suis int\u00e9ress\u00e9 aux seuls scrutins solennels ayant enregistr\u00e9 plus de 75% de participation.\u00a0J&rsquo;ai aussi exclu les d\u00e9put\u00e9s n&rsquo;ayant pas particip\u00e9 \u00e0 au moins 85% de ces votes.\u00a0Enfin, j&rsquo;ai \u00e9limin\u00e9 les \u00ab\u00a0non-inscrits\u00a0\u00bb (et ceux ayant chang\u00e9 d&rsquo;\u00e9tiquette en cours de route) car ils sont par d\u00e9finition difficile \u00e0 classer!<\/p>\n<p style=\"text-align: justify;\">Je parviens \u00e0 une matrice de votes de 497 d\u00e9put\u00e9s (sur 577) lors de 96 scrutins solennels (sur 98 survenus jusqu&rsquo;\u00e0 pr\u00e9sent dans la 14\u00e8me l\u00e9gislature):\u00a0<a href=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2015\/09\/kmeans-votes-assemblee.csv\">kmeans-votes-assemblee.csv<\/a><\/p>\n<p style=\"text-align: justify;\">Le codage utilis\u00e9 est -1 (contre), 1 (pour) et 0 (abstention). Les valeurs manquantes correspondent aux absences.<\/p>\n<p style=\"text-align: justify;\">Ult\u00e9rieurement, lors de la mise en forme des donn\u00e9es, les absences seront assimil\u00e9es aux abstentions.\u00a0C&rsquo;est un parti pris discutable mais il faut bien faire des choix!<\/p>\n<h3 style=\"text-align: justify;\"><strong>Pr\u00e9paration des donn\u00e9es<\/strong><\/h3>\n<p style=\"text-align: justify;\">Les <a href=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2015\/09\/kmeans-votes-assemblee.csv\">donn\u00e9es <\/a>ont \u00e9t\u00e9 pr\u00e9alablement charg\u00e9es dans la table votes_part:<\/p>\n<pre>SQL&gt; desc votes_part\n Name                                      Null?    Type\n ----------------------------------------- -------- ----------------------------\n DEPUTE                                             VARCHAR2(300)\n PARTI                                              VARCHAR2(300)\n S1062                                              NUMBER\n S1070                                              NUMBER\n...\n S991                                               NUMBER\n S994                                               NUMBER\n S995                                               NUMBER\n\nSQL&gt; SELECT COUNT (*)\n  2    FROM user_tab_columns\n  3   WHERE table_name = 'VOTES_PART';\n\n  COUNT(*)\n----------\n        98\n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">L&rsquo;algorithme k-means reposant sur un calcul de distance, il n&rsquo;est pas adapt\u00e9 aux cas des variables nominales. Dans notre cas, il nous faut donc passer par une \u00e9tape de conversion du r\u00e9sultat de chaque vote en plusieurs variables indicatrices (\u00ab\u00a0<a href=\"https:\/\/en.wikipedia.org\/wiki\/Dummy_variable_(statistics)\" target=\"_blank\">dummy variable<\/a>\u00a0\u00ab\u00a0).<\/p>\n<p style=\"text-align: justify;\">Par exemple, pour le scrutin 1062 dont le r\u00e9sultat dans VOTES_PART est stock\u00e9 dans le champ S1062, on va produire deux nouveaux champs S1062O et S1062N (O et N pour Oui ou Non).\u00a0Ces derniers s&rsquo;interpr\u00e9tant par rapport \u00e0 une r\u00e9f\u00e9rence implicite qui est l&rsquo;abstention (ou l&rsquo;absence).<\/p>\n<p style=\"text-align: justify;\">Ainsi on pourra avoir les cas de figures suivant:<\/p>\n<table style=\"border-color: #000000; border-style: solid; width: 800px;\" border=\"1\" width=\"400\">\n<tbody>\n<tr>\n<td style=\"text-align: center;\"><strong>Vote<\/strong><\/td>\n<td style=\"text-align: center;\"><strong>Pour<\/strong><\/td>\n<td style=\"text-align: center;\"><strong>Contre<\/strong><\/td>\n<td style=\"text-align: center;\"><strong>Abstention (ou absence)<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: center;\"><strong>Codage initial<\/strong><\/td>\n<td style=\"text-align: center;\">S1062=1<\/td>\n<td style=\"text-align: center;\">S1062=0<\/td>\n<td style=\"text-align: center;\">S1062=-1 (ou NULL)<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: center;\"><strong>Codage avec\u00a0variables indicatrices<\/strong><\/td>\n<td style=\"text-align: center;\">S10620=1<\/p>\n<p>S1062N=0<\/td>\n<td style=\"text-align: center;\">S10620=0<\/p>\n<p>S1062N=1<\/td>\n<td style=\"text-align: center;\">S10620=0<\/p>\n<p>S1062N=0<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"text-align: justify;\">\n<p style=\"text-align: justify;\">\n<p style=\"text-align: justify;\">La mise en oeuvre de cette transformation est r\u00e9alis\u00e9e par l&rsquo;interm\u00e9diaire d&rsquo;une vue. Comme le nombre de champs \u00e0 prendre en compte est important, j&rsquo;utilise un bloc PL\/SQL pour g\u00e9n\u00e9rer dynamiquement le code de la vue:<\/p>\n<pre>SQL&gt; DECLARE\n  2     l_v_ddl   CLOB := 'CREATE OR REPLACE VIEW V_VOTES_PART as SELECT ';\n  3  BEGIN\n  4     FOR rec\n  5        IN (SELECT ROWNUM rn, col\n  6              FROM (SELECT column_name col\n  7                      FROM user_tab_columns\n  8                     WHERE     table_name = 'VOTES_PART'\n  9                           AND column_name NOT LIKE 'S%'\n 10                    UNION ALL\n 11                    SELECT    'case('\n 12                           || column_name\n 13                           || ') when 1 then 1 else 0 end '\n 14                           || column_name\n 15                           || 'O, case('\n 16                           || column_name\n 17                           || ') when -1 then 1 else 0 end '\n 18                           || column_name\n 19                           || 'N'\n 20                      FROM user_tab_columns\n 21                     WHERE table_name = 'VOTES_PART' AND column_name LIKE 'S%'))\n 22     LOOP\n 23        l_v_ddl := l_v_ddl || CASE WHEN rec.rn != 1 THEN ',' END || rec.col;\n 24     END LOOP;\n 25\n 26     l_v_ddl := l_v_ddl || ' FROM VOTES_PART';\n 27\n 28     EXECUTE IMMEDIATE l_v_ddl;\n 29  END;\n 30  \/\n\nPL\/SQL procedure successfully completed.\n\nSQL&gt; SELECT COUNT (*)\n  2    FROM user_tab_columns\n  3   WHERE table_name = 'V_VOTES_PART';\n\n  COUNT(*)\n----------\n       194\n\nSQL&gt; desc V_VOTES_PART\n Name                                      Null?    Type\n ----------------------------------------- -------- ----------------------------\n DEPUTE                                             VARCHAR2(300)\n PARTI                                              VARCHAR2(300)\n S1062O                                             NUMBER\n S1062N                                             NUMBER\n S1070O                                             NUMBER\n S1070N                                             NUMBER\n...\n S991N                                              NUMBER\n S994O                                              NUMBER\n S994N                                              NUMBER\n S995O                                              NUMBER\n S995N                                              NUMBER\n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">La vue contient 194 champs (2*96+2).<\/p>\n<h3 style=\"text-align: justify;\"><strong>Mise en place de la table de param\u00e9trage du mod\u00e8le<\/strong><\/h3>\n<p style=\"text-align: justify;\">Le crit\u00e8re\u00a0principal est le nombre de clusters que l&rsquo;on souhaite obtenir apr\u00e8s partitionnement (clus_num_clusters).\u00a0Dans le cas pr\u00e9sent, si on fait abstraction des \u00ab\u00a0non-inscrits\u00a0\u00bb, il existe 6 <a href=\"http:\/\/www.assemblee-nationale.fr\/14\/tribun\/xml\/effectifs_groupes.asp\" target=\"_blank\">groupes parlementaires<\/a> repr\u00e9sent\u00e9s \u00e0 l&rsquo;Assembl\u00e9e. \u00a0On va donc r\u00e9aliser un partitionnement de la population en 6 clusters:<\/p>\n<pre>SQL&gt; CREATE TABLE assemblee_clu_settings\n  2  (\n  3     setting_name    VARCHAR2 (30 BYTE),\n  4     setting_value   VARCHAR2 (30 BYTE)\n  5  );\n\nTable created.\n\nSQL&gt; BEGIN\n  2     -- Utilisation d'un bloc PLSQL anonyme pour pouvoir r\u00e9f\u00e9rencer\n  3     -- les constantes du package DBMS_DATA_MINING\n  4\n  5     INSERT INTO assemblee_clu_settings (setting_name, setting_value)\n  6          VALUES (DBMS_DATA_MINING.algo_name, DBMS_DATA_MINING.algo_kmeans);\n  7\n  8     INSERT INTO assemblee_clu_settings (setting_name, setting_value)\n  9          VALUES (DBMS_DATA_MINING.prep_auto, DBMS_DATA_MINING.prep_auto_off);\n 10\n 11     INSERT INTO assemblee_clu_settings (setting_name, setting_value)\n 12          VALUES (DBMS_DATA_MINING.clus_num_clusters, 6);\n 13\n 14     COMMIT;\n 15  END;\n 16  \/\n\nPL\/SQL procedure successfully completed.\n\nSQL&gt;\n<\/pre>\n<h3 style=\"text-align: justify;\">Cr\u00e9ation du mod\u00e8le<\/h3>\n<p style=\"text-align: justify;\">On exclut les champs DEPUTE et PARTI de l&rsquo;analyse. Seuls les r\u00e9sultats des scrutins (SxxxO et SxxxN) sont pris en compte:<\/p>\n<pre>SQL&gt; SET TIMING ON;\nSQL&gt; DECLARE\n  2     l_xform   DBMS_DATA_MINING_TRANSFORM.transform_list;\n  3  BEGIN\n  4     DBMS_DATA_MINING_TRANSFORM.set_transform (l_xform,\n  5                                               'DEPUTE',\n  6                                               NULL,\n  7                                               NULL,\n  8                                               NULL);\n  9     DBMS_DATA_MINING_TRANSFORM.set_transform (l_xform,\n 10                                               'PARTI',\n 11                                               NULL,\n 12                                               NULL,\n 13                                               NULL);\n 14     DBMS_DATA_MINING.create_model (\n 15        model_name            =&gt; 'ASSEMBLEE_KMEANS_MODEL',\n 16        mining_function       =&gt; DBMS_DATA_MINING.clustering,\n 17        data_table_name       =&gt; 'V_VOTES_PART',\n 18        case_id_column_name   =&gt; NULL,\n 19        target_column_name    =&gt; NULL,\n 20        settings_table_name   =&gt; 'ASSEMBLEE_CLU_SETTINGS',\n 21        xform_list            =&gt; l_xform);\n 22  END;\n 23  \/\n\nPL\/SQL procedure successfully completed.\n\nElapsed: 00:00:11.59\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">La fonction <a href=\"http:\/\/docs.oracle.com\/database\/121\/SQLRF\/functions030.htm#SQLRF06213\" target=\"_blank\">CLUSTER_ID<\/a> permet de d\u00e9terminer le groupe auquel le mod\u00e8le de partitionnement affecte les donn\u00e9es:<\/p>\n<pre>SQL&gt;   SELECT CLUSTER_ID (assemblee_kmeans_model USING *) clust, COUNT (*) nb\n  2      FROM v_votes_part\n  3  GROUP BY CLUSTER_ID (assemblee_kmeans_model USING *)\n  4  ORDER BY 1;\n\n     CLUST         NB\n---------- ----------\n         2        283\n         4        167\n         6         22\n         8          8\n        10         10\n        11          7\n\n6 rows selected.\n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">On peut ensuite croiser le r\u00e9sultat de ce partitionnement avec l&rsquo;appartenance r\u00e9elle des d\u00e9put\u00e9s aux groupes parlementaires:<\/p>\n<pre>SQL&gt; column PARTI format a55\nSQL&gt; set lines 120\nSQL&gt; set NUMF 999999\nSQL&gt; SELECT *\n  2    FROM (SELECT a.parti, CLUSTER_ID (assemblee_kmeans_model USING *) cls\n  3            FROM v_votes_part a) PIVOT (COUNT (*)\n  4                                              AS cnt\n  5                                        FOR (cls)\n  6                                        IN ('2' AS p1,\n  7                                            '4' AS p2,\n  8                                            '6' AS p3,\n  9                                            '8' AS p4,\n 10                                           '10' AS p5,\n 11                                           '11' AS p6));\n\nPARTI                                                    P1_CNT  P2_CNT  P3_CNT  P4_CNT  P5_CNT  P6_CNT\n------------------------------------------------------- ------- ------- ------- ------- ------- -------\nGroupe Les R\u00e9publicains                                       0     167       0       0      10       7\nGroupe radical, r\u00e9publicain, d\u00e9mocrate et progressiste       13       0       0       0       0       0\nGroupe \u00e9cologiste                                            16       0       0       0       0       0\nGroupe socialiste, r\u00e9publicain et citoyen                   254       0       0       0       0       0\nGroupe de l'union des d\u00e9mocrates et ind\u00e9pendants              0       0      22       0       0       0\nGroupe de la gauche d\u00e9mocrate et r\u00e9publicaine                 0       0       0       8       0       0\n\n6 lignes s\u00e9lectionn\u00e9es.\n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">On constate que la performance du partitionnement est variable en fonction du groupe consid\u00e9r\u00e9.<\/p>\n<p style=\"text-align: justify;\">Les partitions P3 et P4 recouvrent de mani\u00e8re claire un groupe parlementaire (respectivement \u00ab\u00a0Groupe de l&rsquo;union des d\u00e9mocrates et ind\u00e9pendants\u00a0\u00bb et \u00ab\u00a0Groupe de la gauche d\u00e9mocrate et r\u00e9publicaine\u00a0\u00bb). \u00a0En revanche, les partitions P2, P5 et P6 correspondent \u00e0 un \u00e9clatement des membres du groupe \u00ab\u00a0Les R\u00e9publicains\u00a0\u00bb. Enfin le groupe P1 correspond \u00e0 un panachage d&rsquo;un bloc de gauche comprenant les \u00e9cologistes, les radicaux et les socialistes.<\/p>\n<p style=\"text-align: justify;\">L&rsquo;algorithme k-means \u00e9tant it\u00e9ratif on peut augmenter la limite d&rsquo;it\u00e9ration (passage du d\u00e9faut 3 \u00e0 10) pour voir si cela permet de parvenir \u00e0 une meilleure classification:<\/p>\n<pre>SQL&gt; BEGIN\n  2     INSERT INTO assemblee_clu_settings (setting_name, setting_value)\n  3          VALUES (DBMS_DATA_MINING.kmns_iterations, 10);\n  4\n  5     COMMIT;\n  6  END;\n  7  \/\n\nProc\u00e9dure PL\/SQL termin\u00e9e avec succ\u00e8s.\n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">On reconstruit le mod\u00e8le pour tenir compte du nouveau nombre d&rsquo;it\u00e9rations:<\/p>\n<pre>SQL&gt; BEGIN\n  2     DBMS_DATA_MINING.drop_model (model_name =&gt; 'ASSEMBLEE_KMEANS_MODEL');\n  3  END;\n  4  \/\n\nProc\u00e9dure PL\/SQL termin\u00e9e avec succ\u00e8s.\n\nSQL&gt; SET TIMING ON;\nSQL&gt; DECLARE\n  2     l_xform   DBMS_DATA_MINING_TRANSFORM.transform_list;\n  3  BEGIN\n  4     DBMS_DATA_MINING_TRANSFORM.set_transform (l_xform,\n  5                                               'DEPUTE',\n  6                                               NULL,\n  7                                               NULL,\n  8                                               NULL);\n  9     DBMS_DATA_MINING_TRANSFORM.set_transform (l_xform,\n 10                                               'PARTI',\n 11                                               NULL,\n 12                                               NULL,\n 13                                               NULL);\n 14     DBMS_DATA_MINING.create_model (\n 15        model_name            =&gt; 'ASSEMBLEE_KMEANS_MODEL',\n 16        mining_function       =&gt; DBMS_DATA_MINING.clustering,\n 17        data_table_name       =&gt; 'V_VOTES_PART',\n 18        case_id_column_name   =&gt; NULL,\n 19        target_column_name    =&gt; NULL,\n 20        settings_table_name   =&gt; 'ASSEMBLEE_CLU_SETTINGS',\n 21        xform_list            =&gt; l_xform);\n 22  END;\n 23  \/\n\nProc\u00e9dure PL\/SQL termin\u00e9e avec succ\u00e8s.\n\nEcoul\u00e9 : 00 :00 :08.75\nSQL&gt; \n<\/pre>\n<p style=\"text-align: justify;\">Le r\u00e9sultat du partitionnement est sensiblement am\u00e9lior\u00e9:<\/p>\n<pre>SQL&gt;   SELECT DISTINCT CLUSTER_ID (assemblee_kmeans_model USING *) clust\n  2      FROM v_votes_part\n  3  ORDER BY 1;\n\n  CLUST\n-------\n      4\n      6\n      8\n      9\n     10\n     11\n\n6 lignes s\u00e9lectionn\u00e9es.\n\nSQL&gt;\nSQL&gt; SELECT *\n  2    FROM (SELECT a.parti, CLUSTER_ID (assemblee_kmeans_model USING *) cls\n  3            FROM v_votes_part a) PIVOT (COUNT (*)\n  4                                              AS cnt\n  5                                        FOR (cls)\n  6                                        IN ('4' AS p1,\n  7                                            '6' AS p2,\n  8                                            '8' AS p3,\n  9                                            '9' AS p4,\n 10                                           '10' AS p5,\n 11                                           '11' AS p6));\n\nPARTI                                                    P1_CNT  P2_CNT  P3_CNT  P4_CNT  P5_CNT  P6_CNT\n------------------------------------------------------- ------- ------- ------- ------- ------- -------\nGroupe Les R\u00e9publicains                                     184       0       0       0       0       0\nGroupe radical, r\u00e9publicain, d\u00e9mocrate et progressiste        0       0       0       0       1      12\nGroupe \u00e9cologiste                                             0       0       0       0       0      16\nGroupe socialiste, r\u00e9publicain et citoyen                     0       0       0       0     247       7\nGroupe de l'union des d\u00e9mocrates et ind\u00e9pendants              0       0      11      11       0       0\nGroupe de la gauche d\u00e9mocrate et r\u00e9publicaine                 0       8       0       0       0       0\n\n6 lignes s\u00e9lectionn\u00e9es.\n\nSQL&gt;\n<\/pre>\n<p>On a d\u00e9sormais 3 partitions qui recoupent (quasi-exactement) des groupes parlementaires:<\/p>\n<ul>\n<li>P1 contient 100% des membres du \u00ab\u00a0Groupe Les R\u00e9publicains\u00a0\u00bb<\/li>\n<li>P2 contient 100% des membres du \u00ab\u00a0Groupe de la gauche d\u00e9mocrate et r\u00e9publicaine\u00a0\u00bb<\/li>\n<li>P5 contient 97% des membres du \u00ab\u00a0Groupe Socialiste, r\u00e9publicain et citoyen\u00a0\u00bb (la partition contient aussi un unique\u00a0d\u00e9put\u00e9 des radicaux de gauche)<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">En revanche, les membres du \u00ab\u00a0Groupe de l&rsquo;union des d\u00e9mocrates et ind\u00e9pendants\u00a0\u00bb sont d\u00e9sormais divis\u00e9s dans deux partitions P3 et P4. Ils ne sont n\u00e9anmoins pas m\u00e9lang\u00e9s avec des d\u00e9putes d&rsquo;autres tendances.<\/p>\n<p style=\"text-align: justify;\">Enfin, la partition P6 contient un panachage de d\u00e9put\u00e9s de gauche: \u00ab\u00a0Groupe \u00e9cologiste\u00a0\u00bb, \u00ab\u00a0Groupe radical, r\u00e9publicain,\u00a0d\u00e9mocrate et progressiste\u00a0\u00bb et 7 membres du \u00ab\u00a0Groupe socialiste, r\u00e9publicain et citoyen\u00a0\u00bb (des frondeurs?).<\/p>\n<p style=\"text-align: justify;\">Cela sous-entend que pour ces derniers, l&rsquo;algorithme mesure une \u00ab\u00a0distance\u00a0\u00bb moins importante entre leurs votes qu&rsquo;entre ceux des individus des partitions P3 et P4 (regroupant pourtant des membres d&rsquo;un m\u00eame groupe parlementaire).<\/p>\n<p style=\"text-align: justify;\">Une interpr\u00e9tation serait de dire que le \u00ab\u00a0Groupe de l&rsquo;union des d\u00e9mocrates et ind\u00e9pendants\u00a0\u00bb contient deux \u00ab\u00a0tendances\u00a0\u00bb dont les positions divergent de mani\u00e8re r\u00e9currente.<\/p>\n<p style=\"text-align: justify;\">On peut maintenant tenter d&rsquo;ajouter une nouvelle partition dans le mod\u00e8le afin de voir si cela permet \u00e0 l&rsquo;algorithme d&rsquo;aboutir \u00e0 une distinction entre les individus de la partition P6:<\/p>\n<pre>SQL&gt; BEGIN\n  2     UPDATE assemblee_clu_settings\n  3        SET setting_value = 7\n  4      WHERE setting_name = DBMS_DATA_MINING.clus_num_clusters;\n  5\n  6     COMMIT;\n  7  END;\n  8  \/\n\nProc\u00e9dure PL\/SQL termin\u00e9e avec succ\u00e8s.\n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">On reconstruit le mod\u00e8le pour tenir compte du nouveau nombre de clusters:<\/p>\n<pre>SQL&gt; BEGIN\n  2     DBMS_DATA_MINING.drop_model (model_name =&gt; 'ASSEMBLEE_KMEANS_MODEL');\n  3  END;\n  4  \/\n\nProc\u00e9dure PL\/SQL termin\u00e9e avec succ\u00e8s.\n\nSQL&gt; SET TIMING ON;\nSQL&gt; DECLARE\n  2     l_xform   DBMS_DATA_MINING_TRANSFORM.transform_list;\n  3  BEGIN\n  4     DBMS_DATA_MINING_TRANSFORM.set_transform (l_xform,\n  5                                               'DEPUTE',\n  6                                               NULL,\n  7                                               NULL,\n  8                                               NULL);\n  9     DBMS_DATA_MINING_TRANSFORM.set_transform (l_xform,\n 10                                               'PARTI',\n 11                                               NULL,\n 12                                               NULL,\n 13                                               NULL);\n 14     DBMS_DATA_MINING.create_model (\n 15        model_name            =&gt; 'ASSEMBLEE_KMEANS_MODEL',\n 16        mining_function       =&gt; DBMS_DATA_MINING.clustering,\n 17        data_table_name       =&gt; 'V_VOTES_PART',\n 18        case_id_column_name   =&gt; NULL,\n 19        target_column_name    =&gt; NULL,\n 20        settings_table_name   =&gt; 'ASSEMBLEE_CLU_SETTINGS',\n 21        xform_list            =&gt; l_xform);\n 22  END;\n 23  \/\n\nProc\u00e9dure PL\/SQL termin\u00e9e avec succ\u00e8s.\n\nEcoul\u00e9 : 00 :00 :10.68\nSQL&gt; SET TIMING OFF;\nSQL&gt;   SELECT DISTINCT CLUSTER_ID (assemblee_kmeans_model USING *) clust\n  2      FROM v_votes_part\n  3  ORDER BY 1;\n\n  CLUST\n-------\n      4\n      6\n      8\n      9\n     10\n     12\n     13\n\n7 lignes s\u00e9lectionn\u00e9es.\n\nSQL&gt; \n<\/pre>\n<p style=\"text-align: justify;\">On peut constater que l&rsquo;ajout d&rsquo;une partition a permis \u00e0 l&rsquo;algorithme de parvenir \u00e0 la diff\u00e9rentiation\u00a0des membres du \u00ab\u00a0Groupe \u00e9cologiste\u00a0\u00bb (P7) et des membres du \u00ab\u00a0Groupe radical, r\u00e9publicain, d\u00e9mocrate et progressiste\u00a0\u00bb (P6):<\/p>\n<pre>SQL&gt; SELECT *\n  2    FROM (SELECT a.parti, CLUSTER_ID (assemblee_kmeans_model USING *) cls\n  3            FROM v_votes_part a) PIVOT (COUNT (*)\n  4                                              AS cnt\n  5                                        FOR (cls)\n  6                                        IN ('4' AS p1,\n  7                                            '6' AS p2,\n  8                                            '8' AS p3,\n  9                                            '9' AS p4,\n 10                                           '10' AS p5,\n 11                                           '12' AS p6,\n 12                                           '13' AS p7));\n\nPARTI                                                    P1_CNT  P2_CNT  P3_CNT  P4_CNT  P5_CNT  P6_CNT  P7_CNT\n------------------------------------------------------- ------- ------- ------- ------- ------- ------- -------\nGroupe Les R\u00e9publicains                                     184       0       0       0       0       0       0\nGroupe radical, r\u00e9publicain, d\u00e9mocrate et progressiste        0       0       0       0       1      11       1\nGroupe \u00e9cologiste                                             0       0       0       0       0       0      16\nGroupe socialiste, r\u00e9publicain et citoyen                     0       0       0       0     249       3       2\nGroupe de l'union des d\u00e9mocrates et ind\u00e9pendants              0       0      11      11       0       0       0\nGroupe de la gauche d\u00e9mocrate et r\u00e9publicaine                 0       8       0       0       0       0       0\n\n6 lignes s\u00e9lectionn\u00e9es.\n\nSQL&gt;\n<\/pre>\n<p style=\"text-align: justify;\">Ce r\u00e9sultat est tr\u00e8s int\u00e9ressant\u00a0car\u00a0\u00e0 l&rsquo;exception de la s\u00e9paration en deux\u00a0des membres du \u00ab\u00a0Groupe de l&rsquo;union des d\u00e9mocrates et ind\u00e9pendants\u00a0\u00bb et de 5 parlementaires mal-class\u00e9s, la tr\u00e8s large majorit\u00e9 des d\u00e9put\u00e9s peuvent \u00eatre group\u00e9s dans leur famille politique en fonction de leur votes. Les consignes paraissent donc plut\u00f4t bien respect\u00e9es!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Depuis le site web de l&rsquo;Assembl\u00e9e Nationale, il est possible d&rsquo;acc\u00e9der aux r\u00e9sultats des tous les scrutins l\u00e9gislatifs.\u00a0On peut aussi<\/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":[4,6,7],"tags":[],"class_list":["post-357","post","type-post","status-publish","format-standard","hentry","category-clustering","category-oracle","category-oracle-advanced-analytics"],"_links":{"self":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/posts\/357","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=357"}],"version-history":[{"count":0,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/posts\/357\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=357"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=357"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=357"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}