{"id":425,"date":"2015-11-12T07:37:36","date_gmt":"2015-11-12T07:37:36","guid":{"rendered":"http:\/\/blog.tiran.info\/?p=425"},"modified":"2015-11-12T07:37:36","modified_gmt":"2015-11-12T07:37:36","slug":"arbre-de-decision-avec-r","status":"publish","type":"post","link":"https:\/\/blog.tiran.stream\/?p=425","title":{"rendered":"Arbre de d\u00e9cision avec R"},"content":{"rendered":"<p>Je r\u00e9alise ici une analyse similaire \u00e0 celle du <a href=\"http:\/\/blog.tiran.info\/arbre-de-decision-avec-oracle\">pr\u00e9c\u00e9dent billet<\/a> en m&rsquo;appuyant cette fois-ci sur R.<\/p>\n<h3>Chargement des donn\u00e9es<\/h3>\n<p>Les donn\u00e9es des vues v_autos_apprentissage et v_autos_test sont respectivement charg\u00e9es dans les dataframes autos_apprentissage et autos_test:<\/p>\n<pre class=\"brush: js; ruler: true;\">&gt; library(ROracle)\nLe chargement a n\u00e9cessit\u00e9 le package : DBI\nWarning message:\nle package \u2018DBI\u2019 a \u00e9t\u00e9 compil\u00e9 avec la version R 3.2.1 \n&gt; ora = Oracle()\n&gt; cnx = dbConnect(ora, username=&quot;rafa&quot;, password=&quot;rafa&quot;, dbname=&quot;S1401037:1521\/STATPDB&quot;)\n&gt; autos_apprentissage &lt;- dbGetQuery(cnx, &quot;select * from v_autos_apprentissage&quot;)\n&gt; autos_test &lt;- dbGetQuery(cnx, &quot;select * from v_autos_test&quot;)\n&gt; dbDisconnect(cnx)\n[1] TRUE\n&gt;<\/pre>\n<p>Par d\u00e9faut, les donn\u00e9es textuelles (VARCHAR2) sont typ\u00e9es en \u00ab\u00a0character\u00a0\u00bb dans R. Il faut donc passer par une \u00e9tape de conversion sous forme de facteurs:<\/p>\n<pre class=\"brush: js; ruler: true;\">&gt; autos_apprentissage$TYP_BOITE=as.factor(autos_apprentissage$TYP_BOITE)\n&gt; autos_apprentissage$GAMME=as.factor(autos_apprentissage$GAMME)\n&gt; autos_apprentissage$BONUS_MALUS=as.factor(autos_apprentissage$BONUS_MALUS)\n&gt; autos_apprentissage$CARROSSERIE=as.factor(autos_apprentissage$CARROSSERIE)\n&gt; autos_apprentissage$HYBRIDE=as.factor(autos_apprentissage$HYBRIDE)\n&gt; autos_apprentissage$LIB_MRQ=as.factor(autos_apprentissage$LIB_MRQ)\n&gt; autos_apprentissage$COD_CBR=as.factor(autos_apprentissage$COD_CBR)\n&gt; \n&gt; autos_test$TYP_BOITE=as.factor(autos_test$TYP_BOITE)\n&gt; autos_test$GAMME=as.factor(autos_test$GAMME)\n&gt; autos_test$BONUS_MALUS=as.factor(autos_test$BONUS_MALUS)\n&gt; autos_test$CARROSSERIE=as.factor(autos_test$CARROSSERIE)\n&gt; autos_test$HYBRIDE=as.factor(autos_test$HYBRIDE)\n&gt; autos_test$LIB_MRQ=as.factor(autos_test$LIB_MRQ)\n&gt; autos_test$COD_CBR=as.factor(autos_test$COD_CBR)\n&gt; \n&gt; summary(autos_test)\n       LIB_MRQ      LIB_MOD          COD_CBR  HYBRIDE   PUISS_ADMIN_98     PUISS_MAX     TYP_BOITE    NB_RAPP        CONSO_URB       CONSO_EXURB    \n AUDI      :274   Length:654         ES:289   non:654   Min.   : 3.000   Min.   : 44.0   A:249     Min.   :0.000   Min.   : 3.800   Min.   : 3.000  \n SEAT      :104   Class :character   GO:365             1st Qu.: 6.000   1st Qu.: 77.0   M:366     1st Qu.:6.000   1st Qu.: 5.600   1st Qu.: 4.100  \n SKODA     :103   Mode  :character                      Median : 8.000   Median :103.0   V: 39     Median :6.000   Median : 6.400   Median : 4.500  \n VOLKSWAGEN:173                                         Mean   : 9.546   Mean   :120.8             Mean   :5.722   Mean   : 7.039   Mean   : 4.773  \n                                                        3rd Qu.:10.000   3rd Qu.:139.0             3rd Qu.:6.000   3rd Qu.: 7.500   3rd Qu.: 5.200  \n                                                        Max.   :48.000   Max.   :412.0             Max.   :8.000   Max.   :22.200   Max.   :10.700  \n                                                                                                                                                    \n  CONSO_MIXTE     MASSE_ORDMA_MIN MASSE_ORDMA_MAX            CARROSSERIE         GAMME       BONUS_MALUS \n Min.   : 3.200   Min.   : 929    Min.   : 929    BERLINE          :352   INFERIEURE:110   C (0)   :372  \n 1st Qu.: 4.600   1st Qu.:1296    1st Qu.:1296    BREAK            :139   LUXE      : 85   D (150) : 54  \n Median : 5.200   Median :1500    Median :1500    COMBISPACE       : 45   MOY-INFER :208   G (900) : 51  \n Mean   : 5.598   Mean   :1485    Mean   :1485    COUPE            : 65   MOY-SUPER :203   I (2200): 49  \n 3rd Qu.: 6.000   3rd Qu.:1646    3rd Qu.:1646    MONOSPACE        : 26   SUPERIEURE: 48   H (1600): 39  \n Max.   :14.900   Max.   :2315    Max.   :2315    MONOSPACE COMPACT: 27                    N (8000): 29  \n                                                                                           (Other) : 60  \nWarning message:\nIn summary(autos_test) : bytecode version mismatch; using eval\n&gt;<\/pre>\n<p>&nbsp;<\/p>\n<h3>Construction de l&rsquo;arbre de d\u00e9cision<\/h3>\n<p>Le package rpart permet de construire l&rsquo;arbre \u00e0 partir de l&rsquo;\u00e9chantillon d&rsquo;apprentissage. On exclut les champs LIB_MOD et LIB_MRQ qui n&rsquo;ont pas d&rsquo;int\u00e9r\u00eat informatif.<\/p>\n<pre class=\"brush: js; ruler: true;\">&gt; library(rpart)\n&gt; autos_dt &lt;- rpart(BONUS_MALUS~., data=autos_apprentissage[,!(colnames(autos_apprentissage) %in% c(&quot;LIB_MOD&quot;,&quot;LIB_MRQ&quot;))], method=&quot;class&quot;)\n&gt;<\/pre>\n<p>On cherche ensuite \u00e0 \u00ab\u00a0\u00e9laguer\u00a0\u00bb l&rsquo;arbre de mani\u00e8re \u00e0 obtenir le meilleur compromis entre le nombre de feuilles et la performance de classification.\u00a0Ce compromis d\u00e9pend du crit\u00e8re cp (complexity parameter) dont on peut d\u00e9terminer la valeur optimale via les commandes plotcp (mode graphique) et printcp:<\/p>\n<pre class=\"brush: js; ruler: true;\">&gt; plotcp(autos_dt)<\/pre>\n<p><a href=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2015\/11\/plotcp.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-442 size-full\" src=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2015\/11\/plotcp.png\" alt=\"plotcp\" width=\"660\" height=\"553\" \/><\/a><\/p>\n<pre class=\"brush: js; ruler: true;\">&gt; printcp(autos_dt)\n\nClassification tree:\nrpart(formula = BONUS_MALUS ~ ., data = autos_apprentissage[, \n    !(colnames(autos_apprentissage) %in% c(&quot;LIB_MOD&quot;, &quot;LIB_MRQ&quot;))], \n    method = &quot;class&quot;)\n\nVariables actually used in tree construction:\n[1] COD_CBR     CONSO_EXURB CONSO_MIXTE\n\nRoot node error: 1329\/2722 = 0.48824\n\nn= 2722 \n\n         CP nsplit rel error  xerror     xstd\n1  0.170429      0   1.00000 1.00000 0.019623\n2  0.048345      2   0.65914 0.66215 0.018362\n3  0.045147      6   0.46576 0.48608 0.016702\n4  0.025771      7   0.42062 0.42363 0.015901\n5  0.019564     11   0.31753 0.32807 0.014398\n6  0.017682     12   0.29797 0.31603 0.014181\n7  0.017306     14   0.26260 0.28819 0.013650\n8  0.015801     16   0.22799 0.27991 0.013485\n9  0.013544     17   0.21219 0.23928 0.012610\n10 0.010534     19   0.18510 0.20542 0.011793\n11 0.010000     20   0.17457 0.19413 0.011499\n&gt;<\/pre>\n<p>Dans l&rsquo;exemple ci-dessus, l&rsquo;algorithme s&rsquo;interrompt pour un CP de 0.01 (qui se trouve \u00eatre la limite basse par d\u00e9faut du param\u00e8tre). Cela signifie que l&rsquo;ajout de nouvelles feuilles ne permettrait pas d&rsquo;am\u00e9liorer la pr\u00e9cision de la classification de plus d&rsquo;1%.<\/p>\n<p>Dans ce cas pr\u00e9cis, l&rsquo;\u00e9lagage de l&rsquo;arbre n&rsquo;est pas n\u00e9cessaire puisque la structure finale correspond d\u00e9j\u00e0 au CP le plus faible. N\u00e9anmoins, le cas \u00e9ch\u00e9ant l&rsquo;\u00e9lagage serait r\u00e9alis\u00e9 via la fonction prune:<\/p>\n<pre class=\"brush: js; ruler: true;\">&gt; optimcp &lt;- autos_dt$cptable[which.min(autos_dt$cptable[,&quot;xerror&quot;]),&quot;CP&quot;]\n&gt; autos_dt.pruned &lt;- prune(autos_dt, cp = optimcp)<\/pre>\n<h3><\/h3>\n<p>&nbsp;<\/p>\n<h3>Performance du mod\u00e8le<\/h3>\n<p>La sortie de printcp permet aussi de quantifier la performance du mod\u00e8le via deux <a href=\"https:\/\/fr.wikipedia.org\/wiki\/Analyse_discriminante_lin%C3%A9aire#Taux_d.E2.80.99erreur\" target=\"_blank\">taux d&rsquo;erreur<\/a>:<\/p>\n<ul>\n<li>le taux d&rsquo;erreur de re-substitution (rel error * root node error): 0.48824 * 0.17457 * 100 = 8.5%.<\/li>\n<\/ul>\n<p>C&rsquo;est une valeur biais\u00e9e par nature (puisque bas\u00e9e sur la performance de classification de l&rsquo;\u00e9chantillon d&rsquo;apprentissage) et donc plut\u00f4t \u00ab\u00a0optimiste\u00a0\u00bb.<\/p>\n<p>On la retrouve en comparant les valeurs r\u00e9elles de bonus\/malus et les pr\u00e9dictions associ\u00e9es pour autos_apprentissage:<\/p>\n<pre class=\"brush: js; ruler: true;\">&gt; 100*length(which(autos_apprentissage$BONUS_MALUS != predict(autos_dt,type=&quot;class&quot;)))\/dim(autos_apprentissage)[1]\n[1] 8.523145\n&gt;\n<\/pre>\n<ul>\n<li>le taux d&rsquo;erreur de validation crois\u00e9e (xerror * root node error): 0.48824 * 0.19413 * 100 = 9.5%.<\/li>\n<\/ul>\n<p>Ce taux correspond \u00e0 la moyenne des erreurs obtenues en appliquant \u00e0 10 reprises le mod\u00e8le sur des sous-\u00e9chantillons (chaque sous-\u00e9chantillon \u00e9tant obtenu par r\u00e9-\u00e9chantillonnage de l&rsquo;ensemble d&rsquo;apprentissage dans une proportion 90%\/10%).<\/p>\n<p>Ce taux est plus repr\u00e9sentatif que le taux d&rsquo;erreur de re-substitution.<\/p>\n<p>&nbsp;<\/p>\n<p>On peut aussi mesurer\u00a0la performance du classifieur sur notre \u00e9chantillon de test. Ici, on avoisine 89.3% de classifications correctes:<\/p>\n<pre class=\"brush: js; ruler: true;\">&gt; 100*length(which(autos_test$BONUS_MALUS != predict(autos_dt, newdata=autos_test[,!(colnames(autos_test) %in% c(&quot;LIB_MOD&quot;,&quot;LIB_MRQ&quot;))],type=&quot;class&quot;)))\/dim(autos_test)[1]\n[1] 10.70336\n&gt;\n\n<\/pre>\n<p>Enfin, la construction d&rsquo;une matrice de confusion permet d&rsquo;avoir une id\u00e9e de l&rsquo;efficacit\u00e9 du classifieur en fonction des diff\u00e9rentes classes de bonus\/malus:<\/p>\n<pre class=\"brush: js; ruler: true;\">&gt; conf.matrix &lt;- table(autos_test$BONUS_MALUS, predict(autos_dt, newdata=autos_test[,!(colnames(autos_test) %in% c(&quot;LIB_MOD&quot;,&quot;LIB_MRQ&quot;))],type=&quot;class&quot;))\n&gt; print(conf.matrix)\n \n           C (0) D (150) F (500) G (900) H (1600) I (2200) J (3000) K (3600) L (4000) M (6500) N (8000)\n  C (0)      364       6       1       0        0        1        0        0        0        0        0\n  D (150)      5      49       0       0        0        0        0        0        0        0        0\n  F (500)      0       0      21       1        0        1        0        0        0        0        0\n  G (900)      0       0       1      34        0       16        0        0        0        0        0\n  H (1600)     0       0       0       0       21       18        0        0        0        0        0\n  I (2200)     0       0       0       0        6       43        0        0        0        0        0\n  J (3000)     0       0       0       0        0        4        5        1        1        0        0\n  K (3600)     0       0       0       0        0        0        0        4        0        0        0\n  L (4000)     0       0       0       0        0        0        0        0       10        3        0\n  M (6500)     0       0       0       0        0        2        0        0        0        4        3\n  N (8000)     0       0       0       0        0        0        0        0        0        0       29\n&gt;<\/pre>\n<h3><\/h3>\n<p>&nbsp;<\/p>\n<h3>Visualisation de l&rsquo;arbre de d\u00e9cision<\/h3>\n<p>Il peut \u00eatre int\u00e9ressant de repr\u00e9senter graphiquement l&rsquo;arbre de d\u00e9cision avec les r\u00e8gles qui le constitue:<\/p>\n<pre class=\"brush: js; ruler: true;\">&gt; library(rpart.plot)\n&gt; prp(autos_dt.pruned, type=1, extra=3)<\/pre>\n<p><a href=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2015\/11\/decision_tree.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-441 size-full\" src=\"https:\/\/blog.tiran.stream\/wp-content\/uploads\/2015\/11\/decision_tree.png\" alt=\"decision_tree\" width=\"1200\" height=\"1005\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Je r\u00e9alise ici une analyse similaire \u00e0 celle du pr\u00e9c\u00e9dent billet en m&rsquo;appuyant cette fois-ci sur R. Chargement des donn\u00e9es<\/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":[3,12],"tags":[],"class_list":["post-425","post","type-post","status-publish","format-standard","hentry","category-classification","category-r"],"_links":{"self":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/posts\/425","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=425"}],"version-history":[{"count":0,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=\/wp\/v2\/posts\/425\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=425"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=425"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.tiran.stream\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=425"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}