R 中使用 mapply 对子集参数进行非标准评估

2024-01-24

我无法使用subset的论证xtabs or aggregate(或我测试过的任何功能,包括ftable and lm) with mapply。以下调用失败并显示subset争论,但它们的工作没有:

mapply(FUN = xtabs,
       formula = list(~ wool,
                      ~ wool + tension),
       subset = list(breaks < 15,
                     breaks < 20),
       MoreArgs = list(data = warpbreaks))

# Error in mapply(FUN = xtabs, formula = list(~wool, ~wool + tension), subset = list(breaks <  : 
#   object 'breaks' not found
# 
# expected result 1/2:
# wool
# A B 
# 2 2
# 
# expected result 2/2:
#     tension
# wool L M H
#    A 0 4 3
#    B 2 2 5

mapply(FUN = aggregate,
       formula = list(breaks ~ wool,
                      breaks ~ wool + tension),
       subset = list(breaks < 15,
                     breaks < 20),
       MoreArgs = list(data = warpbreaks,
                       FUN = length))

# Error in mapply(FUN = aggregate, formula = list(breaks ~ wool, breaks ~  : 
#   object 'breaks' not found
# 
# expected result 1/2:
#   wool breaks
# 1    A      2
# 2    B      2
# 
# expected result 2/2:
#   wool tension breaks
# 1    B       L      2
# 2    A       M      4
# 3    B       M      2
# 4    A       H      3
# 5    B       H      5

这些错误似乎是由于subset未在正确的环境中评估参数。我知道我可以在data与争论data = warpbreaks[warpbreaks$breaks < 20, ]作为一种解决方法,但我希望提高我对 R 的了解。

我的问题是:

  • 我该如何使用subset争论与mapply?我尝试过match.call and eval.parent,但到目前为止还没有成功(更多细节在我的之前的问题 https://stackoverflow.com/a/55828617/11148823).
  • 为什么是formula参数评估于data = warpbreaks, 但 这subset说法不是吗?

简而言之,当您创建一个列表作为参数传递给函数时,它会在创建时进行评估。您收到的错误是因为 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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

R 中使用 mapply 对子集参数进行非标准评估 的相关文章

随机推荐