Получить важность отдельных деревьев в RandomForest
Вопрос: Есть ли способ извлечь значение переменной для каждой отдельной модели CART из объекта randomForest
?
rf_mod$forest
, похоже, не имеет этой информации, и в документации не упоминается.
В пакете R randomForest
средняя значимость переменной для всего леса моделей CART определяется по importance(rf_mod)
.
library(randomForest)
df <- mtcars
set.seed(1)
rf_mod = randomForest(mpg ~ .,
data = df,
importance = TRUE,
ntree = 200)
importance(rf_mod)
%IncMSE IncNodePurity
cyl 6.0927875 111.65028
disp 8.7730959 261.06991
hp 7.8329831 212.74916
drat 2.9529334 79.01387
wt 7.9015687 246.32633
qsec 0.7741212 26.30662
vs 1.6908975 31.95701
am 2.5298261 13.33669
gear 1.5512788 17.77610
carb 3.2346351 35.69909
Мы также можем извлечь отдельную древовидную структуру с помощью getTree
. Здесь первое дерево.
head(getTree(rf_mod, k = 1, labelVar = TRUE))
left daughter right daughter split var split point status prediction
1 2 3 wt 2.15 -3 18.91875
2 0 0 <NA> 0.00 -1 31.56667
3 4 5 wt 3.16 -3 17.61034
4 6 7 drat 3.66 -3 21.26667
5 8 9 carb 3.50 -3 15.96500
6 0 0 <NA> 0.00 -1 19.70000
Один из обходных путей - вырастить много CART (то есть - ntree = 1
), получить значение переменной каждого дерева и усреднить полученный %IncMSE
:
# number of trees to grow
nn <- 200
# function to run nn CART models
run_rf <- function(rand_seed){
set.seed(rand_seed)
one_tr = randomForest(mpg ~ .,
data = df,
importance = TRUE,
ntree = 1)
return(one_tr)
}
# list to store output of each model
l <- vector("list", length = nn)
l <- lapply(1:nn, run_rf)
Этап извлечения, усреднения и сравнения.
# extract importance of each CART model
library(dplyr); library(purrr)
map(l, importance) %>%
map(as.data.frame) %>%
map( ~ { .$var = rownames(.); rownames(.) <- NULL; return(.) } ) %>%
bind_rows() %>%
group_by(var) %>%
summarise('%IncMSE' = mean('%IncMSE')) %>%
arrange(-'%IncMSE')
# A tibble: 10 x 2
var '%IncMSE'
<chr> <dbl>
1 wt 8.52
2 cyl 7.75
3 disp 7.74
4 hp 5.53
5 drat 1.65
6 carb 1.52
7 vs 0.938
8 qsec 0.824
9 gear 0.495
10 am 0.355
# compare to the RF model above
importance(rf_mod)
%IncMSE IncNodePurity
cyl 6.0927875 111.65028
disp 8.7730959 261.06991
hp 7.8329831 212.74916
drat 2.9529334 79.01387
wt 7.9015687 246.32633
qsec 0.7741212 26.30662
vs 1.6908975 31.95701
am 2.5298261 13.33669
gear 1.5512788 17.77610
carb 3.2346351 35.69909
Я хотел бы иметь возможность извлекать значение переменной каждого дерева непосредственно из объекта randomForest
, без этого обходного метода, который включает в себя полный повторный запуск RF, чтобы упростить воспроизводимые кумулятивные графики важности переменных, подобные этому, и показанному ниже показано для mtcars
. Минимальный пример здесь.
Я знаю, что важность одной переменной дерева не является статистически значимой, и я не намерен интерпретировать деревья изолированно. Я хочу, чтобы они были визуализированы и доведены до сведения, что по мере того, как в лесу растут деревья, переменные меры важности начинают прыгать до стабилизации.
Ответы
Ответ 1
При обучении модели randomForest
оценки важности вычисляются для всего леса и сохраняются непосредственно внутри объекта. Специфичные для дерева оценки не сохраняются и поэтому не могут быть напрямую получены из объекта randomForest
.
К сожалению, вы правы относительно необходимости постепенного создания леса. Хорошей новостью является то, что объект randomForest
является автономным, и вам не нужно реализовывать свой собственный run_rf
. Вместо этого вы можете использовать stats::update
для повторного randomForest::grow
модели случайного леса с одним деревом и randomForest::grow
для добавления дополнительных деревьев по одному:
## Starting with a random forest having a single tree,
## grow it 9 times, one tree at a time
rfs <- purrr::accumulate( .init = update(rf_mod, ntree=1),
rep(1,9), randomForest::grow )
## Retrieve the importance scores from each random forest
imp <- purrr::map( rfs, ~importance(.x)[,"%IncMSE"] )
## Combine all results into a single data frame
dplyr::bind_rows( !!!imp )
# # A tibble: 10 x 10
# cyl disp hp drat wt qsec vs am gear carb
# <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 0 18.8 8.63 1.05 0 1.17 0 0 0 0.194
# 2 0 10.0 46.4 0.561 0 -0.299 0 0 0.543 2.05
# 3 0 22.4 31.2 0.955 0 -0.199 0 0 0.362 5.1
# 4 1.55 24.1 23.4 0.717 0 -0.150 0 0 0.272 5.28
# 5 1.24 22.8 23.6 0.573 0 -0.178 0 0 -0.0259 4.98
# 6 1.03 26.2 22.3 0.478 1.25 0.775 0 0 -0.0216 4.1
# 7 0.887 22.5 22.5 0.406 1.79 -0.101 0 0 -0.0185 3.56
# 8 0.776 19.7 21.3 0.944 1.70 0.105 0 0.0225 -0.0162 3.11
# 9 0.690 18.4 19.1 0.839 1.51 1.24 1.01 0.02 -0.0144 2.77
# 10 0.621 18.4 21.2 0.937 1.32 1.11 0.910 0.0725 -0.114 2.49
Фрейм данных показывает, как значение функции изменяется с каждым дополнительным деревом. Это правая панель вашего примера сюжета. Сами деревья (для левой панели) можно получить из конечного леса, который задается с помощью dplyr::last( rfs )
.
Ответ 2
Отказ от ответственности: это не совсем ответ, но слишком долго, чтобы оставлять комментарии. Удалит, если сочтет неуместным.
Хотя я (думаю, что) понимаю ваш вопрос, если честно, я не уверен, имеет ли ваш вопрос смысл с точки зрения статистики /ML. Следующее основано на моем явно ограниченном понимании RF и CART. Возможно, мой комментарий-пост приведет к некоторому пониманию.
Давайте начнем с некоторой общей теории случайных лесов (RF) о переменной значимости из Хасти, Тибширани, Фридмана, Элементы статистического обучения, с. 593 (жирное лицо):
При каждом разделении в каждом дереве улучшение критерия разделения является показателем важности, приписываемым переменной разделения, и накапливается по всем деревьям в лесу отдельно для каждой переменной. [...] Случайные леса также используют oob выборки, чтобы построить другую меру переменной важности, очевидно, чтобы измерить силу предсказания каждой переменной.
Таким образом, показатель важности переменной в РФ определяется как показатель, накопленный по всем деревьям.
В традиционных единичных классификационных деревьях (CART) важность переменных характеризуется индексом Джини, который измеряет примеси в узлах (см., Например, " Как измерить/оценить" важность переменных "при использовании CART?" (В частности, используя {rpart} из R) и " Carolin Strobl PhD". дипломная работа)
Существуют более сложные меры для характеристики важности переменных в CART-подобных моделях; например в rpart
:
Общим показателем переменной важности является сумма добротности показателей разделения для каждого разделения, для которого оно было первичной переменной, плюс качество * (скорректированное соглашение) для всех разделений, в которых оно было суррогатом. В распечатке они масштабируются до суммы 100 и отображаются округленные значения, исключая любую переменную, доля которой составляет менее 1%.
Итак, суть здесь в следующем: по крайней мере будет непросто (а в худшем случае это не имеет смысла) сравнивать переменные меры из отдельных деревьев классификации с мерами переменной важности, применяемыми к методам на основе ансамбля. как РФ.
Что заставляет меня спросить: почему вы хотите извлечь переменные значения важности для отдельных деревьев из модели RF? Даже если вы придумали метод вычисления значений переменных из отдельных деревьев, я считаю, что они не будут иметь особого значения, и им не придется "сходиться" к накопленным в ансамбле значениям.
Ответ 3
Мы можем упростить это путем
library(tidyverse)
out <- map(seq_len(nn), ~
run_rf(.x) %>%
importance) %>%
reduce('+') %>%
magrittr::divide_by(nn)