Code
library(tidyverse)
library(rpart)
library(rpart.plot)
# library(bayesQR)
# library(broom)
# library(corrplot)
library(yardstick)
library(pROC)
#library(ggrepel)
# library(purrr)
# library(plotly)
Árboles de decisión: clasificación
library(tidyverse)
library(rpart)
library(rpart.plot)
# library(bayesQR)
# library(broom)
# library(corrplot)
library(yardstick)
library(pROC)
#library(ggrepel)
# library(purrr)
# library(plotly)
Regresión Lineal
Regresión Logística
Árboles de Decisión
k Nearest Neighbor
SVM
Naive Bayes
Clustering jerárquico
K-Means
PCA
Redes Neuronales
Aprendizaje profundo
Bagnato (2022)
Los arboles de decisión son representaciones gráficas de posibles soluciones a una decisión basadas en ciertas condiciones, es uno de los algoritmos deaprendizaje supervisado más utilizados en machine learning y pueden realizar tareas de clasificación o regresión (acrónimo del inglés CART).
La comprensión de su funcionamiento suele ser simple y a la vez muy potente. Utilizamos mentalmente estructuras de árbol de decisión constantemente en nuestra vida diaria sin darnos cuenta:
¿Llueve? –> lleva paraguas.
¿Soleado? –> lleva gafas de sol.
¿Estoy cansado? –> toma café.
Son Decisiones del tipo IF THIS, THEN THAT
Los árboles de decisión tienen un primer nodo llamado raíz (root) y luego se descomponen el resto de atributos de entrada en dos ramas (podrían ser más, pero no nos meteremos en eso ahora) planteando una condición que puede ser cierta o falsa. Se bifurca cada nodo en 2 y vuelven a subdividirse hasta llegar a las hojas que son los nodos finales y que equivalen a respuestas a la solución: Si/No, Comprar/Vender, o lo que sea que estemos clasificando. Otro ejemplo son los populares juegos de adivinanza:
1. ¿Animal ó vegetal? -Animal
2. ¿Tiene cuatro patas? -Si
3. ¿Hace guau? -Si
4. -Es un perro!
Supongamos que tenemos atributos como Género con valores “hombre ó mujer” y edad en rangos: “menor de 18 ó mayor de 18” para tomar una decisión.
Podríamos crear un árbol en el que dividamos primero por género y luego subdividir por edad. Ó podría ser al revés: primero por edad y luego por género. El algoritmo es quien analizando los datos y las salidas -por eso es supervisado!- decidirá la mejor forma de hacer las divisiones (splits) entre nodos. Tendrá en cuenta de qué manera lograr una predicción (clasificación ó regresión) con mayor probabilidad de acierto.
Parece sencillo, no? Pensemos que si tenemos 10 atributos de entrada cada uno con 2 o más valores posibles, las combinaciones para decidir el mejor árbol serían cientos ó miles… Esto ya no es un trabajo para hacer artesanalmente. Y ahí es donde este algoritmo cobra importancia, pues él nos devolverá el árbol óptimo para la toma de decisión más acertada desde un punto de vista probabilístico.
Para obtener el árbol óptimo y valorar cada subdivisión entre todos los árboles posibles y conseguir el nodo raiz y los subsiguientes, el algoritmo deberá medir de alguna manera las predicciones logradas y valorarlas para comparar de entre todas y obtener la mejor.
Para medir y valorar, utiliza diversas funciones, siendo las más conocidas y usadas los “Indice gini” y “Ganancia de información” que utiliza la denominada “entropía”. La división de nodos continuará hasta que lleguemos a la profundidad máxima posible del árbol ó se limiten los nodos a una cantidad mínima de muestras en cada hoja. A continuación describiremos muy brevemente cada una de las estrategias nombradas:
Se utiliza para atributos con valores continuos (precio de una casa). Esta función de coste mide el “grado de impureza” de los nodos, es decir, cuán desordenados o mezclados quedan los nodos una vez divididos. Deberemos minimizar ese GINI index.
Se utiliza para atributos categóricos (como en hombre/mujer). Este criterio intenta estimar la información que aporta cada atributo basado en la “teoría de la información”. Para medir la aleatoriedad de incertidumbre de un valor aleatorio de una variable “X” se define la Entropia. Al obtener la medida de entropía de cada atributo, podemos calcular la ganancia de información del árbol. Deberemos maximizar esa ganancia.
Minimum number of splits: Mínimo número de observaciones existentes para dividir un nodo. Valor por defecto 20.
Complexity parameter (cp): Valor típico: 0.01. Indica que si el modelo no mejora el modelo en, al menos un 1 %, no realiza más divisiones. Reduce la complejidad computacional y previene el sobreajuste.
Maximum depth: Valor por defecto 30. Mide la profundidad máxima entre el nodo raiz (profundidad 0) y el nodo más extremo (hojas).
https://www.ibm.com/es-es/topics/decision-trees
No se describen mediante ecuaciones.
No tienen como objetivo estimar parámetros lineales ni discutir su significancia estadística.
Se realiza un proceso de división recursiva de los datos, según los hiperparámetros definidos para minimizar los errores usando criterios como el índice Gini y la Ganancia de información.
Utilizan diferentes criterios de estimación dependiendo de la naturaleza de la variable dependiente. Se dividen en:
Árboles de Clasificación: Cuando la variable dependiente es categórica (dicotómica o politómica).
Árboles de Regresión: Cuando la variable dependiente es métrica (contínua). No utilizan el procedimiento paso a paso.
Pueden tener hiperparámetros
Tenemos un dataset triathlon
, basado en una encuesta a 200 atletas amateur que han competido en un triatlón sprint. La variable objetivo es finished
e indica si han sido o no capaces de terminarlo. Las variables predictoras son:
carbs_consumption
: Ingesta media de carbohidratos (en gr) por kg de peso corporal durante la preparación.training_days
: Binaria. Indica si el atleta se ha entrenado durante más de 90 días antes de la competición.load("data/triathlon.RData")
summary(triathlon)
competitor_id finished carbs_consumption training_days
1 : 1 no :141 Min. : 0.400 less than 90 days:107
2 : 1 yes: 59 1st Qu.: 1.144 more than 90 days: 93
3 : 1 Median : 2.225
4 : 1 Mean : 2.670
5 : 1 3rd Qu.: 3.944
6 : 1 Max. :10.325
(Other):194
# rpart utiliza validación cruzada con criterios random
set.seed(1) # necesario para reproductividad
<- rpart(formula = finished ~ carbs_consumption + training_days,
CART_triathlon data = triathlon,
control = rpart.control(minsplit = 20,
cp = 0.01,
maxdepth = 30),
parms = list(split = "information"), # list(split = "information"),
method = "class")
control
: Indica qué hiperparámetros se usarán.parms
: Indica el criterio para medir la impureza de los datos. “information” indica entropía, mientras que “gini” sería para el índice Gini.method
: “class” Indica que estamos usando un árbol de clasificación. “anova” indicaría un problema de regresiónrpart.plot(x = CART_triathlon,
type = 5,
box.palette = "RdGn",
extra = 2)
printcp(CART_triathlon)
Classification tree:
rpart(formula = finished ~ carbs_consumption + training_days,
data = triathlon, method = "class", parms = list(split = "information"),
control = rpart.control(minsplit = 20, cp = 0.01, maxdepth = 30))
Variables actually used in tree construction:
[1] carbs_consumption training_days
Root node error: 59/200 = 0.295
n= 200
CP nsplit rel error xerror xstd
1 0.42373 0 1.00000 1.00000 0.109312
2 0.16949 1 0.57627 0.57627 0.090038
3 0.01000 2 0.40678 0.50847 0.085589
<- (predict(object = CART_triathlon,
predicciones newdata = triathlon,
type = "prob"))
$fitted_probs <- predicciones[,2] triathlon
<- roc((triathlon$finished == "yes"), triathlon$fitted_probs) ROC
Setting levels: control = FALSE, case = TRUE
Setting direction: controls < cases
plot(ROC, col = "blue")
auc(ROC)
Area under the curve: 0.9404
# Matriz de confusión manual:
<- table(1*(triathlon$finished == "yes"), round(triathlon$fitted_probs))
outcomes outcomes
0 1
0 134 7
1 17 42
<- conf_mat(outcomes)
confusion summary(confusion, event_level = "second")
# A tibble: 13 × 3
.metric .estimator .estimate
<chr> <chr> <dbl>
1 accuracy binary 0.88
2 kap binary 0.697
3 sens binary 0.857
4 spec binary 0.887
5 ppv binary 0.712
6 npv binary 0.950
7 mcc binary 0.702
8 j_index binary 0.745
9 bal_accuracy binary 0.872
10 detection_prevalence binary 0.295
11 precision binary 0.712
12 recall binary 0.857
13 f_meas binary 0.778
Realiza un clasificador utilizando un árbol de decisión para el dataset bayesQR::Churn
Cambia cp = 0.01 por cp = 0.005 en el modelo del triatlón y en Churn. Vuelve a calcular las métricas y a dibujar el árbol. ¿Mejoran las métricas del modelo?
Cambia cp a 0 y el número mínimo de divisiones a 2. ¿Mejoran las métricas? ¿Qué consecuencia negativa podría tener?