问题 随机森林的varImp(插入符号)和重要性(randomForest)之间的差异


我不明白哪个是有区别的 varImp 功能(caret 包)和 importance 功能(randomForest package)用于随机森林模型:

我计算了一个简单的RF分类模型,当计算变量重要性时,我发现两个函数的预测变量的“排名”并不相同:

这是我的代码:

rfImp <- randomForest(Origin ~ ., data = TAll_CS,
                       ntree = 2000,
                       importance = TRUE)

importance(rfImp)

                                 BREAST       LUNG MeanDecreaseAccuracy MeanDecreaseGini
Energy_GLCM_R1SC4NG3        -1.44116806  2.8918537            1.0929302        0.3712622
Contrast_GLCM_R1SC4NG3      -2.61146974  1.5848150           -0.4455327        0.2446930
Entropy_GLCM_R1SC4NG3       -3.42017102  3.8839464            0.9779201        0.4170445
...

varImp(rfImp)
                                 BREAST        LUNG
Energy_GLCM_R1SC4NG3         0.72534283  0.72534283
Contrast_GLCM_R1SC4NG3      -0.51332737 -0.51332737
Entropy_GLCM_R1SC4NG3        0.23188771  0.23188771
...

我以为他们使用相同的“算法”,但我现在不确定。

编辑

为了重现这个问题, ionosphere 数据集(kknn包)可以使用:

library(kknn)
data(ionosphere)
rfImp <- randomForest(class ~ ., data = ionosphere[,3:35],
                       ntree = 2000,
                       importance = TRUE)
importance(rfImp)
             b        g MeanDecreaseAccuracy MeanDecreaseGini
V3  21.3106205 42.23040             42.16524        15.770711
V4  10.9819574 28.55418             29.28955         6.431929
V5  30.8473944 44.99180             46.64411        22.868543
V6  11.1880372 33.01009             33.18346         6.999027
V7  13.3511887 32.22212             32.66688        14.100210
V8  11.8883317 32.41844             33.03005         7.243705
V9  -0.5020035 19.69505             19.54399         2.501567
V10 -2.9051578 22.24136             20.91442         2.953552
V11 -3.9585608 14.68528             14.11102         1.217768
V12  0.8254453 21.17199             20.75337         3.298964
...

varImp(rfImp)
            b         g
V3  31.770511 31.770511
V4  19.768070 19.768070
V5  37.919596 37.919596
V6  22.099063 22.099063
V7  22.786656 22.786656
V8  22.153388 22.153388
V9   9.596522  9.596522
V10  9.668101  9.668101
V11  5.363359  5.363359
V12 10.998718 10.998718
...

我想我错过了一些东西......

编辑2

我想出如果你做前两列的每一行的平均值 importance(rfImp),你得到的结果 varImp(rfImp)

impRF <- importance(rfImp)[,1:2]
apply(impRF, 1, function(x) mean(x))
       V3        V4        V5        V6        V7        V8        V9 
31.770511 19.768070 37.919596 22.099063 22.786656 22.153388  9.596522 
      V10       V11       V12 
 9.668101  5.363359 10.998718     ...

# Same result as in both columns of varImp(rfImp)

我不知道为什么会这样,但必须有一个解释。


2724
2018-06-17 18:59


起源

人们需要一个可重现的例子来准确回答问题。 - topepo
抱歉。我发现使用时会出现同样的问题 ionosphere 数据集。我要编辑这个问题 - Rafa OR
@topepo,你有什么看法?我希望你能帮助解释这些差异。 - Jot eN
我想出如果你做前两列的每一行的平均值 importance(rfImp),你得到的结果 varImp(rfImp),但我不知道为什么。我要编辑@topepo @JotEn这个问题 - Rafa OR


答案:


如果我们遍历varImp的方法:

检查对象:

> getFromNamespace('varImp','caret')
function (object, ...) 
{
    UseMethod("varImp")
}

获取S3方法:

> getS3method('varImp','randomForest')
function (object, ...) 
{
    code <- varImpDependencies("rf")
    code$varImp(object, ...)
}
<environment: namespace:caret>


code <- caret:::varImpDependencies('rf')

> code$varImp
function(object, ...){
                    varImp <- randomForest::importance(object, ...)
                    if(object$type == "regression")
                      varImp <- data.frame(Overall = varImp[,"%IncMSE"])
                    else {
                      retainNames <- levels(object$y)
                      if(all(retainNames %in% colnames(varImp))) {
                        varImp <- varImp[, retainNames]
                      } else {
                        varImp <- data.frame(Overall = varImp[,1])
                      }
                    }

                    out <- as.data.frame(varImp)
                    if(dim(out)[2] == 2) {
                      tmp <- apply(out, 1, mean)
                      out[,1] <- out[,2] <- tmp  
                    }
                    out
                  }

所以这并不是严格地返回randomForest :: importance,

它首先计算,然后只选择数据集中的分类值。

然后它做了一些有趣的事情,它会检查我们是否只有两列:

if(dim(out)[2] == 2) {
   tmp <- apply(out, 1, mean)
   out[,1] <- out[,2] <- tmp  
}

根据varImp手册页:

随机森林:varImp.randomForest和varImp.RandomForest   包含randomForest和的重要性函数的包装器   派对包,分别。

事实显然并非如此。


至于为什么......

如果我们只有两个值,则变量作为预测变量的重要性可以表示为一个值。

如果变量是预测变量 g那么它也必须是预测者 b

它确实有意义,但这不符合他们关于函数功能的文档,因此我可能会将此报告为意外行为。当您希望自己进行相对计算时,该功能会尝试提供帮助。


10
2017-10-05 17:14



快速添加到“至于为什么......”。 randomForest::importance() 在使用“标准错误”重新调整它们并将其报告为之前,使用加权平均值聚合特定于类的重要性分数 meanDecreaseAccuracy。 varImp() 采用(默认情况下)缩放的特定于类的分数并对其进行平均而不进行加权。对于不平等的阶级分布,第一个似乎更接近整体准确性的重要性,第二个偏向于稀有阶级。对此有任何理论上的处理吗? - joha
@joha你有稀有类别偏见的例子吗? (我不确定这里的均值来自哪里;还有其他方法可以将两个值合并为一个,为什么意思?)。另外,在2个对象的情况下,我的粗体评论显然是正确的,但我不确定它不应该对更多类有影响。它意味着额外的信息,每个班级的自由度减少1。 - Shape
我已经添加了一个答案来解释我的意思,也许你可以检查它是否有意义。对前一个评论的一处更正:randomForest :: importance() 才不是 使用加权平均值来聚合特定于类的重要性分数。 - joha


这个答案是@Shape对解决方案的补充。我觉得 importance 遵循Breiman众所周知的方法来计算报告的变量重要性 MeanDecreaseAccuracy,即对于每棵树的袋外样本计算树的准确性,然后一个接一个地置换变量并测量排列后的准确度,以计算没有该变量的精度的降低。
我无法找到关于如何计算第一列中特定类的精度降低的详细信息,但我认为它是 正确预测的类k /总预测类k

正如@Shape解释的那样, varImp 不报告 MeanDecreaseAccuracy 据报道 importance,而是计算(缩放的)类特定的准确度降低的平均值,并为每个类报告它。 (超过2个班级, varImp 仅报告特定类别的准确性下降。)
只有当类分布相等时,这种方法才是相似的。原因是只有在平衡的情况下,一个类别的准确性的降低同样会降低另一个类别的准确性。

library(caret)
library(randomForest)
library(mlbench)

### Balanced sample size ###
data(Ionosphere)
rfImp1 <- randomForest(Class ~ ., data = Ionosphere[,3:35], ntree = 1000, importance = TRUE)

# How importance() calculates the overall decerase in accuracy for the variable
Imp1 <- importance(rfImp1, scale = FALSE)
summary(Ionosphere$Class)/nrow(Ionosphere)
classRatio1 <- summary(Ionosphere$Class)/nrow(Ionosphere)
#      bad      good 
#0.3589744 0.6410256 

# Caret calculates a simple mean
varImp(rfImp1, scale = FALSE)["V3",] # 0.04542253
Imp1["V3", "bad"] * 0.5 + Imp1["V3", "good"] * 0.5 # 0.04542253
# importance is closer to the weighted average of class importances
Imp1["V3", ] # 0.05262225  
Imp1["V3", "bad"] * classRatio1[1] + Imp1["V3", "good"] * classRatio1[2] # 0.05274091

### Equal sample size ###
Ionosphere2 <- Ionosphere[c(which(Ionosphere$Class == "good"), sample(which(Ionosphere$Class == "bad"), 225, replace = TRUE)),]
summary(Ionosphere2$Class)/nrow(Ionosphere2)
classRatio2 <- summary(Ionosphere2$Class)/nrow(Ionosphere2)
#  bad good 
# 0.5  0.5

rfImp2 <- randomForest(Class ~ ., data = Ionosphere2[,3:35], ntree = 1000, importance = TRUE)
Imp2 <- importance(rfImp2, scale = FALSE)

# Caret calculates a simple mean
varImp(rfImp2, scale = FALSE)["V3",] # 0.06126641 
Imp2["V3", "bad"] * 0.5 + Imp2["V3", "good"] * 0.5 # 0.06126641 
# As does the average adjusted for the balanced class ratio
Imp2["V3", "bad"] * classRatio2[1] + Imp2["V3", "good"] * classRatio2[2] # 0.06126641 
# There is now not much difference between the measure for balanced classes
Imp2["V3",] # 0.06106229

我相信这可以解释为对所有课程同等重视的插入符号 importance 如果变量对于更常见的类很重要,则报告变量更为重要。我倾向于同意Max Kuhn,但是差异应该在文档中的某处解释。


4
2018-01-27 13:19





我没有您的确切数据,但使用虚拟数据(见下文)我无法重现此行为。也许仔细检查你真的没有做任何可能影响你的结果的事情。你使用哪个版本的R和插入符号?

library(caret)
library(randomForest)

# classification - same result
rfImp1 <- randomForest(Species ~ ., data = iris[,1:5],
                    ntree = 2000,
                    importance = TRUE)
importance(rfImp1)
varImp(rfImp1)

# regression - same result
rfImp2 <- randomForest(Sepal.Length ~ ., data = iris[,1:4],
                    ntree = 2000,
                    importance = TRUE)
importance(rfImp2)
varImp(rfImp2)

更新:

使用 Ionosphere 这是可重复的数据:

library(caret)
library(randomForest)
library(mlbench)
data(Ionosphere)
str(Ionosphere)
rfImp1 <- randomForest(Class ~ ., data = Ionosphere[,3:35], ntree = 2000, importance = TRUE)

......结果如下:

> head(importance(rfImp1))

         bad     good MeanDecreaseAccuracy MeanDecreaseGini
V3 20.545836 41.43872             41.26313        15.308791
V4 10.615291 29.31543             29.58395         6.226591
V5 29.508581 44.86784             46.79365        21.757928
V6  9.231544 31.77881             31.48614         7.201694
V7 12.461476 34.39334             34.92728        14.802564
V8 12.944721 32.49392             33.35699         6.971502

> head(varImp(rfImp1))

        bad     good
V3 30.99228 30.99228
V4 19.96536 19.96536
V5 37.18821 37.18821
V6 20.50518 20.50518
V7 23.42741 23.42741
V8 22.71932 22.71932

我的猜测是,插入符号和randomForest只是使用不同的方法来聚合来自不同运行的每个变量的结果 - 但@topepo现在很可能会给你一个确切的答案。


2
2018-06-20 20:05



你好@geekoverdose!我用过了 iris 正如你所说,数据集和两种功能的重要性是相同的。我已尝试使用其他数据集来重现问题,我发现如果我使用了 ionosphere 正如我在我的问题中提到的,这两个函数都给出了不同的重要性结果。 rfImp1 <- randomForest(class ~ ., data = ionosphere[,3:35], ntree = 2000, importance = TRUE)  我的R版本是3.2.5和 caret版本是6.0.68 - Rafa OR


https://www.r-bloggers.com/variable-importance-plot-and-variable-selection/ 在给定的链接中,已经显示当您在模型中未指定importance = TRUE时,使用randomForest和Caret包获得相同的平均减少Gini值


0
2018-06-15 12:41