【问题标题】:Next with Revolution R's foreach package?接下来是 Revolution R 的 foreach 包?
【发布时间】:2011-12-04 04:21:30
【问题描述】:

我浏览了大部分文档并进行了大量的谷歌搜索,但找不到以下问题的答案:有没有办法同时引入“类似下一个”的功能foreach循环使用foreach 包?

具体来说,我想做类似的事情(这不适用于next,但没有):

foreach(i = 1:10, .combine = "c") %dopar% {
    n <- i + floor(runif(1, 0, 9))
    if (n %% 3) {next}
    n
}

我意识到我可以嵌套括号,但是如果我想在一个长循环中包含几个下一个条件,这很快就会成为语法噩梦。

这里是否有简单的解决方法(类似下一个功能或解决问题的不同方法)?

【问题讨论】:

    标签: r foreach parallel-processing next


    【解决方案1】:

    您可以将代码放入函数中并调用return。从您的示例中不清楚您希望它在n %% 3 时做什么,所以我将返回NA

    funi <- function(i) {
      n <- i + floor(runif(1, 0, 9))
      if (n %% 3) return(NA)
      n
    }
    foreach(i = 1:10, .combine = "c") %dopar% { funi(i) }
    

    【讨论】:

    • 完美——谢谢——没想到要使用return 和函数。是的,模数 3 是一个非常随意的例子,抱歉。
    • 这个例子很好,很容易展示你的情况。我的意思是next 的行为与return 不同; next 表示该循环实例根本不做任何事情,这在使用foreach 时是不可能的;每个实例都必须返回 something;因此,您需要确保处理您选择返回的任何内容。
    【解决方案2】:

    虽然看起来很奇怪,但您可以在 foreach 循环体中使用 return,而无需辅助函数(如 @Aaron 所示):

    r <- foreach(i = 1:10, .combine='c') %dopar% {
      n <- i + floor(runif(1, 0, 9))
      if (n %% 3) return(NULL)
      n
    }
    

    在此示例中返回 NULL,因为它已被 c 函数过滤掉,这可能很有用。

    此外,虽然它不适用于您的示例,但 when 函数有时可以代替 next,并且对于完全阻止计算发生很有用:

    r <- foreach(i=1:5, .combine='c') %:%
             foreach(j=1:5, .combine='c') %:%
                 when (i != j) %dopar% {
                     10 * i + j
                 }
    

    内部表达式只计算 20 次,而不是 25 次。这对于嵌套的 foreach 循环特别有用,因为 when 可以访问所有上游迭代器值。


    更新

    如果要在返回列表结果时过滤掉NULLs,则需要编写自己的组合函数。这是一个完整的示例,演示了一个与默认组合函数类似但包含过滤机制的组合函数:

    library(doSNOW)
    cl <- makeSOCKcluster(3)
    registerDoSNOW(cl)
    
    filteredlist <- function(a, ...) {
      values <- list(...)
      c(a, values[! sapply(values, is.null)])
    }
    
    r <- foreach(i=1:200, .combine='filteredlist', .init=list(),
                 .multicombine=TRUE) %dopar% {
      # filter out odd values of i
      if (i %% 2) return(NULL)
      i
    }
    

    请注意,当任务结果超过 100 个时,此代码可以正常工作(100 是 .maxcombine 选项的默认值)。

    【讨论】:

    • +1。这仅适用于.combine='c'。如果需要它作为默认列表输出,您必须在之后通过r[!sapply(r, is.null)] 发送remove the NULL list elements
    • @TMS 我添加了一个示例,当您想要在列表中返回结果时过滤掉 NULL。尽管您可以在之后执行此操作,但在 combine 函数中执行此操作会更有效,尤其是在使用 doSNOWdoMPI 后端即时完成时。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-17
    • 2015-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-25
    相关资源
    最近更新 更多