18

我遇到了一个小的 R 问题data.table。非常感谢您的帮助。我该怎么做呢:

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)

我收到以下错误:

sum(v1, na.rm = TRUE) 中的错误:参数的“类型”(字符)无效

现在,两者都v1作为v2字符变量从其他程序传递,所以我不能这样做v1<- quote(Sepal.Length),这似乎可行。

4

1 回答 1

22

弗洛德尔在评论中的答案的替代方案可能是

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 的编辑: 还有一个微妙的原因,为什么paste0and eval\quote方法也比get某些情况下更快。分组速度很快的原因之一是data.table检查j它使用了哪些列,然后只对那些使用的列进行子集化(FAQ 1.12 和 3.1)。它用来base::all.vars(j)做到这一点。在使用get()j列中使用时,会隐藏all.varsdata.table回退到对所有列进行子集化,以防j表达式需要它们(很像在 中.SD使用符号时j.SDcols添加用于求解)。如果无论如何都使用了所有列,那么它没有任何区别,但是如果DT说 1e7x100 那么分组j=sum(V1)j=sum(get("V1"))由于这个原因,应该比分组快得多。至少,这是应该发生的,如果没有,那么它可能是一个错误。另一方面,如果许多查询是动态构建并重复的,那么时间paste0可能parse会进入它。一切都取决于。设置verbose=TRUE应该打印出一条消息,说明哪些列已被 检测到j,以便可以检查。

于 2012-05-20T18:44:12.637 回答