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

Looping multiple listed data frames into a single function

我正在尝试从 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")
        }

None 这些方法行得通!请温柔点,我是列表语法和循环的新手。错误是“警告信息: 在 mclapply(output.spectrans.dudi, function(x) { : 所有计划的核心分别在用户代码中遇到错误”和 "Error in x * w : non-numeric argument to binary operator"。

你很接近,但我会稍微解释一下 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('!')

它会 return 一个长度为 3 的列表和结果(print 的 return 是打印的值)

但很多时候,没有一种功能可以完全满足您的需求。你总是可以定义一个函数,像这样:

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 替换为 "value"(恰好是一个函数)。

然而,在这个函数之外,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]>(在某些情况下它可能是另一个数字),我们在环境中就好像我们刚刚输入了 [=63] =]

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 在多个核心上运行,这意味着如果一个核心出现错误,其他核心仍会完成其工作。

对于分叉进程遇到错误的计算,该错误将是 return 值,以 try-error 对象的形式。 但请注意,同一核心的其他迭代也会出现这种情况。因此,如果对于 mclapply(1:10, fun)fun(1) 将抛出错误,在 2 核的情况下,所有奇数输入都会显示该错误。

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

sapply(output_varpart, class)

迭代中的错误 is/are 输出 -class 是尝试错误,但我们无法确切知道是哪一个。

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