获得随机森林中单个树木的重要性

时间:2019-05-04 17:47:31

标签: r machine-learning random-forest

问题:是否有一种方法可以从randomForest对象中提取每个CART模型的变量重要性?

rf_mod$forest似乎没有此信息,并且the docs没有提及。


在R的randomForest包中,整个importance(rf_mod)给出了整个CART模型林的平均变量重要性。

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以促进可复制的cumulative variable importance plots like this one,下面显示的是mtcarsMinimal example here

我知道一棵树的可变重要性在统计上是没有意义的,我也不打算孤立地解释树。我希望它们用于可视化和传达信息,即随着森林中树木的增加,重要性可变的指标在稳定之前会跳来跳去。

enter image description here

3 个答案:

答案 0 :(得分:9)

训练randomForest模型时,将为整个森林计算重要性得分,并将其直接存储在对象内部。不会保留特定树的分数,因此无法直接从randomForest对象中检索。

不幸的是,您必须逐步构建林是正确的。好消息是randomForest对象是独立的,您不需要实现自己的run_rf。相反,您可以使用stats::update用一棵树重新拟合随机森林模型,并使用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 )给出的最终森林中检索树木本身(用于左侧面板)。

答案 1 :(得分:4)

免责声明:这并不是真正的答案,但是太长了,无法发表评论。如果认为不合适,将删除。

虽然我(认为我)理解您的问题,但老实说,我不确定从统计学/机器学习的角度来看您的问题是否有意义。以下是基于我对RF和CART的明显有限的理解。也许我的评论文章会带来一些见识。

让我们从Hastie, Tibshirani, Friedman, The Elements of Statistical Learning,p。开始的一些关于可变重要性的通用随机森林(RF)理论开始。 593(黑体字):

  

在每棵树的每个分割处,分割标准的改进是   归因于拆分变量的重要性指标,并且   每个变量分别在森林中的所有树木上。 [...]   随机森林还使用oob样本构造不同的变量重要性度量,显然是用来度量每个变量的预测强度。

因此,定义为RF中的变量重要性度量,是在所有树上累积的度量。


在传统的单一分类树(CART)中,变量的重要性通过测量节点杂质的基尼指数来表征(例如,参见How to measure/rank “variable importance” when using CART? (specifically using {rpart} from R)Carolin Strobl's PhD thesis

在类似CART的模型中,存在更复杂的方法来描述变量重要性;例如在rpart中:

  

可变重要性的总体度量是分割的优劣之和   衡量每个拆分的主要变量,以及优度*(已调整   协议)作为代理的所有拆分。在打印输出中,这些比例将按比例累加   到100并显示四舍五入的值,省略比例小于的任何变量   超过1%。


因此,这里的底线是:至少比较单个分类树中的可变量度与应用于集合的可变重要性量度是不容易的(在最坏的情况下,这是没有意义的)诸如RF之类的方法。

哪个使我问:为什么您想从RF模型中提取单个树的可变重要性度量吗?即使您想出一种从各个树计算变量重要性的方法,我相信它们也不是很有意义,也不必“收敛”到集合累计值。

答案 2 :(得分:3)

我们可以简化它

    int thirdArray[] = { 0, 22, 1, 10, 8, 5,39 };
    int key,j;
    for(int i = 1 ; i < thirdArray.length ; i++)
    {
        key = thirdArray[i];
        j = i - 1;

        while(j >=0 && key < thirdArray[j])
        {
            thirdArray[j+1] = thirdArray[j];
            j--;
        }
        arr[j+1] = key;
    }
}