将多个列出的数据帧循环到一个函数中

时间:2018-12-13 02:34:50

标签: r list lapply mclapply

我正在尝试从软件包ade4执行函数varipart()。我试图在相同功能的不同部分的每个列表中使用相同编号的数据框。我需要为每组数据框传递此参数。

########### DATA BELOW
    d1 <- data.frame(y1 = c(1, 2, 3), y2 = c(4, 5, 6))
      d2 <- data.frame(y1 = c(3, 2, 1), y2 = c(6, 5, 4))
      d3 <- data.frame(y1 = c(2, 1, 2), y2 = c(5, 6, 4))
      spec.list <- list(d1, d2, d3)

      d1 <- data.frame(y1 = c(20, 87, 39), y2 = c(46, 51, 8))
      d2 <- data.frame(y1 = c(30, 21, 12), y2 = c(61, 51, 33))
      d3 <- data.frame(y1 = c(2, 11, 14), y2 = c(52, 16, 1))
      env.list <- list(d1, d2, d3)

      d1 <- data.frame(y1 = c(0.15, 0.1, 0.9), y2 = c(0.46, 0.51, 0.82))
      d2 <- data.frame(y1 = c(0.13, 0.31, 0.9), y2 = c(0.11, 0.51, 0.38))
      d3 <- data.frame(y1 = c(0.52, 0.11, 0.14), y2 = c(0.52, 0.36, 0.11))
      spat.list <- list(d1, d2, d3)
###############
      # I have tried two ways 
      library(parallel)
      library(ade4)

        output_varpart <- mclapply(spec.list, function(x){
          varipart(x, env.list, spat.list, type = "parametric")
        })

        output_varpart <- mclapply(x, function(x){
          varipart(spec.list[[x]], env.list[[x]], spat.list[[x]], type = "parametric")
        })

        for(i in 1:length(x)){
          results <- varipart(spec.list, env.list, spat.list, type = "parametric")
        }

这些方法都不起作用!请保持温柔,我是列出语法和循环的新手。错误为“警告消息: 在mclapply(output.spectrans.dudi,function(x){:   所有计划的内核都分别在用户代码中遇到错误”和“ x * w中的错误:二进制运算符的非数字参数”。

1 个答案:

答案 0 :(得分:1)

您很亲密,但是我会解释一下lapply(和mclapply)的工作原理,因为感觉就像您混淆了x的作用一样。首先,这应该起作用:

output_varpart <- mclapply(1:3, function(x){
      varipart(spec.list[[x]], env.list[[x]], spat.list[[x]], type = "parametric")
    })

但是为什么?
函数lapply的含义是:将函数(第二个参数)应用于列表中的所有值(第一个参数)。所以lapply(list('Hello', 'World', '!'), print)会做

print('Hello')
print('World')
print('!')

,它将返回一个长度为3的列表以及结果(返回的print是已打印的值)

但是经常没有一种功能可以完全满足您的需求。您始终可以定义一个函数,如下所示:

my_vari_fun <- function(index) {
  varipart(spec.list[[index]], env.list[[index]], spat.list[[index]], type = "parametric")
}

然后您可以像my_vari_fun(1)那样调用它,并且该参数名为xindex还是其他名称都没有关系。我确定你明白了。所以下一步就是

output_varpart <- lapply(list(1,2,3), my_vari_part)

这样做的缺点是它需要多行代码,因此我们可能不会再使用my_vari_fun。因此,这就是我们可以提供 anonymous 函数的原因,我们只是给了lapply一个函数而不将其分配给名称。我们只需将my_vari_fun替换为它的“值”(恰好是一个函数)。

但是,在此功能之外,x毫无意义。我们也可以用其他名称来称呼它。

我们只需要告诉lapply输入哪些值即可:list(1,2,3)。或者更简单地作为向量,lapply将转换为:1:3

顺便说一句,我刚刚在这里插入了3,但是对于一般情况下,您可以使用1:length(spec.list),只需确保所有列表的长度相同。

最后,我现在谈论了lapply,但是对于mclapply来说,它们都是一样的。区别只是在幕后,mclapply会将其工作分散到多个核心。

编辑:调试

在调试中,lapplymclapply之间存在更多差异。我将首先讨论lapply

如果在lapply内部执行的代码中存在某些错误,则整个lapply将失败,并且不会分配任何内容。有时很难准确地确定错误发生的位置,但是可以做到。一个简单的解决方法可能是仅将部分输入提供给lapply,以查看中断的地方。
但是R还附带了一些调试工具,一旦遇到错误,该工具就会冻结执行。我发现recover是最有用的工具。

您可以通过options(error=recover)进行设置,每次遇到错误时,它都会向后列出引发错误的函数,调用该函数的方式,调用该功能的功能, ...
然后,您可以选择一个数字来探索该功能所在的环境。当我尝试模拟您的错误时,我得到了:

Error in x * w : non-numeric argument to binary operator

Enter a frame number, or 0 to exit   

 1: source("~/.active-rstudio-document")
 2: withVisible(eval(ei, envir))
 3: eval(ei, envir)
 4: eval(ei, envir)
 5: .active-rstudio-document#20: lapply(1:3, function(x) {
    varipart(spec.list[[x]], env.list[[x]], spat.list[
 6: FUN(X[[i]], ...)
 7: .active-rstudio-document#21: varipart(spec.list[[x]], env.list[[x]], spat.list[[x]], type = "parametric")
 8: as.matrix(scalewt(Y, scale = scale))
 9: scalewt(Y, scale = scale)
10: apply(df, 2, weighted.mean, w = wt)
11: FUN(newX[, i], ...)
12: weighted.mean.default(newX[, i], ...)

其中很多是R的内部函数,您可以看到varipart的作用:它将东西传递给较低的函数,由谁传递,等等。

出于我们的目的,我们需要数字6:在这里lapply调用您的函数,输入值为i-th
一旦输入6,我们将得到一个新提示,显示为Browse[1]>(在某些情况下,它可能是另一个数字),并且我们处在环境中,就像我们刚刚输入

function(x){
  varipart(spec.list[[x]], env.list[[x]], spat.list[[x]], type = "parametric")
}

这意味着键入x将为您提供此函数失败的值,而spec.list[[x]]等将告诉您varipart哪些输入失败。然后,最后一步是确定这意味着什么:varipart被破坏,或者您的输入之一被破坏。

在这种情况下,我注意到我可以通过在data.frame中的某列中再加上numeric来获得相同的错误。但是,您还必须查看是否也是您的问题,但是如果您弄清楚了问题出在哪里,调试就会变得容易得多。

使用mclapply

mclapply在多个内核上运行,这意味着,如果一个内核中有错误,则其他内核仍将完成其工作。

对于派生过程遇到错误的计算,该错误将以try-error对象的形式作为返回值。 但是请注意,相同内核的其他迭代也是如此。因此,如果对于mclapply(1:10, fun)fun(1)将引发错误,在2个内核的情况下,所有奇数输入都将显示该错误。

因此,我们可以查看返回值,以缩小搜索范围:

sapply(output_varpart, class)

错误在于输出类为try-error的迭代中,但我们无法确切知道哪个。

如何实际解决它取决于计算的大小。
如果它们真的很广泛,那么保留成功的价值并通过仅重新运行出现故障的部分来缩小范围可能是值得的。 或者,如果我只看到一个try-error,我们就不需要再看了。
但是通常,我发现将mclapply更改为常规lapply并使用上述方法最为有用。