简而言之,当您创建一个列表作为参数传递给函数时,它会在创建时进行评估。您收到的错误是因为 R 尝试创建您想要在调用环境中传递的列表。
为了更清楚地看到这一点,假设您尝试在调用之前创建要传递的参数mapply
:
f_list <- list(~ wool, ~ wool + tension)
d_list <- list(data = warpbreaks)
mapply(FUN = xtabs, formula = f_list, MoreArgs = d_list)
#> [[1]]
#> wool
#> A B
#> 27 27
#>
#> [[2]]
#> tension
#> wool L M H
#> A 9 9 9
#> B 9 9 9
创建公式列表没有问题,因为这些公式在需要时才会被评估,当然warpbreaks
可以从全局环境访问,因此调用mapply
works.
当然,如果您尝试在之前创建以下列表mapply
call:
subset_list <- list(breaks < 15, breaks < 20)
然后R会告诉你breaks
没有找到。
但是,如果您使用以下命令创建列表warpbreaks
在搜索路径中,那么你就不会有问题:
subset_list <- with(warpbreaks, list(breaks < 15, breaks < 20))
subset_list
#> [[1]]
#> [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
#> [14] TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
#> [27] FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
#> [40] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE
#> [53] FALSE FALSE
#>
#> [[2]]
#> [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE
#> [14] TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE FALSE FALSE TRUE
#> [27] FALSE FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE
#> [40] TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE
#> [53] TRUE FALSE
所以你会认为我们可以把它传递给mapply
一切都会好起来的,但现在我们收到一个新错误:
mapply(FUN = xtabs, formula = f_list, subset = subset_list, MoreArgs = d_list)
#> Error in eval(substitute(subset), data, env) : object 'dots' not found
那我们为什么会得到这个呢?
问题在于传递给的任何函数mapply
那个电话eval
,或者它们本身调用一个使用的函数eval
.
如果你查看源代码mapply
你会看到它需要你传递的额外参数并将它们放入一个名为的列表中dots
,然后它将传递给内部mapply
call:
mapply
#> function (FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE)
#> {
#> FUN <- match.fun(FUN)
#> dots <- list(...)
#> answer <- .Internal(mapply(FUN, dots, MoreArgs))
#> ...
If your FUN
它本身调用另一个函数,该函数调用eval
因此,对于其任何论点,它将尝试eval
物体dots
,它不会存在于其中的环境中eval
叫做。通过执行以下操作很容易看到这一点mapply
on a match.call
包装:
mapply(function(x) match.call(), x = list(1))
[[1]]
(function(x) match.call())(x = dots[[1L]][[1L]])
所以我们的错误的最小可重现示例是
mapply(function(x) eval(substitute(x)), x = list(1))
#> Error in eval(substitute(x)) : object 'dots' not found
那么解决办法是什么呢?看来您已经找到了一个非常好的方法,即手动对您希望传递的数据帧进行子集化。其他人可能会建议您探索purrr::map
以获得更优雅的解决方案。
然而,它is可能得到mapply
做你想做的事,秘诀就是修改FUN
将其变成匿名包装xtabs
动态子集:
mapply(FUN = function(formula, subset, data) xtabs(formula, data[subset,]),
formula = list(~ wool, ~ wool + tension),
subset = with(warpbreaks, list(breaks < 15, breaks < 20)),
MoreArgs = list(data = warpbreaks))
#> [[1]]
#> wool
#> A B
#> 2 2
#>
#> [[2]]
#> tension
#> wool L M H
#> A 0 4 3
#> B 2 2 5