Вопрос
У меня есть данные. 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]
Простите за это. Тем не менее, я оставляю вопрос открытым, потому что мне все еще интересно, почему мой подход к :=
Оператор не работает. Так что, может быть, кто -то может мне там помочь.
Решение
Вы были на правильном пути со своей второй попыткой. Вот подход, который использует 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
Вы также можете использовать выражение LHS, а не символ:
for (i in grep("_", names(DT), value=TRUE))
DT[, (i) := get(i)-RF]
Другие советы
Обходной путь, который я, к сожалению, обнаружил после того, как я опубликовал вопрос:
DT[, .SD, .SDcols = patterns('_')] - 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[, .SD, .SDcols = patterns("_")] - DT[, RF], addCol = DT[, addCol])
Обновлено для использования set()
+..
; set
мощный (см. Редактивы для более ранней попытки).
varnames <- grep("_", names(DT), value=TRUE)
set(DT, j = varnames, value = DT[, ..varnames] - DT[, RF])