Le foreste casuali non sono quasi una scatola nera. Si basano su alberi decisionali, che sono molto facili da interpretare:
#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)
Ciò si traduce in un semplice albero decisionale:
> 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) *
Se Petal.Length <4.95, questo albero classifica l'osservazione come "altro". Se è maggiore di 4,95, classifica l'osservazione come "virginica". Una foresta casuale è una raccolta semplice di molti di questi alberi, in cui ognuno è addestrato su un sottoinsieme casuale di dati. Ogni albero quindi "vota" sulla classificazione finale di ogni osservazione.
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
Puoi anche estrarre singoli alberi da RF e osservarne la struttura. Il formato è leggermente diverso rispetto ai rpart
modelli, ma è possibile ispezionare ogni albero se lo si desidera e vedere come modella i dati.
Inoltre, nessun modello è veramente una scatola nera, poiché è possibile esaminare le risposte previste rispetto alle risposte effettive per ogni variabile nel set di dati. Questa è una buona idea indipendentemente dal tipo di modello che stai costruendo:
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)
Ho normalizzato le variabili (lunghezza e larghezza del petalo e del petalo) in un intervallo 0-1. La risposta è anche 0-1, dove 0 è altro e 1 è virginica. Come puoi vedere, la foresta casuale è un buon modello, anche sul set di test.
Inoltre, una foresta casuale calcolerà varie misure di importanza variabile, che possono essere molto istruttive:
> importance(model.rf, type=1)
MeanDecreaseAccuracy
Sepal.Length 0.28567162
Sepal.Width -0.08584199
Petal.Length 0.64705819
Petal.Width 0.58176828
Questa tabella rappresenta la quantità di rimozione di ogni variabile che riduce la precisione del modello. Infine, ci sono molte altre trame che puoi creare da un modello di foresta casuale, per vedere cosa sta succedendo nella casella nera:
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)])
È possibile visualizzare i file della guida per ciascuna di queste funzioni per avere un'idea migliore di ciò che visualizzano.