Ссылаясь на столбцы data.table именами, сохраненными в переменных
data.table
- фантастический пакет R, и я использую его в библиотеке, которую я разрабатываю. Пока все идет хорошо, за исключением одного осложнения. Кажется, что гораздо сложнее (по сравнению с обычными кадрами данных) ссылаться на столбцы data.table
, используя имена, сохраненные в переменных (как для фреймов данных, например: colname="col"; df[df[,colname]<5,colname]=0
).
Возможно, что усложняет большинство из них - очевидное отсутствие согласованности синтаксиса на этом в data.table
. В некоторых случаях eval(colname)
и get(colname)
, или даже c(colname)
, похоже, работают. В других случаях решение DT[,colname, with=F]
является решением. Однако в других, например, в функциях set()
и subset()
, я вообще не нашел решения. Наконец, был рассмотрен крайний, хотя и довольно распространенный случай использования (передача имен столбцов в программный файл data.table), и предлагаемые решения, хотя и явно выполняющие свою работу, не кажутся особенно читаемыми...
Возможно, я слишком много усложняю? Если бы кто-нибудь мог наброситься на быстрый чек-лист, ссылаясь на имена столбцов data.table
, используя переменные для разных распространенных сценариев, я был бы очень благодарен.
UPDATE:
Некоторые конкретные примеры, которые работают, могут содержать имена столбцов жесткого кода:
x.short = subset(x, abs(dist)<=100)
set(x, which(x$val<10), "val", 0)
Теперь предположим distcol="dist"
, valcol="val"
. Каков наилучший способ сделать это, используя distcol
и valcol
, но не dist
и val
?
Ответы
Ответ 1
Если вы собираетесь выполнять сложные операции внутри ваших выражений j
, вы, вероятно, должны использовать eval
и quote
. Одна из проблем с текущей версией data.table
заключается в том, что среда eval
не всегда корректно обрабатывается - eval и quote в data.table (Примечание: там был обновлением этого ответа на основе обновления пакета.) - и текущее исправление для этого - добавить .SD
в eval
. Насколько я могу судить по нескольким тестам, которые я запускал, это не влияет на скорость (например, имея .SD[1]
в j
).
Интересно, что этот вопрос вызывает только j
, и вы будете нормально использовать eval
обычно в i
(где .SD
пока недоступно).
Другая проблема - назначение, и там у вас должны быть строки. Я знаю один способ извлечь имя строки из цитируемого выражения - это не очень, но это работает. Вот пример, объединяющий все вместе:
x = data.table(dist = c(1:10), val = c(1:10))
distcol = quote(dist)
valcol = quote(val)
x[eval(valcol) < 5,
capture.output(str(distcol, give.head = F)) := eval(distcol)*sum(eval(distcol, .SD))]
Обратите внимание, как я был в порядке, не добавляя .SD
в один eval(distcol)
, но не будет, если я возьму его из другого eval
.
Другой вариант - использовать get
:
diststr = "dist"
valstr = "val"
x[get(valstr) < 5, c(diststr) := get(diststr)*sum(get(diststr))]
Ответ 2
Возможно, вы уже знаете об этом решении?
DT[[colname]]
Это вдохновлено решением @eddi в комментариях ниже, используя пример OP:
set.seed(1)
x = data.table(a = 1:10, b=rnorm(10))
colstr="b"
col <- eval(parse(text=paste("quote(",colstr,")",sep="")))
x[eval(col)<0]
x[eval(col)<0,c(colstr):=-100]
Ответ 3
Скажите, что у вас есть имя столбца в переменной x
, вы можете сделать
colname = as.name(x)
вы можете использовать colname
в функции subset
Ответ 4
eval
определенно не рекомендуется для подмножества data.table
с использованием динамически сохраняемых переменных. Следующий пример поможет:
# Toy data.table example
DT = data.table(a = c(1,2,3), b = c(4,5,6))
# Saved variable
mVar <- "a"
# Subset
DT[DT[[mVar]] < 2]
eval
очень чувствителен к сложным символьным выражениям и обычно не рекомендуется для производственного кода.