我试图回答 this nice question 关于为 data.table 对象创建非标准评估函数,进行分组求和。 Akrun 提出了一个可爱的答案,我将在这里简化:

akrun <- function(data, var, group){
 var <- substitute(var)
 group <- substitute(group)
 data[, sum(eval(var)), by = group]
}

library(data.table)
mt = as.data.table(mtcars)
akrun(mt, cyl, mpg)
#    group    V1
# 1:     6 138.2
# 2:     4 293.3
# 3:     8 211.4

我也在研究一个答案,并且接近相同的答案,但是 substitute s 与其余的内联。我的结果是一个错误:
gregor = function(data, var, group) {
  data[, sum(eval(substitute(var))), by = substitute(group)]
}

gregor(mt, mpg, cyl)
# Error in `[.data.table`(data, , sum(eval(substitute(var))), by = substitute(group)) :
#  'by' or 'keyby' must evaluate to vector or list of vectors
#  (where 'list' includes data.table and data.frame which are lists, too)

从表面上看,我的功能是对 Akrun 的简单替换。为什么不起作用?

请注意,这两种替换都会导致问题,如下所示:
gregor_1 = function(data, var, group) {
  var = substitute(var)
  data[,sum(eval(var)),
       by = substitute(group)]
}
gregor_1(mt, mpg, cyl)
# Same error as above


gregor_2 = function(data, var, group) {
  group = substitute(group)
  data[,sum(eval(substitute(var))),
       by = group]
}
gregor_2(mt, mpg, cyl)
# Error in eval(substitute(var)) : object 'mpg' not found

最佳答案

substitute 的文档中,您可以阅读它如何决定替换的内容,
事实上,默认情况下,它会搜索调用它的环境。
如果您在 substitute 框架内调用 data.table(即内部 [] )
它将无法找到符号,因为它们不存在于 data.table 评估环境中,
它们位于调用 [ 的环境中。

您可以“反转”调用函数的顺序以获得您想要的行为:

library(data.table)

foo <- function(dt, group, var) {
    eval(substitute(dt[, sum(var), by = group]))
}

foo(as.data.table(mtcars), cyl, mpg)
   cyl    V1
1:   6 138.2
2:   4 293.3
3:   8 211.4

关于r - 为什么 `substitute` 可以在多行中工作,而不能在单行中工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58649510/

10-12 19:43