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

Eval и quote в data.table

Что мне здесь не хватает?

d = data.table(a = 1:5)

d[, a]                   # 1 2 3 4 5
d[, sum(a)]              # 15

d[, eval(quote(a))]      # 1 2 3 4 5
d[, sum(eval(quote(a)))] # 15

quoted_a = quote(a)
d[, eval(quoted_a)]      # 1 2 3 4 5
d[, sum(eval(quoted_a))] # Error in eval(expr, envir, enclos) : object 'a' not found

Что происходит? Я запускаю R 2.15.0 и data.table 1.8.9.

4b9b3361

Ответ 1

UPDATE (eddi): По сравнению с версия 1.8.11 это исправлено, а .SD - не требуется в случаях, когда выражение может быть оценено на месте, как в OP. Поскольку в настоящее время наличие .SD вызывает конструкцию полного .SD, это приведет к значительно более быстрым скоростям в некоторых случаях.


Что происходит, так это то, что вызовы eval() обрабатываются иначе, чем вы, вероятно, себе представляете в коде, который реализует [.data.table(). В частности, [.data.table() содержит специальные ветки оценки для выражений i и j, которые начинаются с символа eval. Когда вы завершаете вызов eval внутри вызова sum(), eval больше не является первым элементом анализируемого/замещенного выражения, а специальная ветвь оценки пропускается.

Вот бит кода в функции монстра, отображаемый при вводе getAnywhere("[.data.table"), который делает специальную учетную запись для вызовов eval(), переданных через [.data.table() j -argument:

jsub = substitute(j)
    ...
    # Skipping some lines
    ...
jsubl = as.list.default(jsub)
if (identical(jsubl[[1L]], quote(eval))) {  # The test for eval 'on the outside' 
    jsub = eval(jsubl[[2L]], parent.frame(), parent.frame())
    if (is.expression(jsub)) 
        jsub = jsub[[1L]]
}

Как обходной путь, либо следуйте примеру в data.table FAQ 1.6 (pdf здесь), или явно укажите eval() в сторону .SD, локальная переменная, которая содержит столбцы любой таблицы данных, на которой вы работаете (здесь d). (Для более подробного объяснения роли .SD см. Первые несколько абзацев этого ответа).

d[, sum(eval(quoted_a, envir=.SD))]