29

我有一个 data.table DT,其中包含一个名为的列RF和许多带有下划线_的列。我想用下划线遍历所有这些列并RF从中减去该列。但是,我被困住了。似乎 a 中:=运算符的 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]

对此感到抱歉。但是,我保留这个问题是因为我仍然对为什么我与:=操作员的方法不起作用感兴趣。所以也许有人可以在那里帮助我。

4

3 回答 3

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

您还可以使用 LHS 表达式而不是符号:

for (i in grep("_", names(DT), value=TRUE))
    DT[, (i) := get(i)-RF]
于 2011-12-05T08:07:59.903 回答
5

我发布问题后不幸发现的解决方法如下:

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])
于 2011-12-04T17:56:16.310 回答
4

更新为使用set()+ ..; set功能强大(参见早期尝试的编辑)。

varnames <- grep("_", names(DT), value=TRUE)
set(DT, j = varnames, value = DT[, ..varnames] - DT[, RF])
于 2012-12-11T14:39:56.013 回答