为啥随机森林并行化后重要性会受到影响?

Posted

技术标签:

【中文标题】为啥随机森林并行化后重要性会受到影响?【英文标题】:Why importance is affected after parallelization of randomForest?为什么随机森林并行化后重要性会受到影响? 【发布时间】:2015-12-29 14:54:13 【问题描述】:

我现在正在使用 R 中的 randomForest 包。为了加快分类步骤,我对并行执行森林感兴趣。为此,我使用包'foreach'的方式与'foreach'小插图上指示的方式类似。这包括将树的总数除以您想要使用的核心数,然后将它们与包“randomForest”的“组合”功能组合:

require(randomForest)
require(foreach)
require(doParallel)
registerDoParallel(cores=CPUS)
rf  <- foreach::foreach(ntree=rep(ceiling(NTREE/CPUS), CPUS), .combine=randomForest::combine, .packages='randomForest') %dopar% 
    randomForest::randomForest(x=t(Y), y=A, ntree=ntree, importance=TRUE, ...)
    

我将“平行”森林的结果与一个核心中生成的森林进行了比较。与测试集的预测能力似乎相似,但“重要性”值大大降低,这影响了变量选择的后续步骤。

imp <- importance(rf,type=1)

我想知道为什么会发生这种情况,以及它是正确的还是有任何错误。非常感谢!

【问题讨论】:

代码似乎是正确的,据此:cran.r-project.org/web/packages/foreach/vignettes/foreach.pdf。我已经检查了随机生成的示例。重要性似乎确实有点不同,但在使用相同参数训练森林时它也会发生一些变化。我不认为这是一个错误,但你可以发布一个可重现的例子来证明我错了 是的,差异肯定只是由于算法的随机性,这取决于您的 NTREE 值是什么,以及数据的维度。您是否验证过这种情况始终如一地发生? 【参考方案1】:

randomForest::combine 不支持重新计算变量重要性。在 randomForest 包中,重要性仅在 randomForest::randomForest 函数终止之前计算。两个选项是:

编写您自己的变量重要性函数,它将组合的森林和训练集作为输入。这大约是 50 行代码。

使用类似“lapply”的并行计算,其中每个 randomForest 对象都是输出列表中的一个元素。接下来在所有森林中聚合变量重要性并简单地计算平均值。在 foreach 循环之外使用 do.call(rf.list,combine) 。这种方法是总变量重要性的近似值,但是相当不错。

Windows 支持的代码示例:

library(randomForest)
library(doParallel)
CPUS=6; NTREE=5000
cl = makeCluster(CPUS)
registerDoParallel(cl)
data(iris)
rf.list = foreach(ntree = rep(NTREE/CPUS,CPUS),
                  .combine=c,
                  .packages="randomForest") %dopar% 
                    list(randomForest(Species~.,data=iris,importance=TRUE, ntree=ntree))  
                  
stopCluster(cl)
big.rf = do.call(combine,rf.list)
big.rf$importance = rf.list[[1]]$importance
for(i in 2:CPUS) big.rf$importance = big.rf$importance + rf.list[[i]]$importance
big.rf$importance  = big.rf$importance / CPUS
varImpPlot(big.rf)

#test number of trees in one forest and combined forest, big.rf
print(big.rf)  #5000 trees
rf.list[[1]]$ntree 

#training single forest
rf.single = randomForest(Species~.,data=iris,ntree=5000,importance=T)
varImpPlot(big.rf)
varImpPlot(rf.single)
#print unscaled variable importance, no large deviations
print(big.rf$importance)

# setosa  versicolor  virginica MeanDecreaseAccuracy MeanDecreaseGini
# Sepal.Length 0.033184860 0.023506673 0.04043017           0.03241500         9.679552
# Sepal.Width  0.008247786 0.002135783 0.00817186           0.00613059         2.358298
# Petal.Length 0.335508637 0.304525644 0.29786704           0.30933142        43.160074
# Petal.Width  0.330610910 0.307016328 0.27129746           0.30023245        44.043737

print(rf.single$importance)

# setosa   versicolor  virginica MeanDecreaseAccuracy MeanDecreaseGini
# Sepal.Length 0.031771614 0.0236603417 0.03782824          0.031049531         9.516198
# Sepal.Width  0.008436457 0.0009236979 0.00880401          0.006048261         2.327478
# Petal.Length 0.341879367 0.3090482654 0.29766905          0.312507316        43.786481
# Petal.Width  0.322015885 0.3045458852 0.26885097          0.296227150        43.623370

#but when plotting using varImppLot, scale=TRUE by default
#either simply turn of scaling to get comparable results
varImpPlot(big.rf,scale=F)
varImpPlot(rf.single,scale=F)

#... or correct scaling to the number of trees
big.rf$importanceSD = CPUS^-.5 * big.rf$importanceSD 


#and now there are no large differences for scaled variable importance either
varImpPlot(big.rf,scale=T)
varImpPlot(rf.single,scale=T)

【讨论】:

感谢 Soren 的建议!我正在尝试实施“解决方案 2”,但我发现了一个问题。并行随机森林在一个函数内部,我无法使该函数获得适当数量的树:它每个核心执行 500 棵树(默认),而不是 rep(CPUS/NTREE,CPUS) 树... 哦忘了 ntree=ntree ok 代码已修复,当在并行foreach循环中调用randomForest时,您可以随意更改所有参数,甚至可以在循环外引用未导出的常量。玩得开心:) 好的!我更正了,它起作用了,但恐怕我没有得到与非平行随机森林的结果相同的结果。重要性不同,所以我得到的变量也不同。 这可能是因为您查看了缩放变量的重要性,而没有纠正重要性SD。我更改了代码以显示原始重要性非常相似。该代码还显示了如何纠正重要性SD

以上是关于为啥随机森林并行化后重要性会受到影响?的主要内容,如果未能解决你的问题,请参考以下文章

为啥打乱训练数据会影响我的随机森林分类器的准确性?

随机森林变量重要性排序时的影响为负值怎么办

随机森林(RF)的原理

特征筛选(随机森林)

随机森林

测量随机森林回归器中每个预测器特征重要性对目标值的影响(量化)(目标值的提升或下降)