Случайные леса вряд ли являются черным ящиком. Они основаны на деревьях решений, которые очень легко интерпретировать:
#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, оно классифицирует наблюдение как «virginica». Случайный лес - это просто набор из множества таких деревьев, каждое из которых обучается на случайном подмножестве данных. Затем каждое дерево «голосует» за окончательную классификацию каждого наблюдения.
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
Вы даже можете вытащить отдельные деревья из рф и посмотреть на их структуру. Формат немного отличается от 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 - virginica. Как видите, случайный лес - хорошая модель, даже на тестовом наборе.
Кроме того, случайный лес вычислит различную меру переменной важности, которая может быть очень информативной:
> 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)])
Вы можете просмотреть файлы справки для каждой из этих функций, чтобы лучше понять, что они отображают.