Comprender el bosque aleatorio usando Python (Scikit-Learn)

Los árboles son un algoritmo de aprendizaje supervisado popular con beneficios que incluyen poder usarse tanto para la regresión como para la clasificación, además de ser fácil de interpretar. Sin embargo, los árboles de decisión no son el algoritmo más desempeñado y son propensos al sobreajuste debido a pequeñas variaciones en los datos de entrenamiento. Esto puede dar como resultado un árbol completamente diferente. Esta es la razón por la cual las personas a menudo recurren a modelos de conjunto como árboles en bolsas y bosques aleatorios. Estos consisten en múltiples árboles de decisión entrenados en datos de arranque y agregados para lograr un mejor rendimiento predictivo del que cualquier árbol podría ofrecer. Este tutorial incluye lo siguiente:

  • Que esta empacando
  • Lo que hace que los bosques al azar sean diferentes
  • Entrenar y ajustar un bosque aleatorio usando Scikit-Learn
  • Calcular e interpretar la importancia de la característica
  • Visualizar árboles de decisión individuales en un bosque aleatorio

Como siempre, el código utilizado en este tutorial está disponible en mi Github. A versión de video De este tutorial también está disponible en mi canal de YouTube para aquellos que prefieren seguirlo visualmente. Con eso, ¡comencemos!

¿Qué es el bolso (agregando bootstrap)

Bootstrap + aggregating = Embolsar. Imagen de Michael Galarnyk.

Los bosques aleatorios se pueden clasificar como algoritmos de bolsas (bootstrap aggregatóning). El bolso consta de dos pasos:

1.) Bootstrap Sampling: cree múltiples conjuntos de entrenamiento dibujando al azar muestras con reemplazo del conjunto de datos original. Estos nuevos conjuntos de entrenamiento, llamados conjuntos de datos de arranque, generalmente contienen el mismo número de filas que el conjunto de datos original, pero las filas individuales pueden aparecer varias veces o no. En promedio, cada conjunto de datos de arranque contiene aproximadamente el 63.2% de las filas únicas de los datos originales. Los ~ 36.8% restantes de las filas se dejan fuera y se pueden usar para la evaluación fuera de bolsa (OOB). Para más información sobre este concepto, vea mi Muestreo con y sin publicación de blog de reemplazo.

2.) Predicciones de agregación: cada conjunto de datos de arranque se utiliza para entrenar un modelo de árbol de decisión diferente. La predicción final se realiza combinando los resultados de todos los árboles individuales. Para la clasificación, esto generalmente se hace a través de la mayoría de la votación. Para la regresión, las predicciones se promedian.

El entrenamiento de cada árbol en una muestra de arranque diferente introduce la variación entre los árboles. Si bien esto no elimina completamente la correlación, especialmente cuando ciertas características dominan, ayuda a reducir el sobreajuste cuando se combina con la agregación. Promediar las predicciones de muchos de estos árboles reduce la general diferencia del conjunto, mejorando la generalización.

Lo que hace que los bosques al azar sean diferentes

A diferencia de otros algoritmos de árboles en bolsas, para cada árbol de decisión en bosques aleatorios, solo se selecciona un subconjunto de características en cada nodo de decisión y se utiliza la mejor característica dividida del subconjunto. Imagen de Michael Galarnyk.

Supongamos que hay una sola característica fuerte en su conjunto de datos. En árboles en bolsascada árbol puede dividirse repetidamente en esa característica, lo que lleva a árboles correlacionados y menos beneficio de la agregación. Los bosques aleatorios reducen este problema al introducir una mayor aleatoriedad. Específicamente, cambian cómo se seleccionan las divisiones durante el entrenamiento:

1). Cree N Bootstraped DataSets. Tenga en cuenta que si bien el arranque se usa comúnmente en bosques aleatorios, no es estrictamente necesario porque el paso 2 (selección de características aleatorias) introduce suficiente diversidad entre los árboles.

2). Para cada árbol, en cada nodo, se selecciona un subconjunto aleatorio de características como candidatos, y la mejor división se elige de ese subconjunto. En scikit-learn, esto está controlado por el max_features parámetro, que por defecto es 'sqrt' para clasificadores y 1 para regresores (equivalente a los árboles en bolsas).

3). Predicciones agregadas: Vote por la clasificación y el promedio de la regresión.

Nota: Uso de bosques aleatorios Muestreo con reemplazo de conjuntos de datos de arranque y muestreo sin reemplazo para seleccionar un subconjunto de características.

Muestreo con procedimiento de reemplazo. Imagen de Michael Galarnyk

Puntaje fuera de bolsa (OOB)

Debido a que ~ 36.8% de los datos de capacitación están excluidos de cualquier árbol determinado, puede usar esta porción de retención para evaluar las predicciones del árbol. Scikit-Learn permite esto a través del parámetro OOB_Score = True, proporcionando una forma eficiente de estimar el error de generalización. Verá este parámetro utilizado en el ejemplo de entrenamiento más adelante en el tutorial.

Entrenamiento y ajuste de un bosque al azar en Scikit-Learn

Los bosques aleatorios siguen siendo una línea de base fuerte para los datos tabulares gracias a su simplicidad, interpretabilidad y capacidad para paralelo ya que cada árbol está entrenado de forma independiente. Esta sección demuestra cómo cargar datos, Realice una división de prueba de trencapacite a un modelo de línea de base, hiperparámetros de tune utilizando la búsqueda de cuadrícula y evalúe el modelo final en el conjunto de pruebas.

Paso 1: Entrena un modelo de referencia

Antes de sintonizar, es una buena práctica capacitar a un modelo de referencia utilizando valores predeterminados razonables. Esto le brinda una sensación inicial de rendimiento y le permite validar la generalización utilizando la puntuación fuera de bolsa (OOB), que está integrada en modelos basados ​​en bolsas como bosques aleatorios. Este ejemplo utiliza las ventas de viviendas en el conjunto de datos del condado de King (Licencia Universal CCO 1.0), que contiene ventas de propiedades del área de Seattle entre mayo de 2014 y mayo de 2015. Este enfoque nos permite reservar el conjunto de pruebas para la evaluación final después de la sintonización.

Python"># Import libraries

# Some imports are only used later in the tutorial
import matplotlib.pyplot as plt

import numpy as np

import pandas as pd

# Dataset: Breast Cancer Wisconsin (Diagnostic)
# Source: UCI Machine Learning Repository
# License: CC BY 4.0
from sklearn.datasets import load_breast_cancer

from sklearn.ensemble import RandomForestClassifier

from sklearn.ensemble import RandomForestRegressor

from sklearn.inspection import permutation_importance

from sklearn.model_selection import GridSearchCV, train_test_split

from sklearn import tree

# Load dataset
# Dataset: House Sales in King County (May 2014–May 2015)
# License CC0 1.0 Universal
url = 'https://raw.githubusercontent.com/mGalarnyk/Tutorial_Data/master/King_County/kingCountyHouseData.csv'

df = pd.read_csv(url)

columns = ['bedrooms',

            'bathrooms',

            'sqft_living',

            'sqft_lot',

             'floors',

             'waterfront',

             'view',

             'condition',

             'grade',

             'sqft_above',

             'sqft_basement',

             'yr_built',

             'yr_renovated',

             'lat',

             'long',

             'sqft_living15',

             'sqft_lot15',

             'price']

df = df[columns]

# Define features and target

X = df.drop(columns='price')

y = df['price']

# Train/test split

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

# Train baseline Random Forest

reg = RandomForestRegressor(

    n_estimators=100,        # number of trees

    max_features=1/3,        # fraction of features considered at each split

    oob_score=True,          # enables out-of-bag evaluation

    random_state=0

)

reg.fit(X_train, y_train)

# Evaluate baseline performance using OOB score

print(f"Baseline OOB score: {reg.oob_score_:.3f}")

Paso 2: Hyperparámetros de tune con búsqueda de cuadrícula

Si bien el modelo de línea de base ofrece un punto de partida fuerte, el rendimiento a menudo se puede mejorar al sintonizar los hiperparámetros clave. Búsqueda de cuadrícula validación cruzada, implementada por GridSearchCVexplora sistemáticamente combinaciones de hiperparámetros y utiliza validación cruzada para evaluar cada una, seleccionando la configuración con el rendimiento de validación más alto. Los hiperparámetros más comúnmente ajustados incluyen:

  • n_estimators: El número de árboles de decisión en el bosque. Más árboles pueden mejorar la precisión pero aumentar el tiempo de entrenamiento.
  • max_features: El número de características a considerar al buscar la mejor división. Los valores más bajos reducen la correlación entre los árboles.
  • max_depth: La profundidad máxima de cada árbol. Los árboles menos profundos son más rápidos pero pueden poco ajustados.
  • min_samples_split: El número mínimo de muestras requeridas para dividir un nodo interno. Los valores más altos pueden reducir el sobreajuste.
  • min_samples_leaf: El número mínimo de muestras necesarias para estar en un nodo de hoja. Ayuda a controlar el tamaño del árbol.
  • bootstrap: Si se usan muestras de bootstrap al construir árboles. Si falsa, se usa todo el conjunto de datos.
param_grid = {

    'n_estimators': [100],

    'max_features': ['sqrt', 'log2', None],

    'max_depth': [None, 5, 10, 20],

    'min_samples_split': [2, 5],

    'min_samples_leaf': [1, 2]

}

# Initialize model

rf = RandomForestRegressor(random_state=0, oob_score=True)

grid_search = GridSearchCV(

    estimator=rf,

    param_grid=param_grid,

    cv=5,             # 5-fold cross-validation

    scoring='r2',     # evaluation metric

    n_jobs=-1         # use all available CPU cores

)

grid_search.fit(X_train, y_train)

print(f"Best parameters: {grid_search.best_params_}")

print(f"Best R^2 score: {grid_search.best_score_:.3f}")

Paso 3: Evaluar el modelo final en el conjunto de pruebas

Ahora que hemos seleccionado el modelo de mejor rendimiento basado en la validación cruzada, podemos evaluarlo en el conjunto de pruebas de retención para estimar su rendimiento de generalización.

# Evaluate final model on test set

best_model = grid_search.best_estimator_

print(f"Test R^2 score (final model): {best_model.score(X_test, y_test):.3f}")

Calcular la importancia de la característica del bosque aleatorio

Una de las ventajas clave de los bosques aleatorios es su interpretabilidad, algo que a menudo carecen los modelos de idiomas grandes (LLM). Si bien los LLM son potentes, generalmente funcionan como cajas negras y pueden exhibir sesgos que son difíciles de identificar. En contraste, Scikit-Learn respalda dos métodos principales para medir la importancia de las características en los bosques aleatorios: disminución media de la impureza y la importancia de la permutación.

1). Disminución media de la impureza (MDI): también conocida como importancia de Gini, este método calcula la reducción total de la impureza traída por cada característica en todos los árboles. Esto es rápido y está integrado en el modelo a través de reg.feature_importances_. Sin embargo, las importantes de características basadas en la impureza pueden ser engañosas, especialmente para las características con alta cardinalidad (muchos valores únicos), ya que es más probable que estas características sean elegidas simplemente porque proporcionan más puntos de división potenciales.

importances = reg.feature_importances_

feature_names = X.columns

sorted_idx = np.argsort(importances)[::-1]

for i in sorted_idx:

    print(f"{feature_names[i]}: {importances[i]:.3f}")

2). Importancia de la permutación: este método evalúa la disminución en el rendimiento del modelo cuando los valores de una sola característica se barajan aleatoriamente. A diferencia de MDI, explica las interacciones y la correlación de características. Es más confiable pero también más costoso computacionalmente.

# Perform permutation importance on the test set

perm_importance = permutation_importance(reg, X_test, y_test, n_repeats=10, random_state=0)

sorted_idx = perm_importance.importances_mean.argsort()[::-1]

for i in sorted_idx:

    print(f"{X.columns[i]}: {perm_importance.importances_mean[i]:.3f}")

Es importante tener en cuenta que nuestras características geográficas LAT y Long también son útiles para la visualización, como lo muestra el gráfico a continuación. Es probable que compañías como Zillow aprovechen la información de ubicación ampliamente en sus modelos de valoración.

Percentil de precio de la vivienda para el condado de King. Imagen de Michael Galarnyk.

Visualizar árboles de decisión individuales en un bosque aleatorio

Un bosque aleatorio consta de múltiples árboles de decisión, uno para cada estimador especificado a través del n_estimators parámetro. Después de entrenar el modelo, puede acceder a estos árboles individuales a través del atributo .estimators_. Visualizar algunos de estos árboles puede ayudar a ilustrar cuán diferente cada uno divide los datos debido a muestras de entrenamiento de arranque y selección de características aleatorias en cada división. Si bien el ejemplo anterior utilizó un azar a RandomForestregresor, aquí demostramos esta visualización utilizando un Clasificador RandomForest Capacitado en el conjunto de datos de Wisconsin de cáncer de mama (Licencia CC por 4.0) para resaltar la versatilidad de los bosques aleatorios para las tareas de regresión y clasificación. Este breve video Demuestra cómo se ven 100 estimadores entrenados de este conjunto de datos.

Coloque un modelo de bosque aleatorio usando Scikit-Learn

# Load the Breast Cancer (Diagnostic) Dataset

data = load_breast_cancer()

df = pd.DataFrame(data.data, columns=data.feature_names)

df['target'] = data.target

# Arrange Data into Features Matrix and Target Vector

X = df.loc[:, df.columns != 'target']

y = df.loc[:, 'target'].values

# Split the data into training and testing sets

X_train, X_test, Y_train, Y_test = train_test_split(X, y, random_state=0)

# Random Forests in `scikit-learn` (with N = 100)

rf = RandomForestClassifier(n_estimators=100,

                            random_state=0)

rf.fit(X_train, Y_train)

Trazar estimadores individuales (árboles de decisión) de un bosque aleatorio utilizando matplotlib

Ahora puede ver todos los árboles individuales del modelo ajustado.

rf.estimators_

Ahora puedes visualizar árboles individuales. El siguiente código visualiza el primer árbol de decisión.

fn=data.feature_names

cn=data.target_names

fig, axes = plt.subplots(nrows = 1,ncols = 1,figsize = (4,4), dpi=800)

tree.plot_tree(rf.estimators_[0],

               feature_names = fn, 

               class_names=cn,

               filled = True);

fig.savefig('rf_individualtree.png')

Aunque trazar muchos árboles puede ser difícil de interpretar, es posible que desee explorar la variedad entre los estimadores. El siguiente ejemplo muestra cómo visualizar los primeros cinco árboles de decisión en el bosque:

# This may not the best way to view each estimator as it is small

fig, axes = plt.subplots(nrows=1, ncols=5, figsize=(10, 2), dpi=3000)

for index in range(5):

    tree.plot_tree(rf.estimators_[index],

                   feature_names=fn,

                   class_names=cn,

                   filled=True,

                   ax=axes[index])

    axes[index].set_title(f'Estimator: {index}', fontsize=11)

fig.savefig('rf_5trees.png')

Conclusión

Los bosques aleatorios consisten en múltiples árboles de decisión entrenados en datos de arranque para lograr un mejor rendimiento predictivo de lo que podría obtenerse de cualquiera de los árboles de decisión individuales. Si tiene preguntas o pensamientos sobre el tutorial, siéntase libre de comunicarse con YouTube o incógnita.