Прокручивать столбцы в data.table и преобразовывать эти столбцы - PullRequest
28 голосов
/ 04 декабря 2011

У меня есть data.table DT со столбцом с именем RF и множеством столбцов с подчеркиванием _.Я хочу перебрать все эти столбцы с подчеркиванием и вычесть из него столбец RF.Тем не менее, я застрял.Кажется, что все, что касается RHS оператора := в data.table, не работает с динамическими переменными.

Вот мой DT и требуемый вывод (в жестком коде):

library(data.table)
DT <- data.table(RF  = 1:10,
                 S_1 = 11:20,
                 S_2 = 21:30)
#Desired output
DT[ , S_1 := S_1 - RF]
DT[ , S_2 := S_2 - RF]
DT
      RF S_1 S_2
 [1,]  1  10  20
 [2,]  2  10  20
 [3,]  3  10  20
...

Тем не менее, я хочу, чтобы это было более гибким, т. Е. Перебирал все столбцы с «_» в имени и вычитал RF:

#1. try: Does not work; Interestingly, the i on the LHS of := is interpreted as the column i, but on the RHS of
#:= it is interpreted as 2 and 3, respectively
for (i in grep("_", names(DT))){
  DT[ , i:= i - 1, with=FALSE]
}
DT
          RF  S_1 S_2
 [1,]  1   1   2
 [2,]  2   1   2
 [3,]  3   1   2
...

#2. try: Work with parse and eval
for (i in grep("_", names(DT), value=TRUE)){
  DT[ , eval(parse(text=i)):= eval(parse(text=i)) - RF]
}
#Error in eval(expr, envir, enclos) : object 'S_1' not found

Любые советы, как это было бы здорово.

РЕДАКТИРОВАТЬ: Как только я опубликовал вопрос, я подумал про себя: почему вы вообще работаете с оператором :=, и, конечно же, я просто понял, что мне не нужно,Это работает и не нуждается в цикле:

DT[, grep("_", names(DT)), with=FALSE] - DT[, RF]

Извините за это.Однако я оставляю вопрос открытым, потому что мне все еще интересно, почему мой подход с оператором := не работает.Так что, может быть, кто-то может помочь мне там.

Ответы [ 3 ]

14 голосов
/ 05 декабря 2011

Вы были на правильном пути со второй попытки. Вот подход, использующий substitute для построения выражения, которое передается как аргумент 'j' в DT[ , j ].

for (i in grep("_", names(DT), value=TRUE)){
    e <- substitute(X := X - RF, list(X = as.symbol(i)))
    DT[ , eval(e)]
}
DT
#     RF S_1 S_2
# [1,]  1  10  20
# [2,]  2  10  20
# [3,]  3  10  20
# [4,]  4  10  20
# [5,]  5  10  20

Или сейчас (1 год спустя), что with=FALSE применяется к LHS := ok:

for (i in grep("_", names(DT), value=TRUE))
    DT[, i:=get(i)-RF, with=FALSE]

или with=FALSE можно избежать, если сделать LHS выражением, а не символом:

for (i in grep("_", names(DT), value=TRUE))
    DT[, (i):=get(i)-RF]
4 голосов
/ 11 декабря 2012

Спасибо за вопрос и за ответы. Я использовал решение с помощью временной переменной для подобных задач.

varnames <- grep("_", names(DT), value=TRUE)
for (i in varnames) {
  DT[, ".tmp"] <- DT[, i, with = F]
  DT[, i := .tmp - RF, with = F]
  if (i == tail(varnames, 1)) DT[, ".tmp"] <- NULL
}

Единственный риск - перезаписать существующую переменную .tmp.

Отлично. set() является мощным.

varnames <- grep("_", names(DT), value=TRUE)
set(DT, j = varnames, value = DT[, varnames, with = F] - DT[, RF])
4 голосов
/ 04 декабря 2011

Обходной путь, который я, к сожалению, обнаружил после публикации вопроса, выглядит следующим образом:

DT[, grep("_", names(DT)), with=FALSE] - DT[, RF]

Это также работает в более сложной настройке, в которой есть дополнительные столбцы, которые вы хотите сохранить, но с некоторыми дополнительнымиусилие:

library(data.table)
DT <- data.table(RF  = 1:10,
                 S_1 = 11:20,
                 S_2 = 21:30,
                 addCol = rnorm(10)) #Column that should not be subtracted by RF, but still kept in DT

DT <- cbind(DT[, grep("_", names(DT)), with=FALSE] - DT[, RF], addCol = DT[, addCol])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...