Подтвердить что ты не робот

Data.table.. обозначение с функциями в j

Я пытаюсь использовать data.table .. нотацию с функциями, вот код, который у меня есть до сих пор:

set.seed(42)
dt <- data.table(
  x = rnorm(10),
  y = runif(10)
)

test_func <- function(data, var, var2) {
  vars <- c(var, var2)
  data[, ..vars]
}

test_func(dt, 'x', 'y') # this works

test_func2 <- function(data, var, var2) {
  data[, ..var]
}

test_func2(dt, 'x', 'y') # this works too

test_func3 <- function(data, var, var2) {
  data[, sum(..var)]
}

test_func3(dt, 'x', 'y') 
# this does not work
# Error in eval(jsub, SDenv, parent.frame()) : object '..var' not found

Кажется, что data.table не распознает .. после того, как он завернут внутри другой функции в j. Я знаю, что могу использовать sum(get(var)) для достижения результатов, но я хочу знать, что использую наилучшую практику в большинстве ситуаций.

4b9b3361

Ответ 1

Parroting ответ на другую проблему, которая также работает здесь. Не самое прекрасное решение, но варианты по этому работали для меня много раз в прошлом.

Спасибо @Frank для решения без parse() здесь!

Я хорошо знаком со старой поговоркой "Если ответ - это синтаксический анализ(), вы должны, как правило, переосмыслить вопрос". Но мне сложно придумывать альтернативы много раз, оценивая в data.table вызывающая среда, мне бы хотелось увидеть надежное решение, которое не выполняет произвольный код, переданный в виде символьной строки. На самом деле половина причин, по которым я отправляю такой ответ, в надежде, что кто-то может порекомендовать лучший вариант.

test_func3 <- function(data, var, var2) {
  expr = substitute(sum(var), list(var=as.symbol(var)))
  data[, eval(expr)]
}

test_func3(dt, 'x', 'y')
## [1] 5.472968

Быстрая оговорка о гипотетических сценариях конца света возможна с помощью eval (parse (...))

Более подробно подробно обсуждается об опасностях eval(parse(...)), но я не буду повторять их полностью.

Теоретически у вас могут быть проблемы, если один из ваших столбцов назван чем-то неудачным, например "(system(paste0('kill ',Sys.getpid())))" (не выполняйте это, он будет убивать вашу сессию R на месте!). Вероятно, этого достаточно, чтобы не потерять сон, если вы не планируете положить это в пакет на CRAN.


Обновление:

Для конкретного случая в комментариях ниже, где таблица сгруппирована, а затем sum применяется ко всем, .SDcols потенциально полезна. Единственный способ, которым я знаю, чтобы эта функция возвращала согласованные результаты, даже если dt имел столбец с именем var3, должен оценивать аргументы внутри среды функций, но вне среды data.table, используя c().

set.seed(42)
dt <- data.table(
  x = rnorm(10),
  y = rnorm(10),
  z = sample(c("a","b","c"),size = 10, replace = TRUE)
)


test_func3 <- function(data, var, var2, var3) {
  ListOfColumns = c(var,var2)
  GroupColumn <- c(var3)
  dt[, lapply(.SD, sum), by= eval(GroupColumn), .SDcols = ListOfColumns]
}

test_func3(dt, 'x', 'y','z') 

возвращает

   z         x         y
1: b 1.0531555  2.121852
2: a 0.3631284 -1.388861
3: c 4.0566838 -2.367558