Регрессия случайного леса: извлечение обучающих выборок в конечных узлах каждого дерева

#r #regression #random-forest

#r #регрессия #случайный лес

Вопрос:

Я хочу реализовать подход с прогнозирующим рецептом от Берцимаса и др. (2020), где они сочетают подход машинного обучения с оптимизацией. Для этого мне нужно посмотреть на конечные узлы (области разделения) каждого дерева решений в лесу.

В частности, я хочу знать следующие вещи для каждого дерева:

  1. В какой регион попадают обучающие выборки?
  2. К какому региону принадлежат тестовые выборки?

Я надеюсь, что мой вопрос станет понятнее на следующем рисунке одного дерева решений:

Пример дерева регрессии

Здесь, для первого конечного узла, меня интересует не прогноз 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=" "))
}
  

Необходимо упомянуть: я тестировал это только для числовых характеристик.