【发布时间】:2019-10-31 18:42:49
【问题描述】:
我试图回答 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
我也在研究一个答案,并且得到了接近相同的答案,但 substitutes 与其他答案一致。我的结果是一个错误:
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
【问题讨论】:
-
我现在没有时间(或者可能没有能力)对此进行深入研究,但似乎在
data.table调用中,您传递给substitute的任何变量仍然是符号(例如,如果你将它包装在rleid或as.integer中,对于像我这样的菜鸟来说,警告会更清楚一些)。那是对的吗?那么,substitute在 data.table 调用中使用时不会查看函数环境吗?另外,我对 data.table 的所有事情都很熟悉,所以如果这已经很明显了,我很抱歉。 -
我认为这是一个很好的贡献。 Akrun 最初的建议也是关于环境的,我尝试了
substitute(var, env = parent.frame(environment()))之类的版本,也没有运气。但这似乎是正确的轨道。 -
嘿格雷戈尔! (来自 UW STTR 的迈克尔)。我最近一直在考虑为 data.table 过程编写函数,并且已经走上了创建函数的道路,这些函数将列名的字符向量作为参数而不是不带引号的符号。通常,使用 data.table 编写函数存在一些潜在问题,其中函数可能会通过创建临时列来利用底层 data.table 对象以避免复制整个表。潜在的列名冲突和更改输入表的键。我希望看到更多关于最佳做法的讨论。
标签: r data.table non-standard-evaluation