В R data.table, как передать переменные параметры в выражение?

Я застрял с небольшой проблемой 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)

Я получаю следующую ошибку:

Ошибка в сумме (v1, na.rm = TRUE): недопустимый "тип" (символ) Аргумент

Теперь оба v1 и v2 передаются из другой программы как символьная переменная, поэтому я не могу сделать это v1<- quote(Sepal.Length), который, похоже, работает.

Ответы

Ответ 1

Альтернативой flolel-ответу в комментариях может быть

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

EDIT:

И чтобы поместить это в функцию,

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


ИЗМЕНИТЬ от Мэтью: Там тонкая причина, по которой методы 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, чтобы это можно было проверить.