4. Árboles de decisión

Agenda

  • ¿Qué es un árbol de decisión?
  • ¿Cómo se construye un árbol de decisión?
  • ¿Cómo se evalúa un árbol de decisión?
  • ¿Cómo se elige un árbol de decisión?

Árboles de decisión

Los árboles de decisión son estructuras parecidas a los diagramas de flujo que utilizan nodos y ramas. Los caminos en el árbol separan los datos de tal manera que se pueda llegar a una separación precisa de un conjunto de datos.

Los árboles de decisión son útiles porque proporcionan una forma fácil de visualizar y entender cómo se toman las decisiones en un modelo.

  • Nodos: grupo de observaciones que comparten una característica.

  • Ramas: separación de los nodos.

  • Hojas: resultado final de la separación.

Árboles de decisión

¿Qué es un buen árbol de decisión?

Efectivamente separa las observaciones en grupos homogéneos.

¿Cómo se construye un árbol de decisión?

Color Tamaño (m) Animal
Gris oscuro 5 Tiburón
Gris oscuro 6 Tiburón
Gris claro 7 Ballena
Gris oscuro 15 Tiburón
Azul 20 Ballena
Gris claro 25 Ballena

¿Cómo se construye un árbol de decisión?

Hay que identificar la variable que mejor separa las ballenas de los tiburones. Comencemos con el color.

¿Cómo se construye un árbol de decisión?

Si la variable es continua, se pueden tratar todos los valores posibles como puntos de corte.

¿Cómo se construye un árbol de decisión?

Ahora, que tenemos todas las posibles separaciones, ¿cómo elegimos la mejor?

Necessitamos una métrica para evaluar la calidad de la separación.

  • Entropía
  • Ganancia de información
  • Pureza de Gini
  • log loss

Pureza de Gini es una medida para evaluar qué tan mezclados están los datos (pureza). Toma valores desde 0 (perfectamente separados) a 0.5 (completamente revueltos).

https://mlu-explain.github.io/decision-tree/

¿Cómo se construye un árbol de decisión?

Crear la base de datos.

library(tibble)
animales_marinos <- tibble(
  Color = c("Gris oscuro", "Gris oscuro", "Gris claro", "Gris oscuro", "Azul", "Gris claro"),
  Tamano = c(5, 6, 7, 15, 20, 25),
  Animal = factor(c("Tiburón", "Tiburón", "Ballena", "Tiburón", "Ballena", "Ballena"))
)

Especificar el modelo.

tree_spec <- 
  decision_tree(cost_complexity=0, 
  min_n=0) |> 
  set_mode("classification") |> 
  set_engine("rpart")

¿Cómo se construye un árbol de decisión?

Estimar el modelo.

tree_results <- tree_spec |>
    fit(Animal ~ ., data = animales_marinos)

Visualizar los resultados.

cart_tree_fit <- tree_results$fit

treemisc::tree_diagram(cart_tree_fit, roundint = FALSE)

¿Cómo se construye un árbol de decisión?

tree_results <- tree_spec |>
    fit(Animal ~ Tamano, data = animales_marinos)
cart_tree_fit <- tree_results$fit

treemisc::tree_diagram(cart_tree_fit, roundint = FALSE)

Arbusto

Crear un árbol de decisión con algunos predictores.

Seleccionar los predictores.

los_datos <- DataWorkshopKL::base_NR

mi_primer_arbol <- los_datos |> 
  select("PYALC", "GETALC", "GENDER", "GRADE") 

Especificar el modelo.

tree_spec <- 
  decision_tree() |> 
  set_mode("classification") |> 
  set_engine("rpart")

Estimar el modelo

Estimar el modelo

tree_results <- tree_spec |>
    fit(PYALC ~ ., data = mi_primer_arbol)

Visualizar el árbol.

cart_tree_fit <- tree_results$fit

treemisc::tree_diagram(cart_tree_fit, roundint = FALSE)

Árboles de clasificación y regresión (CART)

Ahora, utilicemos todos los datos de la base de entrenamiento.

tree_results <- tree_spec |>
  fit(PYALC ~ ., data = datos_entrenamiento)

Calcular las métricas de desempeño del modelo.

predict(tree_results, predecir_estos_valores)

entrenamiento <- datos_entrenamiento %>%
  select(-PYALC)

prediccion_tree <- predict(tree_results, entrenamiento)

resultados_prueba_tree <- cbind(prediccion_tree, datos_entrenamiento) |>
select(PYALC, .pred_class) |>
  tibble()

Calcular las métrcias

Calcular las metricas que nos interesan.

tree_metrics <- custom_metrics(resultados_prueba_tree,
  truth = PYALC,
  estimate = .pred_class
) |>
  mutate(model = "Árbol")

Poner las métricas en un formato más fácil de comparar.

rbind(tree_metrics, lm_metrics) |>
  pivot_wider(names_from = model, values_from = .estimate)

CART con hiperparámetros

¿Qué es un hiperparámetro?

Los hiperparámetros son valores para los modelos que se pueden ajustar y que permiten controlar el proceso de entrenamiento de un modelo.

El proceso de selección de los hiperparámetros se llama ajuste de hiperparámetros (tunning) y se puede hacer de forma manual o automática.

Por ahora, vamos a hacerlo de forma manual.

tree_spec <- 
  decision_tree(min_n = 3, cost_complexity = 0.001) |>
  set_mode("classification") |>
  set_engine("rpart")

Estimar el modelo.

tree_h_results <- tree_spec |>
    fit(PYALC ~ ., data = datos_entrenamiento)

Calcular las métricas

Calcular las métricas que nos interesan.

tree_h_predicciones <- predict(tree_h_results, entrenamiento)

resultados_tree_h <- cbind(tree_h_predicciones, datos_entrenamiento) |>
  tibble()

tree_h_metrics <- custom_metrics(
  resultados_tree_h,
  truth = PYALC,
  estimate = .pred_class
) |>
  mutate(model = "Árbol hiperparámetros")

Tabla de métricas

rbind(lm_metrics, tree_metrics, tree_h_metrics) |>
  pivot_wider(names_from = model, values_from = .estimate)

¡Pero todo esto pasa en los datos de entrenamiento!

¿Por qué es malo?

El objetivo es encontrar un modelo que no solo sea buena en los datos de entrenamiento, sino que también sea bueno en datos futuros. Si solo evaluamos el modelo en los datos de entrenamiento, no sabemos si el modelo es bueno en datos futuros.

datos_prueba_out <- 
  datos_prueba |> 
    select(PYALC) 

lm_predicciones <- cbind(predict(lm_results, datos_prueba), datos_prueba_out)|> mutate(model="lm")

tree_predicciones <- cbind(predict(tree_results, datos_prueba), datos_prueba_out)|> mutate(model="Árbol")

tree_h_predicciones <- cbind(predict(tree_h_results, datos_prueba), datos_prueba_out) |>  mutate(model="Árbol hiperparámetros")

Desempeño de los modelos

all_models <- 
rbind(lm_predicciones, tree_predicciones, tree_h_predicciones) 

all_models

Tabla con todos los modelos

all_models_prueba <- all_models |> 
  group_split(model) %>%
   setNames(unique(all_models$model)) %>%
  map_dfr(., ~custom_metrics(.x,
               truth = PYALC,
               estimate = .pred_class), .id = "names")

all_models_prueba |> 
  pivot_wider(names_from = names, values_from = .estimate)

¿Cómo vamos a elegir el mejor modelo si solo evaluamos el modelo en los datos de prueba?

Práctica

Estime un arbol de decisión para la variable de consumo de marihuna. Intente diferente valores para los hiperparámetros y compare el desempeño del modelo en los datos de entrenamiento.