2017-01-26 3 views
2

Я хочу создать новые столбцы, используя оператор присваивания в data.table, поскольку существующие столбцы делятся на определенное количество. Код, который я пытаюсь, выдает двоичную ошибку оператора из-за характера выражения.Выполнение арифметики с присвоением именованного вектора в data.table

Вот что я пытаюсь сделать:

DT <- data.table(x1=1:4,x2=5:8,x3=9:12) 
DT[, c("y1","y2") := mget(c("x1","x2"))] # works as expected 
DT[, c("y3","y4") := mget(c("x1","x2"))/2] # Error in mget(c("x1", "x2"))/2 : non-numeric argument to binary operator 

Имена столбцов передаются через переменные, следовательно, вектор символов. Есть ли альтернативный способ сделать это?

ответ

1

Используя mget, мы возвращаем вывод list, а значения в list могут быть доступны с помощью lapply. Таким образом, мы используем lapply в петлю над list, а затем назначить (:=) его новые столбцы «У3» и «y4»

DT[, c("y3","y4") := lapply(mget(c("x1","x2")), `/`, 2)] 

Однако синтаксис data.table будет указывать столбцы в .SDcols

DT[, c("y3","y4") := lapply(.SD, `/`, 2), .SDcols = x1:x2] 
DT 
# x1 x2 x3 y3 y4 
#1: 1 5 9 0.5 2.5 
#2: 2 6 10 1.0 3.0 
#3: 3 7 11 1.5 3.5 
#4: 4 8 12 2.0 4.0 

Это может быть сделано более ясным с созданием некоторых векторов и поместить его в list с mget

z1 <- 1:4 
z2 <- 5:8 
mget(paste0("z", 1:2)) 
#$z1 
#[1] 1 2 3 4 

#$z2 
#[1] 5 6 7 8 

mget(paste0("z", 1:2)) /2 
#Error in mget(paste0("z", 1:2))/2 : 
# non-numeric argument to binary operator 

при использовании lapply/sapply, мы перебрать list элементов, а затем разделить на 2

lapply(mget(paste0("z", 1:2)), `/`, 2) 
#$z1 
#[1] 0.5 1.0 1.5 2.0 

#$z2 
#[1] 2.5 3.0 3.5 4.0 
+0

спасибо за подробное объяснение! Я не думал об этом прокручивать, поскольку я не понял источник ошибки. Первый метод, использующий 'mget', работал для меня. Со вторым подходом вы могли бы изменить свой ответ, чтобы сделать его «eval (c (« x1 »,« x2 »)', если он идиоматичен? Я упростил имена переменных в моем вопросе, они фактически не в последовательности. – Naumz

+1

@Naumz Нет 'eval' не возвращает значение столбцов. Вам нужно либо' mget', либо 'get' (для одного столбца). Если он не находится в последовательности, вы все равно можете использовать '.SDcols = c (" x1 "," x2 ")' или '.SDcols = c (1, 2)' ie индекс столбца – akrun

+2

Я бы не рекомендовал его, но 'DT [, setDT (mget (paste0 («x», 1: 2)))/2] 'также, по-видимому, работает. Или' DT [, .SD/2, .SDcols = x1: x2] ' – Frank