R:如何为预先指定的复制数量使用foreach,例如在while循环中


library(foreach)
library(doMC)

myfun <- function(threshold){
val <- rnorm(1, mean = 0, sd = 1)
if(val > threshold){
stop("bad")
}else return(val)
}
results <- vector("list", length = 10)
parallel_fun <- function(reps, threshold){
registerDoMC(cores = 48)
results = foreach (j = 1:reps, .combine = rbind) %dopar% {
myfun(threshold)
}
}
> parallel_fun(reps = 10, threshold = 0)
Error in { : task 1 failed - "bad" 

以上是一个简单的、可重复的例子。我想并行化myfun以获得reps = 10的复制次数。当生成的val大于某个threshold时,myfun可能会停止。在这种情况下,我想停止运行myfun,而不是让它返回val。最后,我希望我的results有10个vals,大于一些threshold。因此,我认为在这里使用while循环可能更合适,因为我想让它一直运行,直到有10个值满足threshold。是否有可能重新使用foreach来并行化while循环?

控制流程

通常不鼓励对控制流使用异常。理想情况下,

使用你想要的函数

在这个特定的示例中,您正在模拟截断正态分布。因此,您可以使用截断规范包中的truncnorm函数。

重写函数或者,重写myfun以始终返回正确的值:

myfun = function(threshold){
repeat{
val = rnorm(1, 0, 1)
if(val <= threshold)
break
}
val 
}

这只是一种可能的变体。这里我使用自定义的do-while结构。

请注意,根据阈值的不同,可能会发生大量或可能无限次的迭代,因此要小心行事,要么设置最大迭代次数,要么在threshold没有超出所讨论的函数的最大范围时进行一些初步检查,最好是两者都进行。

有了这个,你应该能够像现在一样轻松地运行foreach

写一个包装器

如果您无法控制myfun,则需要构造包装器,该构造可能与上面的函数几乎相同:

wrap_myfun = function(threshold){
repeat{
val = try(myfun(threshold))
if(is.numeric(val))
break
}
val
}

跟踪迭代:

如果您需要跟踪生成上述数字所需的迭代次数,您可以将repeat重写为for循环,或者只是添加计数器和另一个选项:

wrap_myfun = function(threshold, .maxiter=10^9, .default=NA){
iter = 1
repeat{
val = try(myfun(threshold))
if(is.numeric(val))
break
if(iter >= .maxiter){
val = .default 
break
}
iter = iter + 1
}
list("value"=val, "iterations"=iter)
}

或者,代替分配默认值,您可以使用' stop('达到的最大迭代';)。那要看问题有多严重。

这样,您已经将所有逻辑移动到数据生成函数中,并且您不必管理在foreach中实现的队列。负载应该在内核之间平均分配(超过一些迭代的可能随机的长计算时间,但这是您无法影响的)。

相关内容

  • 没有找到相关文章

最新更新