我遇到data.table
的小R问题。非常感谢您的帮助。我该怎么做:
getResult <- function(dt, expr, gby) {
e <- substitute(expr)
b <- substitute(gby)
return(dt[,eval(e),by=b])
}
v1 <- "Sepal.Length"
v2 <- "Species"
dt <- data.table(iris)
rDT <- getResult(dt, sum(v1, na.rm=TRUE), v2)
我收到以下错误:
总和错误(v1,na.rm = TRUE):无效的'type'(字符)of 参数
现在,v1
和v2
都从其他程序传递为字符变量,因此我无法执行此操作v1<- quote(Sepal.Length)
。
答案 0 :(得分:21)
在评论中替代flodel的答案可能是
e <- parse(text = paste0("sum(", v1, ", na.rm = TRUE)"))
b <- parse(text = v2)
rDT2 <- dt[, eval(e), by = eval(b)]
# b V1
# [1,] setosa 250.3
# [2,] versicolor 296.8
# [3,] virginica 329.4
修改强>
并将其置于一个函数中,
getResult <- function(dt, expr, gby){
return(dt[, eval(expr), by = eval(gby)])
}
(dtR <- getResult(dt = dt, expr = e, gby = b))
# gives the same result as above
来自Matthew的编辑:
在某些情况下,paste0
和eval
\ quote
方法可能比get
更快,这是一个微妙的原因。分组可能很快的一个原因是data.table
检查j
以查看它使用哪些列,然后仅对那些使用过的列进行子集(FAQ 1.12和3.1)。它使用base::all.vars(j)
来做到这一点。在get()
中使用j
时,正在使用的列对all.vars
隐藏,data.table
会回退到所有列的子集,以防j
表达式需要它们(非常类似于在.SD
中使用j
符号时,.SDcols
已添加到其中以解决问题。如果仍然使用了所有列,那么它没有什么区别,但如果DT
表示1e7x100,那么分组j=sum(V1)
应该比分组j=sum(get("V1"))
快得多。至少,那是应该发生的事情,如果没有,那么它可能是一个错误。另一方面,如果正在动态构建许多查询并重复,那么paste0
和parse
的时间可能会进入。一切都取决于。设置verbose=TRUE
应该打印出一条消息,说明j
使用了哪些列,以便进行检查。