R中具有mapply的子集参数的非标准评估

汤玛士

我不能使用subset的参数xtabsaggregate(或I测试,包括任何功能ftablelm)用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.calleval.parent,但到目前为止都没有成功(更多信息请参见前面的问题)。
  • 为什么在中对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有效。

当然,如果您尝试在mapply通话之前创建以下列表

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调用:

mapply
#> function (FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE) 
#> {
#>     FUN <- match.fun(FUN)
#>     dots <- list(...)
#>     answer <- .Internal(mapply(FUN, dots, MoreArgs))
#> ...

如果您FUN自己调用了另一个调用eval其任何参数的函数,则它将尝试eval使用对象dots,该对象eval调用的环境中将不存在通过在包装mapply执行以下操作很容易看到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以获得更优雅的解决方案。

但是,它可能得到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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章