Випадкові ліси навряд чи є чорною скринькою. Вони засновані на деревах рішень, які дуже легко інтерпретувати:
#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)
Це призводить до простого дерева рішень:
> 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) *
Якщо Petal.Length <4,95, це дерево класифікує спостереження як "інше". Якщо вона перевищує 4,95, це класифікує спостереження як "віргініку". Випадковий ліс - це проста сукупність багатьох таких дерев, де кожне тренується за випадковим набором даних. Тоді кожне дерево "голосує" за остаточну класифікацію кожного спостереження.
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
Можна навіть витягнути окремі дерева з rf та подивитися на їх будову. Формат дещо інший, ніж для rpart
моделей, але ви можете оглянути кожне дерево, якщо хочете, і побачити, як воно моделює дані.
Крім того, жодна модель не є справді чорною скринькою, оскільки ви можете вивчити прогнозовані відповіді та фактичні відповіді для кожної змінної в наборі даних. Це гарна ідея незалежно від того, яку модель ви будуєте:
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)
Я нормалізував змінні (довжина та ширина пелюсток і ширина) до діапазону 0-1. Відповідь також 0-1, де 0 - інше і 1 - віргініка. Як ви бачите, випадковий ліс є хорошою моделлю навіть на тестовому наборі.
Крім того, випадковий ліс обчислює різні міри змінної важливості, які можуть бути дуже інформативними:
> importance(model.rf, type=1)
MeanDecreaseAccuracy
Sepal.Length 0.28567162
Sepal.Width -0.08584199
Petal.Length 0.64705819
Petal.Width 0.58176828
Ця таблиця відображає, наскільки видалення кожної змінної зменшує точність моделі. Нарешті, існує багато інших сюжетів, які можна зробити з випадкової лісової моделі, щоб переглянути, що відбувається в чорному полі:
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)])
Ви можете переглянути файли довідки для кожної з цих функцій, щоб краще зрозуміти, що вони відображають.