Los bosques aleatorios son una modificación de los árboles de decisión en bagging que crean una gran colección de árboles descorrelacionados para mejorar aún más el rendimiento predictivo. Se han convertido en un algoritmo de aprendizaje listo para usar muy popular que disfruta de un buen rendimiento predictivo con relativamente poco ajuste de hiperparámetros. Existen muchas implementaciones modernas de bosques aleatorios; sin embargo, se menciona el algoritmo de Leo Breiman (Breiman 2001).
Se emplearán la siguiente paquetería con el énfasis en cómo implementar bosques aleatorios con ranger (Wright and Ziegler 2017). Otra implementación de bosques se lleva cabo con h2o (LeDell et al. 2021). El resto de este material se basa fuertemente en el cap 11 de Boehmke and Greenwell (2020).
# data
library(mlbench)
library(tidyverse)
library(tidymodels)
library(rpart.plot)
library(vip)
data("BreastCancer")
BCrec <- recipe(Class ~ ., data = BreastCancer) %>%
step_naomit(all_predictors()) %>%
prep(BreastCancer, verbose = FALSE) %>%
bake(new_data = NULL)
BCrec2 <- BCrec %>% select(-Class,-Id) %>% mutate_all(as.numeric)
BCrec4 <- tibble(BCrec2,BCrec %>% select(Class))
set.seed(1234)
BCrec_split <- initial_split(BCrec4)
BCrec_train <- training(BCrec_split)
BCrec_test <- testing(BCrec_split)
# librerías auxiliares
library(dplyr) # manejo de datos
library(ggplot2) # mejores gráficas
# librerías de modelación
library(ranger) # implementación en c++ de random forest
library(h2o) # implementación en java-based de random forest
El ensacado o bagging de árboles introduce un componente aleatoria en el proceso de construcción de árboles al construir muchos árboles en copias de arranque de los datos de entrenamiento. El bagging luego agrega las predicciones en todos los árboles.
Los bosques aleatorios ayudan a reducir la correlación de árboles al inyectar más aleatoriedad en el proceso de crecimiento de los árboles. Más específicamente, mientras crece un árbol de decisión durante el proceso de baggging, los bosques aleatorios realizan una aleatorización de variables divididas donde cada vez que se realiza una división, la búsqueda de la variable dividida se limita a un subconjunto aleatorio de de las características . Los valores predeterminados típicos son \(m_{try}=\frac{p}{3}\) (regresión) y \(m_{try}=\sqrt{p}\) (clasificación), pero esto debe considerarse un parámetro de ajuste.
El algoritmo básico para un bosque aleatorio de regresión o clasificación se puede generalizar de la siguiente manera:
Dado que el algoritmo selecciona aleatoriamente una muestra de arranque para entrenar y una muestra aleatoria de características para usar en cada división, se produce un conjunto más diverso de árboles que tiende a disminuir la correlación de árboles más allá de los árboles en bolsas y, a menudo, aumenta drásticamente el poder predictivo.
Los bosques aleatorios se han vuelto populares porque tienden a proporcionar un rendimiento muy bueno desde el primer momento. Aunque tienen varios hiperparámetros que se pueden ajustar, los valores predeterminados tienden a producir buenos resultados.
Por ejemplo, al entrenar un modelo de bosque aleatorio con todos los hiperparámetros configurados en sus valores predeterminados, obtenemos un OOB rmse que es mejor que cualquier modelo hasta ahora.
# number of features
n_features <- length(setdiff(names(BCrec4), "Cell.size"))
# train a default random forest model
BC_rf1 <- ranger(
Cell.size ~ .,
data = BCrec_train,
mtry = floor(n_features / 3),
respect.unordered.factors = "order",
seed = 123
)
# get OOB RMSE
(default_rmse <- sqrt(BC_rf1$prediction.error))
## [1] 1.240171
Existen varios hiperparámetros ajustables a considerar al entrenar un modelo. Los principales incluyen:
La primera consideración es la cantidad de árboles dentro del bosque aleatorio. Aunque técnicamente no es un hiperparámetro, el número de árboles debe ser lo suficientemente grande para estabilizar la tasa de error. Una buena regla general es comenzar con \(10\) veces el número de características, sin embargo, a medida que se ajustan otros hiperparámetros como \(m_{try}\) y el tamaño del nodo, es posible que se requieran más o menos árboles. Más árboles proporcionan estimaciones de error más robustas y estables y medidas de importancia variable; sin embargo, el impacto en el tiempo de cálculo aumenta linealmente con el número de árboles.
El hiperparámetro que controla la función de aleatorización de variables divididas de los bosques aleatorios a menudo se denomina \(m_{try}\) y ayuda a equilibrar la correlación de árboles baja con una fuerza predictiva razonable. Con problemas de regresión, el valor predeterminado suele ser \(m_{try}=\frac{p}{3}\) y para la clasificación \(\sqrt{p}\). Sin embargo, cuando hay menos predictores relevantes (por ejemplo, datos ruidosos), un valor más alto de \(m_{try}\) tiende a funcionar mejor porque hace que sea más probable seleccionar aquellas características con la señal más fuerte. Cuando hay muchos predictores relevantes, un \(m_{try}\) bajo podría funcionar mejor.
Los bosques aleatorios se construyen sobre árboles de decisiones individuales; en consecuencia, la mayoría de las implementaciones de bosques aleatorias tienen uno o más hiperparámetros como el tamaño del nodo, la profundidad máxima, el número máximo de nodos terminales o el tamaño de nodo requerido para permitir divisiones adicionales. El tamaño del nodo es probablemente el hiperparámetro más común para controlar la complejidad del árbol y la mayoría de las implementaciones utilizan los valores predeterminados de uno para la clasificación y cinco para la regresión, ya que estos valores tienden a producir buenos resultados. Sin embargo, si los datos tienen muchos predictores ruidosos y valores altos tienen un mejor rendimiento, entonces el rendimiento puede mejorar al aumentar el tamaño del nodo (es decir, disminuir la profundidad y complejidad del árbol). Además, si el tiempo de cálculo es una preocupación, a menudo se puede disminuir el tiempo de ejecución sustancialmente aumentando el tamaño del nodo y tener solo impactos marginales en la estimación de error.
El esquema de muestreo predeterminado para bosques aleatorios es el bootstrap donde se muestrea el \(100%\) de las observaciones con reemplazo (en otras palabras, cada copia de bootstrap tiene el mismo tamaño que los datos de entrenamiento originales); sin embargo, se ajusta tanto el tamaño de la muestra como si tomar la muestra con o sin reemplazo. El parámetro de tamaño de la muestra determina cuántas observaciones se extraen para el entrenamiento de cada árbol. Disminuir el tamaño de la muestra conduce a árboles más diversos y, por lo tanto, a una menor correlación entre árboles, lo que puede tener un efecto positivo en la precisión de la predicción. En consecuencia, si hay algunas características dominantes de datos, reducir el tamaño de la muestra también puede ayudar a minimizar la correlación entre árboles.
Además, con muchas características categóricas de un número variable de niveles, el muestreo con reemplazo puede conducir a una selección dividida de variables sesgada. En consecuencia, categorías que no están equilibradas, el muestreo sin reemplazo proporciona un uso menos sesgado de todos los niveles en los árboles del bosque aleatorio.
La regla de división predeterminada durante la construcción de árboles de bosques aleatorios consiste en seleccionar, de todas las divisiones de las variables candidatas seleccionadas aleatoriamente, la división que minimiza la impureza de Gini (en el caso de la clasificación) y el SSE (en caso de regresión). Árboles de inferencia condicional implementan un mecanismo de división alternativo que ayude a reducir este sesgo de selección de variables.
Para aumentar la eficiencia computacional, las reglas de división se pueden aleatorizar donde solo se considera un subconjunto aleatorio de posibles valores de división para una variable. Si solo se selecciona al azar un único valor de división aleatorio, entonces llamamos a este procedimiento árboles extremadamente aleatorios. Debido a la aleatoriedad adicional de los puntos de división, este método tiende a no tener ninguna mejora, o a menudo tiene un impacto negativo, en la precisión predictiva.
Con respecto al tiempo de ejecución, los árboles extremadamente aleatorios son los más rápidos ya que los puntos de corte se dibujan de forma completamente aleatoria, seguidos del bosque aleatorio clásico, mientras que para los bosques de inferencia condicionales el tiempo de ejecución es el más grande.
Con una mayor cantidad de hiperparámetros, se debe llevar mayor estrategia con el ajuste. Se considera cómo avanzar en una búsqueda en la cuadrícula. Las búsquedas de cuadrículas cartesianas completas evalúan cada combinación de hiperparámetros de interés. El siguiente bloque de código busca en \(120\) combinaciones de configuraciones de hiperparámetros:
# cuadrícula de hiperparámetros
hyper_grid <- expand.grid(
mtry = floor(n_features * c(.05, .15, .25, .333, .4)),
min.node.size = c(1, 3, 5, 10),
replace = c(TRUE, FALSE),
sample.fraction = c(.5, .63, .8),
rmse = NA
)
# búsqueda cartesiana de cuadrícula
for(i in seq_len(nrow(hyper_grid))) {
# fit model for ith hyperparameter combination
fit <- ranger(
formula = Cell.size ~ .,
data = BCrec_train,
num.trees = n_features * 10,
mtry = hyper_grid$mtry[i],
min.node.size = hyper_grid$min.node.size[i],
replace = hyper_grid$replace[i],
sample.fraction = hyper_grid$sample.fraction[i],
verbose = FALSE,
seed = 123,
respect.unordered.factors = 'order',
)
# exportar error OOB
hyper_grid$rmse[i] <- sqrt(fit$prediction.error)
}
# modelos top
hyper_grid %>%
arrange(rmse) %>%
mutate(perc_gain = (default_rmse - rmse) / default_rmse * 100) %>%
head(10)
## mtry min.node.size replace sample.fraction rmse perc_gain
## 1 0 5 TRUE 0.63 1.240676 -0.04078014
## 2 3 5 TRUE 0.63 1.240676 -0.04078014
## 3 0 10 TRUE 0.63 1.243332 -0.25491073
## 4 3 10 TRUE 0.63 1.243332 -0.25491073
## 5 0 10 FALSE 0.80 1.245002 -0.38956505
## 6 3 10 FALSE 0.80 1.245002 -0.38956505
## 7 0 3 TRUE 0.50 1.247997 -0.63104506
## 8 3 3 TRUE 0.50 1.247997 -0.63104506
## 9 0 10 FALSE 0.50 1.249266 -0.73337182
## 10 3 10 FALSE 0.50 1.249266 -0.73337182
Al mirar los resultados, los \(10\) mejores modelos están todos cerca o por debajo de un rmse de \(1.25\). En estos resultados, el valor predeterminado de mtry
es \([\frac{No. features}{3}⌋=3\) y los tamaños de nodo más pequeños (árboles más profundos) funcionan mejor. El muestreo de menos del \(100%\) agrega aleatoriedad adicional en el procedimiento, lo que ayuda a descorrelacionar aún más los árboles.
Sin embargo, a más hiperparámetros, los conjuntos de datos se hacen más grandes, y una búsqueda cartesiana completa puede volverse exhaustiva y computacionalmente costosa. Además de la búsqueda cartesiana completa, el paquete h2o
proporciona una búsqueda de cuadrícula aleatoria que permite saltar de una combinación aleatoria a otra y también proporciona reglas de detención temprana que permiten detener la búsqueda de cuadrícula una vez que se cumple una determinada condición. Aunque es probable que el uso de una ruta de búsqueda discreta aleatoria no encuentre el modelo óptimo, por lo general hace un buen trabajo al encontrar un modelo muy bueno.
Para ajustar un modelo de bosque aleatorio con h2o
, primero se inicia sesión de h2o
.
h2o.no_progress()
h2o.init(max_mem_size = "5g")
## Connection successful!
##
## R is connected to the H2O cluster:
## H2O cluster uptime: 17 minutes 51 seconds
## H2O cluster timezone: America/Mexico_City
## H2O data parsing timezone: UTC
## H2O cluster version: 3.32.1.3
## H2O cluster version age: 2 months and 10 days
## H2O cluster name: H2O_started_from_R_juan_acuna_dmg384
## H2O cluster total nodes: 1
## H2O cluster total memory: 4.94 GB
## H2O cluster total cores: 4
## H2O cluster allowed cores: 4
## H2O cluster healthy: TRUE
## H2O Connection ip: localhost
## H2O Connection port: 54321
## H2O Connection proxy: NA
## H2O Internal Security: FALSE
## H2O API Extensions: Amazon S3, XGBoost, Algos, AutoML, Core V3, TargetEncoder, Core V4
## R Version: R version 4.1.0 (2021-05-18)
El cálculo de la importancia de las características y los efectos de las características para bosques aleatorios, además de la medida de la importancia de la característica basada en impurezas, también se incluye una función de permutación medida de importancia. En el enfoque basado en permutación, para cada árbol, la muestra OOB se transmite por el árbol y se registra la precisión de la predicción. Luego, los valores de cada variable (uno a la vez) se permutan aleatoriamente y se vuelve a calcular la precisión. La disminución en la precisión como resultado de esta mezcla aleatoria de valores de características se promedia sobre todos los árboles para cada predictor. Las variables con la mayor disminución promedio en la precisión se consideran las más importantes.
Por ejemplo, podemos calcular ambas medidas de importancia de características con ranger
estableciendo el argumento importance
.
# vip basada en impurezas
rf_impurity <- ranger(
formula = Cell.size ~ .,
data = BCrec_train,
num.trees = 2000,
mtry = 3,
min.node.size = 1,
sample.fraction = .80,
replace = FALSE,
importance = "impurity",
respect.unordered.factors = "order",
verbose = FALSE,
seed = 123
)
# vip basada en permutaciones
rf_permutation <- ranger(
formula = Cell.size ~ .,
data = BCrec_train,
num.trees = 2000,
mtry = 3,
min.node.size = 1,
sample.fraction = .80,
replace = FALSE,
importance = "permutation",
respect.unordered.factors = "order",
verbose = FALSE,
seed = 123
)
Los VIP resultantes se muestran en la Figura . Normalmente, no se verá el mismo orden de importancia en variables entre las dos opciones; sin embargo, a menudo se verán variables similares en la parte superior de los gráficos (y también en la parte inferior). En consecuencia, parece haber suficiente evidencia para sugerir que tres variables se destacan como las más influyentes:
p1 <- vip::vip(rf_impurity, num_features = 25, bar = FALSE)
p2 <- vip::vip(rf_permutation, num_features = 25, bar = FALSE)
gridExtra::grid.arrange(p1, p2, nrow = 1)
Los bosques aleatorios proporcionan un algoritmo que a menudo tiene una gran precisión predictiva. Vienen con todos los beneficios de los árboles de decisión (con la excepción de las divisiones sustitutas) y el bagging, pero reducen en gran medida la inestabilidad y la correlación entre árboles. Y debido al atributo de selección de variable de división agregado, los bosques aleatorios también son más rápidos que el bagging, ya que tienen un espacio de búsqueda de características más pequeño en cada división de árbol. Sin embargo, los bosques aleatorios todavía sufren de una velocidad computacional lenta a medida que las bases de datos se hacen grandes, pero, al igual que el bagging, el algoritmo se basa en pasos independientes y la mayoría de las implementaciones modernas (ranger
, h2o
) permiten la paralelización para mejorar el tiempo de entrenamiento.