En esta unidad, usarás la biblioteca YDF (Yggdrasil Decision Forest) para entrenar e interpretar un árbol de decisión.
Esta unidad se inspiró en el instructivo de 🧭 YDF Getting Started.
Preliminares
Antes de estudiar el conjunto de datos, haz lo siguiente:
- Crea un notebook de Colab nuevo.
- Para instalar la biblioteca de YDF, coloca y ejecuta la siguiente línea de código en tu nuevo notebook de Colab:
!pip install ydf -U
- Importa las siguientes bibliotecas:
import ydf import numpy as np import pandas as pd
El conjunto de datos de pingüinos de Palmer
En este Colab, se usa el conjunto de datos de Palmer Penguins, que contiene mediciones de tamaño de tres especies de pingüinos:
- Barbijo
- Gentoo
- Adelia
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 pingüinos de Palmer. Estos son los pingüinos:
Figura 16. Tres especies diferentes de pingüinos. 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 da 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 | Adelia | Torgersen | 39.1 | 18.7 | 181.0 | 3750.0 | masculino | 2007 |
1 | Adelia | Torgersen | 39.5 | 17.4 | 186.0 | 3800.0 | female | 2007 |
2 | Adelia | 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 es necesario realizar la codificación one-hot, la normalización ni agregar el atributo is_present adicional.
La siguiente celda de código 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 un árbol de decisión con hiperparámetros predeterminados
Puedes entrenar tu primer árbol de decisión con el algoritmo de aprendizaje CART (árboles de clasificación y regresión), también conocido como aprendiz, sin especificar ningún hiperparámetro.
Esto se debe a que el modelo de aprendizaje ydf.CartLearner
proporciona buenos valores predeterminados para los hiperparámetros. Más adelante en el curso, aprenderás más sobre cómo funciona este tipo de modelo.
model = ydf.CartLearner(label=label).train(train_dataset)
En la llamada anterior, no se especificaron las columnas que se usarán como variables 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, textual) de los atributos de entrada. Por lo tanto, la semántica de las funciones 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.
Figura 17: Es 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. Verosimilitud de diferentes especies si bill_depth_mm ≥
42.3
Especie | Probabilidad |
---|---|
Adelia (rojo) | 8% |
Pingüino papúa (azul) | 58% |
Sujetador de mentón (verde) | 36% |
Tabla 5. Verosimilitud de diferentes especies si bill_depth_mm < 42.3
Especie | Probabilidad |
---|---|
Adelia (rojo) | 97% |
Pingüino papúa (azul) | 2% |
Sujetador de mentón (verde) | 0% |
bill_depth_mm
es un atributo numérico. Por lo tanto, el valor 42.3 se encontró con el algoritmo de división exacta para la clasificación binaria con características numéricas.
Si bill_depth_mm ≥ 42.3
es verdadero, se realizan más pruebas para determinar si flipper_length_mm ≥ 207.5
puede separar casi perfectamente los pingüinos papúa de los pingüinos papúa y Adelia.
El siguiente código proporciona la exactitud del entrenamiento y la 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 poco común, pero es posible que la exactitud de la prueba sea mayor que la exactitud del entrenamiento. En ese caso, es posible que el conjunto de prueba difiera del conjunto de entrenamiento. Sin embargo, este no es el caso aquí, ya que los datos de entrenamiento y prueba se dividieron de forma aleatoria. Una explicación más probable es que el conjunto de datos de prueba sea muy pequeño (solo 72 ejemplos), por lo que la estimación de la 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, continuaremos con un entrenamiento y una prueba para simplificar las cosas.
Mejora de 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:
Usa un algoritmo de aprendizaje más potente, como un modelo de bosque aleatorio o de árboles potenciados por gradiente. Esos algoritmos de aprendizaje se explicarán en la próxima página.
Optimiza el hiperparámetro con tus observaciones y tu intuición. La guía para mejorar el modelo puede ser útil.
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 y de árboles potenciados por 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 61 ejemplos contiene una combinación de etiquetas de Adelia y Barbijo. ¿Por qué el algoritmo no dividió más esta hoja? 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()
Figura 18. Es un árbol de decisión entrenado con min_examples=1.
El nodo hoja que contiene 61 ejemplos se dividió varias veces.
Para ver si vale la pena 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ó, ya que la precisión de la prueba pasó de 0.9167 a 0.97222. Este cambio de hiperparámetro fue una buena idea.
Vista previa de los bosques de decisión
Si seguimos mejorando los hiperparámetros, es probable que alcancemos una precisión perfecta. 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, descubrirás por qué.
Uso y limitaciones
Como se mencionó anteriormente, un solo árbol de decisión suele tener una calidad inferior a la de los métodos modernos de aprendizaje automático, como los bosques aleatorios, los árboles potenciados por gradiente y las redes neuronales. Sin embargo, los árboles de decisión siguen siendo útiles en los siguientes casos:
- Como modelo de referencia simple y económico para evaluar enfoques más complejos
- Cuando hay una compensación entre la calidad y la interpretabilidad del modelo
- Como proxy para la interpretación del modelo de bosques de decisión, que se explorará más adelante en el curso.