Creación de un árbol de decisiones

En esta unidad, usarás la biblioteca de YDF (bosque de decisión de Yggdrasil) para entrenar e interpretar un árbol de decisión.

Esta unidad se inspira en el instructivo 🧭 Cómo comenzar con YDF.

Preliminares

Antes de estudiar el conjunto de datos, haz lo siguiente:

  1. Crea un nuevo notebook de Colab.
  2. Para instalar la biblioteca YDF, coloca y ejecuta la siguiente línea de código en tu nuevo notebook de Colab:
    !pip install ydf -U
  3. Importa las siguientes bibliotecas:
    import ydf
    import numpy as np
    import pandas as pd

El conjunto de datos de los pingüinos de Palmer

Este Colab usa el conjunto de datos de los pinguinos de Palmer, que contiene mediciones de tamaño de tres especies de pingüinos:

  • Barbijo
  • Gentoo
  • Adelie

Este es un problema de clasificación: el objetivo es predecir la especie de pingüino según los datos del conjunto de datos de Palmer's Penguins. Estos son los pingüinos:

Tres especies de pingüinos
diferentes.

Figura 16: Tres especies de pingüinos diferentes. Imagen de @allisonhorst

 

El siguiente código llama a una función de pandas para cargar el conjunto de datos de Palmer Penguins en la memoria:

path = "https://storage.googleapis.com/download.tensorflow.org/data/palmer_penguins/penguins.csv"
dataset = pd.read_csv(path)
label = "species"

# Display the first 3 examples.
dataset.head(3)

En la siguiente tabla, se aplica formato a los primeros 3 ejemplos del conjunto de datos Palmer Penguins:

Tabla 3. Los primeros 3 ejemplos en Palmer Penguins

especie island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sexo año
0 Adelie Torgersen 39.1 18.7 181.0 3750.0 masculino 2007
1 Adelie Torgersen 39.5 17.4 186.0 3800.0 female 2007
2 Adelie Torgersen 40.3 18.0 195.0 3250.0 female 2007

El conjunto de datos completo contiene una combinación de atributos numéricos (por ejemplo, bill_depth_mm), categóricos (por ejemplo, island) y faltantes. A diferencia de las redes neuronales, los bosques de decisión admiten todos estos tipos de atributos de forma nativa, por lo que no tienes que realizar la codificación one-hot, la normalización ni la función is_present adicional.

En la siguiente celda de código, se divide el conjunto de datos en un conjunto de entrenamiento y un conjunto de prueba:

# Use the ~20% of the examples as the testing set
# and the remaining ~80% of the examples as the training set.
np.random.seed(1)
is_test = np.random.rand(len(dataset)) < 0.2

train_dataset = dataset[~is_test]
test_dataset = dataset[is_test]

print("Training examples: ", len(train_dataset))
# >> Training examples: 272

print("Testing examples: ", len(test_dataset))
# >> Testing examples: 72

Entrena árboles de decisión con hiperparámetros predeterminados

Puedes entrenar tu primer árbol de decisión con el algoritmo de aprendizaje (también conocido como "aprendiz") CART (árboles de clasificación y regresión) sin especificar ningún hiperparámetro. Esto se debe a que el aprendiz ydf.CartLearner proporciona buenos valores de hiperparámetros predeterminada. Más adelante en el curso, aprenderás más sobre el funcionamiento de este tipo de modelo.

model = ydf.CartLearner(label=label).train(train_dataset)

La llamada anterior no especificó las columnas que se usarán como atributos de entrada. Por lo tanto, se usa cada columna del conjunto de entrenamiento. La llamada tampoco especificó la semántica (por ejemplo, numérica, categórica o de texto) de los atributos de entrada. Por lo tanto, la semántica de los componentes se infiere automáticamente.

Llama a model.plot_tree() para mostrar el árbol de decisión resultante:

model.plot_tree()

En Colab, puedes usar el mouse para mostrar detalles sobre elementos específicos, como la distribución de clases en cada nodo.

Un árbol de decisión entrenado con hiperparámetros predeterminados.

Figura 17: Un árbol de decisión entrenado con hiperparámetros predeterminados.

Colab muestra que la condición raíz contiene 243 ejemplos. Sin embargo, es posible que recuerdes que el conjunto de datos de entrenamiento contenía 272 ejemplos. Los 29 ejemplos restantes se reservaron automáticamente para la validación y la poda del árbol.

La primera condición prueba el valor de bill_depth_mm. En las tablas 4 y 5, se muestra la probabilidad de diferentes especies según el resultado de la primera condición.

Tabla 4. Probabilidad de diferentes especies si bill_depth_mm ≥ 42.3

Especie Probabilidad
Adelia (rojo) 8%
Gentoo (azul) 58%
Correa de mentón (verde) 36%

 

Tabla 5. Probabilidad de diferentes especies si bill_depth_mm < 42.3

Especie Probabilidad
Adelia (rojo) 97%
Gentoo (azul) 2%
Correa para el mentón (verde) 0%

bill_depth_mm es un atributo numérico. Por lo tanto, se encontró el valor 42.3 con el algoritmo de división exacta para la clasificación binaria con atributos numéricos.

Si bill_depth_mm ≥ 42.3 es verdadero, se deben realizar más pruebas para determinar si flipper_length_mm ≥ 207.5 puede separar casi perfectamente los Gentoo y los Gentoo+Adelie.

El siguiente código proporciona la precisión de entrenamiento y prueba del modelo:

train_evaluation = model.evaluate(train_dataset)
print("train accuracy:", train_evaluation.accuracy)
# >> train accuracy:  0.9338

test_evaluation = model.evaluate(test_dataset)
print("test accuracy:", test_evaluation.accuracy)
# >> test accuracy:  0.9167

Es raro, pero posible, que la precisión de la prueba sea mayor que la precisión del entrenamiento. En ese caso, es posible que el conjunto de prueba difiera del conjunto de entrenamiento. Sin embargo, este no es el caso, ya que el entrenamiento y la prueba se dividieron de forma aleatoria. Una explicación más probable es que el conjunto de datos de prueba es muy pequeño (solo 72 ejemplos), por lo que la estimación de precisión es ruidosa.

En la práctica, para un conjunto de datos tan pequeño, sería preferible usar la validación cruzada, ya que calcularía valores de métricas de evaluación más precisos. Sin embargo, en este ejemplo, continuamos con una capacitación y pruebas por motivos de sencillez.

Mejora los hiperparámetros del modelo

El modelo es un solo árbol de decisión que se entrenó con valores de hiperparámetros predeterminados. Para obtener mejores predicciones, puedes hacer lo siguiente:

  1. Usa un algoritmo de aprendizaje más potente, como un bosque aleatorio o un modelo de árboles mejorados con gradiente. Estos algoritmos de aprendizaje se explicarán en la siguiente página.

  2. Optimiza el hiperparámetro con tus observaciones y tu intuición. La guía de mejora de modelos puede ser útil.

  3. Usa el ajuste de hiperparámetros para probar automáticamente una gran cantidad de hiperparámetros posibles.

Como aún no vimos el algoritmo de bosque aleatorio ni de árboles con aumento de gradiente, y como la cantidad de ejemplos es demasiado pequeña para realizar un ajuste automático de hiperparámetros, mejorarás el modelo de forma manual.

El árbol de decisión que se muestra arriba es pequeño, y la hoja con el ejemplo 61 contiene una combinación de etiquetas de Adelia y Barbijo. ¿Por qué el algoritmo no dividió esta hoja más? Existen dos motivos posibles:

  • Es posible que se haya alcanzado la cantidad mínima de muestras por hoja (min_examples=5 de forma predeterminada).
  • Es posible que el árbol se haya dividido y, luego, se haya podado para evitar el sobreajuste.

Reduce la cantidad mínima de ejemplos a 1 y observa los resultados:

model = ydf.CartLearner(label=label, min_examples=1).train(train_dataset)
model.plot_tree()

Un árbol de decisión entrenado con min_examples=1.

Figura 18: Un árbol de decisión entrenado con min_examples=1.

 

El nodo hoja que contiene 61 ejemplos se dividió varias veces.

Para ver si es útil dividir aún más el nodo, evaluamos la calidad de este nuevo modelo en el conjunto de datos de prueba:

print(model.evaluate(test_dataset).accuracy)
# >> 0.97222

La calidad del modelo aumentó con una precisión de prueba que pasó de 0.9167 a 0.97222. Este cambio de hiperparámetro fue una buena idea.

Anterior de un bosque de decisión

Si seguimos mejorando los hiperparámetros, es probable que podamos lograr una precisión óptima. Sin embargo, en lugar de este proceso manual, podemos entrenar un modelo más potente, como un bosque aleatorio, y ver si funciona mejor.

model = ydf.RandomForestLearner(label=label).train(train_dataset)
print("Test accuracy: ", model.evaluate(test_dataset).accuracy)
# >> Test accuracy: 0.986111

La precisión del bosque aleatorio es mejor que la de nuestro árbol simple. En las próximas páginas, aprenderás por qué.

Uso y limitaciones

Como se mencionó anteriormente, un solo árbol de decisión suele tener una calidad más baja que los métodos modernos de aprendizaje automático, como los bosques aleatorios, los árboles con gradiente boosting y las redes neuronales. Sin embargo, los árboles de decisión siguen siendo útiles en los siguientes casos:

  • Como un modelo de referencia simple y económico para evaluar enfoques más complejos.
  • Cuando hay un equilibrio entre la calidad y la interpretabilidad del modelo.
  • Como proxy para la interpretación del modelo de bosques de decisión, que el curso explorará más adelante.