我有一个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]
很抱歉。但是,我将问题保持开放,因为我仍然对我使用:=
运算符的方法不起作用的原因感兴趣。所以也许有人可以帮助我。
答案 0 :(得分:14)
你第二次尝试就走在了正确的轨道上。这是一种使用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:
for (i in grep("_", names(DT), value=TRUE))
DT[, i:=get(i)-RF, with=FALSE]
通过使LHS成为表达式而不是符号,可以避免或with=FALSE
:
for (i in grep("_", names(DT), value=TRUE))
DT[, (i):=get(i)-RF]
答案 1 :(得分:4)
我在发布问题后不幸发现的解决方法如下:
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])
答案 2 :(得分:4)
感谢您提出问题和答案。 我正在使用临时变量帮助解决类似任务的解决方案。
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])