2015-12-23 4 views
1

Как использовать имена столбцов переменных в RHS: = операций? Например, учитывая эту data.table «dt», я хотел бы создать два новых столбца: «first_y» и «first_z», которые содержат первое наблюдение за данным столбцом для значений «x».R - Data.table - Использование имен переменных столбцов в операциях RHS

dt <- data.table(x = c("one","one","two","two","three"), 
       y = c("a", "b", "c", "d", "e"), 
       z = c(1, 2, 3, 4, 5)) 

dt 
     x y z 
1: one a 1 
2: one b 2 
3: two c 3 
4: two d 4 
5: three e 5 

Вот как вы могли бы это сделать без имен переменных столбцов.

dt[, c("first_y", "first_z") := .(first(y), first(z)), by = x] 

dt 
     x y z first_y first_z 
1: one a 1  a  1 
2: one b 2  a  1 
3: two c 3  c  3 
4: two d 4  c  3 
5: three e 5  e  5 

Но как бы это сделать, если имена столбцов «y» и «z» динамически сохраняются в переменной?

cols <- c("y", "z") 

# This doesn't work 
dt[, (paste0("first_", cols)) := .(first(cols)), by = x] 

# Nor does this 
q <- quote(first(as.name(cols[1]))) 
p <- quote(first(as.name(cols[2]))) 
dt[, (paste0("first_", cols)) := .(eval(q), eval(p)), by = x] 

Я пробовал множество других комбинаций quote() и eval() и as.name() без успеха. LHS операции работает по назначению и документируется во многих местах, но я не могу найти ничего об использовании имени переменной столбца в RHS. Заранее спасибо.

+0

Это может быть но в соответствии с этим faq: https://cran.r-project.org/web/packages/data.table/vignettes/datatable-faq.pdf, это не рекомендуется: dt [, (paste0 ("first_", cols)): = first (.SD [[cols]]), by = x] – user2507320

+0

Как интересно, этот sort've работает: 'dt [, (paste0 («first_», cols)): = lapply (lapply (lapply (cols, as.name), eval), сначала), by = x] 'но оценивается в контексте верхнего уровня env – Shape

+0

Я получаю' Ошибка: object 'first' not found', можете ли вы обновить свой вопрос, чтобы сделать его воспроизводимым? – jangorecki

ответ

5

Я не знаком с функцией first (хотя это похоже на то, что определит Хэдли).

dt[, paste0("first_", cols) := lapply(.SD, head, n = 1L), 
    by = x, .SDcols = cols] 
#  x y z first_y first_z 
#1: one a 1  a  1 
#2: one b 2  a  1 
#3: two c 3  c  3 
#4: two d 4  c  3 
#5: three e 5  e  5 
+0

Я всегда думал, что 'lapply (.SD, function (x) x [1L])' выглядит более естественным (и на самом деле это то, что делает 'head'), но в основном это вопрос вкуса – MichaelChirico

+5

' .SD [1 ] 'достаточно? Он также внутренне оптимизирован (поэтому * намного быстрее). – Arun

4

.SDcols ответ отлично подходит для этого случая, но вы также можете просто использовать get:

dt[, paste0("first_", cols) := lapply(cols, function(x) get(x)[1]), by = x] 
dt 
#  x y z first_y first_z 
#1: one a 1  a  1 
#2: one b 2  a  1 
#3: two c 3  c  3 
#4: two d 4  c  3 
#5: three e 5  e  5 

Другой альтернативой является Векторизованной версией - mget:

dt[, paste0("first_", cols) := setDT(mget(cols))[1], by = x] 
Смежные вопросы