随机森林引导训练和森林生成

Posted

技术标签:

【中文标题】随机森林引导训练和森林生成【英文标题】:Random forest bootstrap training and forest generation 【发布时间】:2017-01-22 11:17:39 【问题描述】:

我有大量随机森林的训练数据(暗淡:47600811*9)。我想获取多个(假设 1000)维度为 10000*9 的自举样本(每次运行中获取 9000 个负类和 1000 个正类数据点)并迭代地为所有这些树生成树,然后将所有这些树组合成 1 个森林。 下面给出了所需代码的粗略概念。有人可以指导我如何从我的实际 trainData 生成随机样本并以最佳方式迭代地为它们生成树吗?这将是很大的帮助。谢谢

library(doSNOW)
library(randomForest)
cl <- makeCluster(8)
registerDoSNOW(cl)

for (i=1:1000)
B <- 1000 
U <- 9000 
dataB <- trainData[sample(which(trainData$class == "B"), B,replace=TRUE),] 
dataU <- trainData[sample(which(trainData$class == "U"), U,replace=TRUE),] 
subset <- rbind(dataB, dataU)

我不确定这是否是从实际 trainData 一次又一次(1000 次)生成子集的最佳方式。

rf <- foreach(ntree=rep(125, 8), .packages='randomForest') %dopar% 
  randomForest(subset[,-1], subset$class, ntree=ntree)


crf <- do.call('combine', rf)
print(crf)
stopCluster(cl)

【问题讨论】:

您是否尝试将 randomForest sampsize 参数设置为较小的值?将 sampsize 设置得更小,将 ntree 设置得更高可能与您正在做的类似。 @steve-weston 我正在尝试通过i = replicate(3, c(sample(which(trainData$class == "B"), 50, replace = T), sample(which(trainData$class == "U"), 50, replace = T))) 创建实际数据的子集,然后应用 foreach rf &lt;- foreach(ntree=rep(125, 8), .packages='randomForest') %dopar% randomForest(trainData[i,-1], trainData[i,]$class, ntree=ntree, sampsize=rep(2,2)),然后通过crf &lt;- do.call('combine', rf) 组合树。然后我只得到 1000 棵树,而我的 i 包含 3 个子集,对于每个子集我生成 1000 棵树,那么我应该得到 3000 棵树。如何纠正? 你的程序有一个错误,我在我的回答中描述并修复了这个错误。 【参考方案1】:

这样的事情会起作用

# Replicate expression 1000 times, store output of each replication in a list
# Find indices of class B and sample 9000 times with replacement
# Do the same 1000 times for class U. Combine the two vectors of indices

i = replicate(1000, c(sample(which(trainData$class == "B"), 9000, replace = T), sample(which(trainData$class == "U"), 1000, replace = T)))

然后将 i 输入到 lapply 的并行版本中

mclapply(i, function(i, ntree) randomForest(trainData[i,-1], trainData[i,]$class, ntree=ntree)

【讨论】:

你能指导我如何在上面提到的foreach 命令中使用这个并行版本的 lapply 来计算每个i(来自 trainData 的子集)的树,以便稍后我可以结合所有树变成森林。实际上,我需要将此i 传递给上述示例randomForest(subset[,-1], subset$class, ntree=ntree) 中的这行代码,第一个参数将是所有子集数据帧而不是第一列class,第二个参数将是class 列该子集数据帧。 我认为您在这里建议的是将%dopar% 之后的行替换为 randomForest(subset[,-1], subset$class, ntree=ntree) mclapply(i, function(i, ntree) randomForest(trainData[i,-1], trainData[i,]$class, ntree=ntree)。我说的对吗? 我已经尝试过这种方式 rf &lt;- foreach(ntree=rep(4,8), .packages="randomForest") %dopar% mclapply(i, function(i, ntree) randomForest(trainData[i,-1], trainData[i,]$class, ntree=ntree)) 但它给出了错误:task 1 failed - "could not find function "mclapply"" 尽管对函数 mclapply 的简单测试有效:simplify2array(mclapply(rep(4, 5), rnorm, mc.preschedule = FALSE, mc.set.seed = FALSE)) @Newbie 不,你不能将%dopar% 与`mclapply. dopar` 一起使用,这是for loop 的并行版本,mclapplylapply 的并行版本。在 R 中,*apply 实际上与 for loop 相同,当您逐字运行代码时会发生什么?我没有任何数据,所以我无法测试代码。 如果我这样运行它:rf &lt;- mclapply(i, function(i, ntree) randomForest(trainData[i,-1], trainData[i,]$HepG2, ntree=rep(4,8))) 然后我得到这个错误:Warning message: In mclapply(i, function(i, ntree) randomForest(trainData[i, -1], : all scheduled cores encountered errors in user code。如果你能建议我如何在问题中给出的原始代码中使用这个 mclapply 块会更好。【参考方案2】:

尽管您的示例并行化了内部循环而不是外部循环,但只要内部 foreach 循环的执行时间超过几秒钟,它就可以很好地工作,几乎可以肯定的是。但是,您的程序确实有一个错误:它丢弃了前 999 个 foreach 结果,只处理最后一个结果。为了解决这个问题,您可以预先分配一个长度为 1000*8 的列表,并在外部 for 循环的每次迭代中将 foreach 的结果分配给它。例如:

library(doSNOW)
library(randomForest)
trainData <- data.frame(a=rnorm(20), b=rnorm(20),
                        class=c(rep("U", 10), rep("B", 10)))
n <- 1000         # outer loop count
chunksize <- 125  # value of ntree used in inner loop
nw <- 8           # number of cluster workers
cl <- makeCluster(nw)
registerDoSNOW(cl)
rf <- vector('list', n * nw)
for (i in 1:n) 
  B <- 1000
  U <- 9000
  dataB <- trainData[sample(which(trainData$class == "B"), B,replace=TRUE),]
  dataU <- trainData[sample(which(trainData$class == "U"), U,replace=TRUE),]
  subset <- rbind(dataB, dataU)
  ix <- seq((i-1) * nw + 1, i * nw)
  rf[ix] <- foreach(ntree=rep(chunksize, nw),
                    .packages='randomForest') %dopar% 
    randomForest(subset[,-1], subset$class, ntree=ntree)
  

cat(sprintf("# models: %d; expected # models: %d\n", length(rf), n * nw))
cat(sprintf("expected total # trees: %d\n", n * nw * chunksize))
crf <- do.call('combine', rf)
print(crf)

这应该可以解决您在指向我的评论中提到的问题。

【讨论】:

感谢您的详细解答。我正在对我的真实数据进行尝试,让我们看看它是否有效。非常感谢。 我生成了一个 100*100 的列表,然后为 i = 1:100 创建了一个循环,然后我在每个 foreach 中生成 (125*8) 树。我想我应该得到 125*8*100 = 100000 棵树,但实际上我得到了 1250000。你能指导我为什么会这样吗?谢谢。 @Newbie 我已经完成了我的示例,因此您可以自己运行它。在这个过程中,我解决了一些问题。我错误地计算了结果列表的长度,因为我混淆了结果数和树的总数。 非常感谢史蒂夫。

以上是关于随机森林引导训练和森林生成的主要内容,如果未能解决你的问题,请参考以下文章

随机森林

r语言随机森林结果规则怎么显示

随机森林

随机森林

随机森林训练占比为多少比较合适

spark 随机森林算法案例实战