#r #regression #random-forest
#r #регрессия #случайный лес
Вопрос:
Я хочу реализовать подход с прогнозирующим рецептом от Берцимаса и др. (2020), где они сочетают подход машинного обучения с оптимизацией. Для этого мне нужно посмотреть на конечные узлы (области разделения) каждого дерева решений в лесу.
В частности, я хочу знать следующие вещи для каждого дерева:
- В какой регион попадают обучающие выборки?
- К какому региону принадлежат тестовые выборки?
Я надеюсь, что мой вопрос станет понятнее на следующем рисунке одного дерева решений:
Здесь, для первого конечного узла, меня интересует не прогноз m, а значения y1, y4 и y5, которые формируют основу для прогноза.
Идеальным результатом была бы структура, подобная матрице, где каждый столбец представляет одно дерево, а каждая строка представляет одну обучающую (тестовую) выборку. Для каждой выборки и дерева структура должна давать мне идентификатор региона / конечного узла, где можно найти образец!
Я просмотрел randomForest
а также ranger
пакет, но не смог найти ничего подходящего … в какой-то статье упоминалось о реализации метода с caret
пакетом, но они ничего не упоминали о том, как обойти предсказание.
Вот воспроизводимый пример регрессии с использованием ranger
:
library(MASS)
library(e1071)
library(ranger)
#load data
data(Boston)
set.seed(111)
ind <- sample(2, nrow(Boston), replace = TRUE, prob=c(0.8, 0.2))
train <- Boston[ind == 1,]
test <- Boston[ind == 2,]
#train random forest
boston.rf <- ranger(medv ~ ., data = train)
Любая помощь высоко ценится. Приветствия!
Комментарии:
1. В randomForest нет ни одного дерева (по умолчанию 500), поэтому существует 500 различных регионов, которые объединяются для получения окончательного ответа. На ваш вопрос нет простого ответа.
Ответ №1:
один из способов, который я нашел до сих пор, чтобы получить эту информацию, заключается в использовании randomForest
пакета с опцией keep.inbag=T
— это позволяет вам извлекать информацию, какие выборки используются для создания каждого дерева, — и метод getTree
для извлечения древовидной структуры каждого дерева в лесу.
Я создал функцию для извлечения идентификатора терминального узла с учетом древовидной структуры из getTree
.
# function to retrieve the terminal node id given a rf tree structure and a sample (with numerical only features)
get_terminal_node_id_for_sample <- function(tree, sample){
node_id=1
search <- TRUE
while(search){
if(tree$status[node_id]=="-1"){
search <- FALSE
break
}
if(sample[as.character(tree$split.var[node_id])] < tree$split.point[node_id]){
node_id <- as.numeric(tree$left.daughter[node_id])
} else {
node_id <- as.numeric(tree$right.daughter[node_id])
}
}
return(node_id)
}
И использовал это так:
library(randomForest)
library(MASS)
library(e1071)
# load data
data(Boston)
set.seed(111)
ind <- sample(2, nrow(Boston), replace = TRUE, prob=c(0.8, 0.2))
train <- Boston[ind == 1,]
test <- Boston[ind == 2,]
# train random forest and keep inbag information
model = randomForest(medv~.,data = train,
keep.inbag=T)
# get the first tree of the forest
treeind <- 1
tree <- data.frame(getTree(model, k=treeind, labelVar=TRUE))
# loop over each sample in inbag of the first tree
for (sampleind in which(model$inbag[,treeind]>0)){
sample <- train[sampleind,]
node_id <- get_terminal_node_id_for_sample(tree,sample)
##########################
# do whatever with node_id
##########################
print(paste("sample",sampleind,"is in terminal node",node_id,sep=" "))
}
Необходимо упомянуть: я тестировал это только для числовых характеристик.