用expand.grid替换嵌套循环并使用多个参数调用内部函数

时间:2016-03-15 17:37:16

标签: r

我想使用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替换嵌套循环并调用inner 函数有多个参数?
  3. 如何使用*apply系列函数返回矩阵列表?
  4. PS:我想使用两个嵌套循环很容易实现这一点,但我想知道是否有R-way。

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

1 个答案:

答案 0 :(得分:6)

假设df <- data.frame(a = 1:2, b = 3:4)我们申请apply(df, 1, function(x) fun(x))。然后两个传递的参数x向量 c(1, 3)c(2, 4)

但是,当df <- expand.grid(c(1,2,3), c(median, mean))apply(df, 1, function(x) fun(x))完成后,我们无法再将1median存储到单个向量中,因为它们的类型太不相同。然后x恰好是列表,例如x <- 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)