【问题标题】:replace nested loop with expand.grid and call inner function with multiple arguments用 expand.grid 替换嵌套循环并用多个参数调用内部函数
【发布时间】:2016-07-01 07:22:13
【问题描述】:

我想将rollapply 函数与widthbyFUN 参数的各种组合一起使用(widthby 应该具有相同的值)。我启发了here 并创建了以下代码,这些代码正在运行,但到目前为止它与rollapply 无关,它只是演示了如何将几个参数传递给apply 内部的函数:

> dframe   <- expand.grid(c(1,2,3), c(1,2,3))
> testFunc <- function(a, b) a^2 + b
> apply(dframe, 1, function(x) testFunc(x[1], x[2]))
[1]  2  5 10  3  6 11  4  7 12
> apply(dframe, 1, function(x) x[1]^2 + x[2])
[1]  2  5 10  3  6 11  4  7 12
> apply(dframe, 1, function(x) (x[1]^2 + x[2]))
[1]  2  5 10  3  6 11  4  7 12
> apply(dframe, 1, function(x) {x[1]^2 + x[2]})
[1]  2  5 10  3  6 11  4  7 12

我的最终解决方案在这里,但这不起作用:

> dframe   <- expand.grid(c(1,2,3), c(median, mean))
> testFunc <- function(a, b) rollapply(mtcars, width = a, by = a, FUN = b, align="left")

> apply(dframe, 1, function(x) testFunc(x[1], x[2]))
 Error in get(as.character(FUN), mode = "function", envir = envir) : 
  object 'b' of mode 'function' was not found

> apply(dframe, 1, function(x) rollapply(mtcars, width = x[1], by = x[1], FUN = x[2], align="left"))
 Error in match.fun(FUN) : 'x[2]' is not a function, character or symbol 

当我直接调用testFunc 时,一切正常,所以我猜问题是apply 无法以某种方式收集结果:

> testFunc(10,mean)
       mpg cyl   disp    hp  drat     wt   qsec  vs  am gear carb
[1,] 20.37 5.8 208.61 122.8 3.538 3.1280 18.581 0.6 0.3  3.6  2.5
[2,] 19.89 6.6 259.25 149.6 3.552 3.6689 18.301 0.4 0.3  3.4  2.9
[3,] 20.39 6.2 228.25 152.6 3.654 2.8633 16.914 0.3 0.5  3.9  2.6

> class(testFunc(10,mean))
[1] "matrix"

我也试过调试testFunc 并从apply 调用它,似乎参数传递正确:

> debug(testFunc)
> apply(dframe, 1, function(x) testFunc(x[1], x[2]))
debugging in: testFunc(x[1], x[2])
debug: rollapply(mtcars, width = a, by = a, FUN = b, align = "left")

Browse[2]> print(a)
$Var1
[1] 1

Browse[2]> print(b)
$Var2
function (x, na.rm = FALSE) 
UseMethod("median")
<bytecode: 0x08244ffc>
<environment: namespace:stats>

Browse[2]> n
Error in get(as.character(FUN), mode = "function", envir = envir) : 
  object 'b' of mode 'function' was not found

问题:

  1. 什么是错误,我做错了什么?
  2. 如何用expand.grid 替换嵌套循环并调用内部 具有多个参数的函数?
  3. 如何使用*apply 系列函数返回矩阵列表?

PS:我想使用两个嵌套循环很容易实现这一点,但我想知道是否有 R-way。

PPS:Here 是关于类似错误(object 'b' of mode 'function' was not found)的答案,结论是b(在我的情况下)与命名参数与其他函数冲突。但我在我的代码中看不到这个问题。

【问题讨论】:

    标签: r


    【解决方案1】:

    假设df &lt;- data.frame(a = 1:2, b = 3:4) 和我们应用apply(df, 1, function(x) fun(x))。那么两个传递的参数xvectors c(1, 3)c(2, 4)

    但是,当 df &lt;- expand.grid(c(1,2,3), c(median, mean))apply(df, 1, function(x) fun(x)) 完成后,我们不能再将例如 1median 存储到单个向量中,因为它们的类型太不同了。那么x 恰好是一个列表,例如x &lt;- list(1, median)。然后,执行x[1]x[2] 不会如所愿提供1median;相反,这些是具有单个元素的列表(因此出现错误object 'b' of mode 'function' was not found)。这实际上可以在您的调试示例中看到。

    因此,在您的情况下,这里有一些使用 apply 的方法:

    1) 不修改testFunc,但承认apply传递了一个列表;在那种情况下do.call有帮助,但它也关心df的列名,所以我也使用unname

    apply(unname(df), 1, do.call, what = testFunc)
    

    2) 与 1) 相同,但没有 do.call:

    apply(dframe, 1, function(x) testFunc(x[[1]], x[[2]]))
    

    3) testFunc 重新定义为具有单个参数:

    testFunc <- function(a) rollapply(mtcars, width = a[[1]], by = a[[1]], FUN = a[[2]], align="left")
    apply(dframe, 1, testFunc)
    

    【讨论】:

    • 很好的答案,另一个选项可能是Vectorize(testFunc)(dframe[[1]],dframe[[2]])
    • 非常感谢。还有一个问题:是否有任何调试技术有助于解决这些问题?
    • @WakanTanka,我必须承认我一般不会使用很多调试工具(这可能不是一件好事),但在这种情况下,我会发现像 apply(dframe, 1, function(x) browser()) 这样的东西就足够了。您所做的同样好,您只需要认识到$Var1 代表列表元素的名称而不是向量元素的名称,并且rollapply 不接受列表。您可能会发现traceback 也提供了丰富的信息,因为它表明错误发生在get(as.character(FUN), mode = "function", envir = envir)
    猜你喜欢
    • 1970-01-01
    • 2018-09-30
    • 1970-01-01
    • 2016-07-08
    • 2012-11-06
    • 2021-01-29
    • 1970-01-01
    • 1970-01-01
    • 2018-08-06
    相关资源
    最近更新 更多