随机森林引导训练和森林生成
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 <- foreach(ntree=rep(125, 8), .packages='randomForest') %dopar% randomForest(trainData[i,-1], trainData[i,]$class, ntree=ntree, sampsize=rep(2,2))
,然后通过crf <- 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 <- 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
的并行版本,mclapply
是lapply
的并行版本。在 R 中,*apply
实际上与 for loop
相同,当您逐字运行代码时会发生什么?我没有任何数据,所以我无法测试代码。
如果我这样运行它:rf <- 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 我已经完成了我的示例,因此您可以自己运行它。在这个过程中,我解决了一些问题。我错误地计算了结果列表的长度,因为我混淆了结果数和树的总数。 非常感谢史蒂夫。以上是关于随机森林引导训练和森林生成的主要内容,如果未能解决你的问题,请参考以下文章