Árboles de decisión para clasificación

Las librerías

library(dplyr)
library(tidyverse)
library(rpart)
library(rpart.plot)
library(caret)
library(e1071)

Los datos

datos <- read.csv("../datos/wine.csv")
head(datos)
##   X1 X14.23 X1.71 X2.43 X15.6 X127 X2.8 X3.06 X.28 X2.29 X5.64 X1.04 X3.92
## 1  1  13.20  1.78  2.14  11.2  100 2.65  2.76 0.26  1.28  4.38  1.05  3.40
## 2  1  13.16  2.36  2.67  18.6  101 2.80  3.24 0.30  2.81  5.68  1.03  3.17
## 3  1  14.37  1.95  2.50  16.8  113 3.85  3.49 0.24  2.18  7.80  0.86  3.45
## 4  1  13.24  2.59  2.87  21.0  118 2.80  2.69 0.39  1.82  4.32  1.04  2.93
## 5  1  14.20  1.76  2.45  15.2  112 3.27  3.39 0.34  1.97  6.75  1.05  2.85
## 6  1  14.39  1.87  2.45  14.6   96 2.50  2.52 0.30  1.98  5.25  1.02  3.58
##   X1065
## 1  1050
## 2  1185
## 3  1480
## 4   735
## 5  1450
## 6  1290
tail(datos)
##     X1 X14.23 X1.71 X2.43 X15.6 X127 X2.8 X3.06 X.28 X2.29 X5.64 X1.04 X3.92
## 172  3  14.16  2.51  2.48  20.0   91 1.68  0.70 0.44  1.24   9.7  0.62  1.71
## 173  3  13.71  5.65  2.45  20.5   95 1.68  0.61 0.52  1.06   7.7  0.64  1.74
## 174  3  13.40  3.91  2.48  23.0  102 1.80  0.75 0.43  1.41   7.3  0.70  1.56
## 175  3  13.27  4.28  2.26  20.0  120 1.59  0.69 0.43  1.35  10.2  0.59  1.56
## 176  3  13.17  2.59  2.37  20.0  120 1.65  0.68 0.53  1.46   9.3  0.60  1.62
## 177  3  14.13  4.10  2.74  24.5   96 2.05  0.76 0.56  1.35   9.2  0.61  1.60
##     X1065
## 172   660
## 173   740
## 174   750
## 175   835
## 176   840
## 177   560

Poner nombres de columnas

colnames(datos) <- c("Tipo.Vino","Alcohol", "Malic.Acid","Ceniza","Alcal.Ceniza",
"Magnesio", "Fenols.Tot", "Flavanoides", "Fenoles.No.Flava",
"Proantocianinos", "Int.Color", "Tono.Color", "OD280.OD315", "Prolino")
head(datos)
##   Tipo.Vino Alcohol Malic.Acid Ceniza Alcal.Ceniza Magnesio Fenols.Tot
## 1         1   13.20       1.78   2.14         11.2      100       2.65
## 2         1   13.16       2.36   2.67         18.6      101       2.80
## 3         1   14.37       1.95   2.50         16.8      113       3.85
## 4         1   13.24       2.59   2.87         21.0      118       2.80
## 5         1   14.20       1.76   2.45         15.2      112       3.27
## 6         1   14.39       1.87   2.45         14.6       96       2.50
##   Flavanoides Fenoles.No.Flava Proantocianinos Int.Color Tono.Color OD280.OD315
## 1        2.76             0.26            1.28      4.38       1.05        3.40
## 2        3.24             0.30            2.81      5.68       1.03        3.17
## 3        3.49             0.24            2.18      7.80       0.86        3.45
## 4        2.69             0.39            1.82      4.32       1.04        2.93
## 5        3.39             0.34            1.97      6.75       1.05        2.85
## 6        2.52             0.30            1.98      5.25       1.02        3.58
##   Prolino
## 1    1050
## 2    1185
## 3    1480
## 4     735
## 5    1450
## 6    1290
unique(datos$Tipo.Vino) # ¿Cuáles tipos de vinos existen ?
## [1] 1 2 3

Explorando los datos

datos$Tipo.Vino <- factor(datos$Tipo.Vino)
str(datos)
## 'data.frame':    177 obs. of  14 variables:
##  $ Tipo.Vino       : Factor w/ 3 levels "1","2","3": 1 1 1 1 1 1 1 1 1 1 ...
##  $ Alcohol         : num  13.2 13.2 14.4 13.2 14.2 ...
##  $ Malic.Acid      : num  1.78 2.36 1.95 2.59 1.76 1.87 2.15 1.64 1.35 2.16 ...
##  $ Ceniza          : num  2.14 2.67 2.5 2.87 2.45 2.45 2.61 2.17 2.27 2.3 ...
##  $ Alcal.Ceniza    : num  11.2 18.6 16.8 21 15.2 14.6 17.6 14 16 18 ...
##  $ Magnesio        : int  100 101 113 118 112 96 121 97 98 105 ...
##  $ Fenols.Tot      : num  2.65 2.8 3.85 2.8 3.27 2.5 2.6 2.8 2.98 2.95 ...
##  $ Flavanoides     : num  2.76 3.24 3.49 2.69 3.39 2.52 2.51 2.98 3.15 3.32 ...
##  $ Fenoles.No.Flava: num  0.26 0.3 0.24 0.39 0.34 0.3 0.31 0.29 0.22 0.22 ...
##  $ Proantocianinos : num  1.28 2.81 2.18 1.82 1.97 1.98 1.25 1.98 1.85 2.38 ...
##  $ Int.Color       : num  4.38 5.68 7.8 4.32 6.75 5.25 5.05 5.2 7.22 5.75 ...
##  $ Tono.Color      : num  1.05 1.03 0.86 1.04 1.05 1.02 1.06 1.08 1.01 1.25 ...
##  $ OD280.OD315     : num  3.4 3.17 3.45 2.93 2.85 3.58 3.58 2.85 3.55 3.17 ...
##  $ Prolino         : int  1050 1185 1480 735 1450 1290 1295 1045 1045 1510 ...
summary(datos)
##  Tipo.Vino    Alcohol        Malic.Acid       Ceniza       Alcal.Ceniza  
##  1:58      Min.   :11.03   Min.   :0.74   Min.   :1.360   Min.   :10.60  
##  2:71      1st Qu.:12.36   1st Qu.:1.60   1st Qu.:2.210   1st Qu.:17.20  
##  3:48      Median :13.05   Median :1.87   Median :2.360   Median :19.50  
##            Mean   :12.99   Mean   :2.34   Mean   :2.366   Mean   :19.52  
##            3rd Qu.:13.67   3rd Qu.:3.10   3rd Qu.:2.560   3rd Qu.:21.50  
##            Max.   :14.83   Max.   :5.80   Max.   :3.230   Max.   :30.00  
##     Magnesio        Fenols.Tot     Flavanoides    Fenoles.No.Flava
##  Min.   : 70.00   Min.   :0.980   Min.   :0.340   Min.   :0.1300  
##  1st Qu.: 88.00   1st Qu.:1.740   1st Qu.:1.200   1st Qu.:0.2700  
##  Median : 98.00   Median :2.350   Median :2.130   Median :0.3400  
##  Mean   : 99.59   Mean   :2.292   Mean   :2.023   Mean   :0.3623  
##  3rd Qu.:107.00   3rd Qu.:2.800   3rd Qu.:2.860   3rd Qu.:0.4400  
##  Max.   :162.00   Max.   :3.880   Max.   :5.080   Max.   :0.6600  
##  Proantocianinos   Int.Color        Tono.Color     OD280.OD315   
##  Min.   :0.410   Min.   : 1.280   Min.   :0.480   Min.   :1.270  
##  1st Qu.:1.250   1st Qu.: 3.210   1st Qu.:0.780   1st Qu.:1.930  
##  Median :1.550   Median : 4.680   Median :0.960   Median :2.780  
##  Mean   :1.587   Mean   : 5.055   Mean   :0.957   Mean   :2.604  
##  3rd Qu.:1.950   3rd Qu.: 6.200   3rd Qu.:1.120   3rd Qu.:3.170  
##  Max.   :3.580   Max.   :13.000   Max.   :1.710   Max.   :4.000  
##     Prolino      
##  Min.   : 278.0  
##  1st Qu.: 500.0  
##  Median : 672.0  
##  Mean   : 745.1  
##  3rd Qu.: 985.0  
##  Max.   :1680.0

Crear datos de enrenamiento 70%

set.seed(2020)
vino_entrenamiento <- sample_frac(datos, .7)
head(vino_entrenamiento)
##   Tipo.Vino Alcohol Malic.Acid Ceniza Alcal.Ceniza Magnesio Fenols.Tot
## 1         3   13.84       4.12   2.38         19.5       89       1.80
## 2         2   11.65       1.67   2.62         26.0       88       1.92
## 3         1   13.71       1.86   2.36         16.6      101       2.61
## 4         2   12.37       1.21   2.56         18.1       98       2.42
## 5         1   13.83       1.57   2.62         20.0      115       2.95
## 6         3   13.78       2.76   2.30         22.0       90       1.35
##   Flavanoides Fenoles.No.Flava Proantocianinos Int.Color Tono.Color OD280.OD315
## 1        0.83             0.48            1.56      9.01       0.57        1.64
## 2        1.61             0.40            1.34      2.60       1.36        3.21
## 3        2.88             0.27            1.69      3.80       1.11        4.00
## 4        2.65             0.37            2.08      4.60       1.19        2.30
## 5        3.40             0.40            1.72      6.60       1.13        2.57
## 6        0.68             0.41            1.03      9.58       0.70        1.68
##   Prolino
## 1     480
## 2     562
## 3    1035
## 4     678
## 5    1130
## 6     615

Crear datos de prueba o validación

vino_prueba <- setdiff(datos, vino_entrenamiento)
head(vino_prueba)
##   Tipo.Vino Alcohol Malic.Acid Ceniza Alcal.Ceniza Magnesio Fenols.Tot
## 1         1   13.24       2.59   2.87         21.0      118       2.80
## 2         1   14.39       1.87   2.45         14.6       96       2.50
## 3         1   13.86       1.35   2.27         16.0       98       2.98
## 4         1   14.12       1.48   2.32         16.8       95       2.20
## 5         1   13.75       1.73   2.41         16.0       89       2.60
## 6         1   12.93       3.80   2.65         18.6      102       2.41
##   Flavanoides Fenoles.No.Flava Proantocianinos Int.Color Tono.Color OD280.OD315
## 1        2.69             0.39            1.82      4.32       1.04        2.93
## 2        2.52             0.30            1.98      5.25       1.02        3.58
## 3        3.15             0.22            1.85      7.22       1.01        3.55
## 4        2.43             0.26            1.57      5.00       1.17        2.82
## 5        2.76             0.29            1.81      5.60       1.15        2.90
## 6        2.41             0.25            1.98      4.50       1.03        3.52
##   Prolino
## 1     735
## 2    1290
## 3    1045
## 4    1280
## 5    1320
## 6     770

Entrenando el modelo

arbol <- rpart(formula = Tipo.Vino ~ ., data = vino_entrenamiento)
arbol
## n= 124 
## 
## node), split, n, loss, yval, (yprob)
##       * denotes terminal node
## 
## 1) root 124 78 2 (0.35483871 0.37096774 0.27419355)  
##   2) Prolino>=755 48  5 1 (0.89583333 0.06250000 0.04166667)  
##     4) Flavanoides>=2.35 41  0 1 (1.00000000 0.00000000 0.00000000) *
##     5) Flavanoides< 2.35 7  4 2 (0.28571429 0.42857143 0.28571429) *
##   3) Prolino< 755 76 33 2 (0.01315789 0.56578947 0.42105263)  
##     6) Int.Color< 4.79 45  4 2 (0.02222222 0.91111111 0.06666667) *
##     7) Int.Color>=4.79 31  2 3 (0.00000000 0.06451613 0.93548387) *

Generando el árbol

rpart.plot(arbol)

Generar predicciones con el modelo

prediccion_1 <- predict(arbol, newdata = vino_prueba, type = "class")

Generando matriz de Confusión

matriz.confusion_1 <- confusionMatrix(prediccion_1, vino_prueba[["Tipo.Vino"]])

matriz.confusion_1
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction  1  2  3
##          1 13  1  0
##          2  1 22  6
##          3  0  2  8
## 
## Overall Statistics
##                                           
##                Accuracy : 0.8113          
##                  95% CI : (0.6803, 0.9056)
##     No Information Rate : 0.4717          
##     P-Value [Acc > NIR] : 3.818e-07       
##                                           
##                   Kappa : 0.6968          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: 1 Class: 2 Class: 3
## Sensitivity            0.9286   0.8800   0.5714
## Specificity            0.9744   0.7500   0.9487
## Pos Pred Value         0.9286   0.7586   0.8000
## Neg Pred Value         0.9744   0.8750   0.8605
## Prevalence             0.2642   0.4717   0.2642
## Detection Rate         0.2453   0.4151   0.1509
## Detection Prevalence   0.2642   0.5472   0.1887
## Balanced Accuracy      0.9515   0.8150   0.7601
n <- nrow(vino_prueba) # Total de casos
print((13 + 22 + 8) / n * 100)
## [1] 81.13208
print("Representa el 81% la probabilidad de Éxito del total de los datos")
## [1] "Representa el 81% la probabilidad de Éxito del total de los datos"

Construir otro modelo

set.seed(7439)
vino_entrenamiento_2 <- sample_frac(datos, .7)

vino_prueba_2 <- setdiff(datos, vino_entrenamiento)

arbol_2 <- rpart(formula = Tipo.Vino ~ ., data = vino_entrenamiento_2)

prediccion_2 <- predict(arbol_2, newdata = vino_prueba_2, type = "class")

rpart.plot(arbol_2)

Otra matriz de confusión con la prediccion_2

matriz.confusion_2 <- confusionMatrix(prediccion_2, vino_prueba_2[["Tipo.Vino"]])

matriz.confusion_2
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction  1  2  3
##          1 14  1  0
##          2  0 22  2
##          3  0  2 12
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9057          
##                  95% CI : (0.7934, 0.9687)
##     No Information Rate : 0.4717          
##     P-Value [Acc > NIR] : 2.81e-11        
##                                           
##                   Kappa : 0.853           
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: 1 Class: 2 Class: 3
## Sensitivity            1.0000   0.8800   0.8571
## Specificity            0.9744   0.9286   0.9487
## Pos Pred Value         0.9333   0.9167   0.8571
## Neg Pred Value         1.0000   0.8966   0.9487
## Prevalence             0.2642   0.4717   0.2642
## Detection Rate         0.2642   0.4151   0.2264
## Detection Prevalence   0.2830   0.4528   0.2642
## Balanced Accuracy      0.9872   0.9043   0.9029
n <- nrow(vino_prueba_2) # Total de casos
print((14 + 22 + 12) / n * 100)
## [1] 90.56604
print("Representa el 90.56% la probabilidad de Éxito del total de los datos")
## [1] "Representa el 90.56% la probabilidad de Éxito del total de los datos"

¿Cómo elegimos un modelo?

Pero también puede ser que el propósito del análisis sea clasificar vinos por riesgo de toxicidad. En este caso sí es importante tener reglas precisas para hacer predicciones.

En todo caso, una manera de elegir un modelo es, en realidad, crear múltiples modelos y compararlos. Por ejemplo, creamos cien árboles con los mismos datos y después analizaos los modelos que tienen más éxito para clasificar para determinar cuáles variables son las que mejor separan los datos y en qué rangos se encuentran los valores de las reglas. De hecho, este es el principio del método Random Forest, pero ese es tema para otro día.