library(MASS)
library(randomForest)
## randomForest 4.6-14
## Type rfNews() to see new features/changes/bug fixes.
library(ggplot2)
## 
## Attaching package: 'ggplot2'
## The following object is masked from 'package:randomForest':
## 
##     margin
library(tibble)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following object is masked from 'package:randomForest':
## 
##     combine
## The following object is masked from 'package:MASS':
## 
##     select
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
data("Boston")
index <- sample(nrow(Boston),nrow(Boston)*0.70) # separar train/test
boston.train <- Boston[index,]
boston.test <- Boston[-index,]
rm(Boston)

El número de columnas es ncol(Boston)

El data set tiene 14 columnas: 1 variables respuesta y 13 predictores.

Bagging

En lugar de ajustar un único árbol, se ajustan muchos de ellos en paralelo formando un “bosque”. En cada nueva predicción, todos los árboles que forman el “bosque” participan aportando su predicción. Como valor final, se toma la media de todas las predicciones (variables continuas) o la clase más frecuente (variables cualitativas). Uno de los métodos de bagging más conocidos es Random Forest. El paquete de R ipred, tiene funciones facilitadoras para el Bagging. Hay que instalarlo antes de su uso.

library(ipred)

Bagging para un arbol de decisiones

modelo simple de Bagging con 100 replicaciones. Calculamos el error cuadrático medio.

boston.bag<- bagging(medv~., data = boston.train, nbagg=100)

boston.bag.pred<- predict(boston.bag, newdata = boston.test)

mean((boston.test$medv-boston.bag.pred)^2)
## [1] 23.75573
rm(boston.bag,boston.bag.pred)

Para el caso de un árbol normal.

library(rpart)

boston.tree<- rpart(medv~., data = boston.train)

boston.tree.pred<- predict(boston.tree, newdata = boston.test)

mean((boston.test$medv-boston.tree.pred)^2)
## [1] 27.52048
rm(boston.tree,boston.tree.pred)

Como podemos ver, ingresar árboles paralelos al modelo disminuye el error. Cabe preguntarse, ¿hasta cuantos árboles es eficiente ingresar?

ntree<- c(1, 3, 5, seq(10, 200, 10))
MSE.test<- rep(0, length(ntree))
for(i in 1:length(ntree)){
  boston.bag1<- bagging(medv~., data = boston.train, nbagg=ntree[i])
  boston.bag.pred1<- predict(boston.bag1, newdata = boston.test)
  MSE.test[i]<- mean((boston.test$medv-boston.bag.pred1)^2)
}
plot(ntree, MSE.test, type = 'l', col=2, lwd=2)

rm(boston.bag1,boston.tree)
## Warning in rm(boston.bag1, boston.tree): object 'boston.tree' not found

Notar que a mayor cantidad de árboles llega un punto donde su ganancia marginal es nula. Además, ingresar demasiados árboles tiende a sobreajustarse a la base de entrenamiento, lo que perjudicaría el modelo y su capacidad de adaptarse a nuevos datos.

Out-of-bag (OOB)

OOB es una forma de validar un modelo de Random Forest. En cada iteración de Bootstrap, las muestras no usadas servirán para testear el modelo. Finalmente, se muestra el MSE disminuído.

boston.bag.oob<- bagging(medv~., data = boston.train, coob=T, nbagg=100)
boston.bag.oob # coob=T significa que sea TRUE el uso de OOB
## 
## Bagging regression trees with 100 bootstrap replications 
## 
## Call: bagging.data.frame(formula = medv ~ ., data = boston.train, coob = T, 
##     nbagg = 100)
## 
## Out-of-bag estimate of root mean squared error:  3.9745
rm(boston.bag.oob)