Los bosques al azar son apenas una caja negra. Se basan en árboles de decisión, que son muy fáciles de interpretar:
#Setup a binary classification problem
require(randomForest)
data(iris)
set.seed(1)
dat <- iris
dat$Species <- factor(ifelse(dat$Species=='virginica','virginica','other'))
trainrows <- runif(nrow(dat)) > 0.3
train <- dat[trainrows,]
test <- dat[!trainrows,]
#Build a decision tree
require(rpart)
model.rpart <- rpart(Species~., train)
Esto da como resultado un árbol de decisión simple:
> model.rpart
n= 111
node), split, n, loss, yval, (yprob)
* denotes terminal node
1) root 111 35 other (0.68468468 0.31531532)
2) Petal.Length< 4.95 77 3 other (0.96103896 0.03896104) *
3) Petal.Length>=4.95 34 2 virginica (0.05882353 0.94117647) *
Si Petal.Length <4.95, este árbol clasifica la observación como "otro". Si es mayor que 4.95, clasifica la observación como "virginica". Un bosque aleatorio es una simple colección de muchos de estos árboles, donde cada uno es entrenado en un subconjunto aleatorio de los datos. Cada árbol "vota" en la clasificación final de cada observación.
model.rf <- randomForest(Species~., train, ntree=25, proximity=TRUE, importance=TRUE, nodesize=5)
> getTree(model.rf, k=1, labelVar=TRUE)
left daughter right daughter split var split point status prediction
1 2 3 Petal.Width 1.70 1 <NA>
2 4 5 Petal.Length 4.95 1 <NA>
3 6 7 Petal.Length 4.95 1 <NA>
4 0 0 <NA> 0.00 -1 other
5 0 0 <NA> 0.00 -1 virginica
6 0 0 <NA> 0.00 -1 other
7 0 0 <NA> 0.00 -1 virginica
Incluso puede extraer árboles individuales del rf y observar su estructura. El formato es ligeramente diferente al de los rpart
modelos, pero puede inspeccionar cada árbol si lo desea y ver cómo modela los datos.
Además, ningún modelo es realmente un recuadro negro, porque puede examinar las respuestas pronosticadas frente a las respuestas reales para cada variable en el conjunto de datos. Esta es una buena idea independientemente del tipo de modelo que esté construyendo:
library(ggplot2)
pSpecies <- predict(model.rf,test,'vote')[,2]
plotData <- lapply(names(test[,1:4]), function(x){
out <- data.frame(
var = x,
type = c(rep('Actual',nrow(test)),rep('Predicted',nrow(test))),
value = c(test[,x],test[,x]),
species = c(as.numeric(test$Species)-1,pSpecies)
)
out$value <- out$value-min(out$value) #Normalize to [0,1]
out$value <- out$value/max(out$value)
out
})
plotData <- do.call(rbind,plotData)
qplot(value, species, data=plotData, facets = type ~ var, geom='smooth', span = 0.5)
He normalizado las variables (sepal y pétalo de largo y ancho) a un rango de 0-1. La respuesta también es 0-1, donde 0 es otro y 1 es virginica. Como puede ver, el bosque aleatorio es un buen modelo, incluso en el conjunto de prueba.
Además, un bosque aleatorio calculará varias medidas de importancia variable, que pueden ser muy informativas:
> importance(model.rf, type=1)
MeanDecreaseAccuracy
Sepal.Length 0.28567162
Sepal.Width -0.08584199
Petal.Length 0.64705819
Petal.Width 0.58176828
Esta tabla representa cuánto eliminar cada variable reduce la precisión del modelo. Finalmente, hay muchas otras parcelas que puede hacer a partir de un modelo de bosque aleatorio, para ver lo que está sucediendo en el cuadro negro:
plot(model.rf)
plot(margin(model.rf))
MDSplot(model.rf, iris$Species, k=5)
plot(outlier(model.rf), type="h", col=c("red", "green", "blue")[as.numeric(dat$Species)])
Puede ver los archivos de ayuda para cada una de estas funciones para tener una mejor idea de lo que muestran.