循环遍历data.table中的列并转换这些列

Chr*_*h_J 28 r data.table

我有一个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
...
Run Code Online (Sandbox Code Playgroud)

但是,我希望它更灵活,即在其名称中使用"_"循环遍历每一列并减去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
Run Code Online (Sandbox Code Playgroud)

任何提示如何做到这一点都会很棒.

编辑:我一发布这个问题,我就问自己:你为什么一开始就与:=操作员合作,果然,我才意识到我没有必要.这确实有效,不需要循环:

DT[, grep("_", names(DT)), with=FALSE] - DT[, RF]
Run Code Online (Sandbox Code Playgroud)

对不起.但是,我保持问题是开放的,因为我仍然对我为何与:=操作员的方法不起作用感兴趣.所以也许有人可以帮助我.

Jos*_*ien 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
Run Code Online (Sandbox Code Playgroud)

或现在(1年后)substitute适用于'j'OK 的LHS :

for (i in grep("_", names(DT), value=TRUE))
    DT[, (i) := get(i)-RF]
Run Code Online (Sandbox Code Playgroud)

或者DT[ , j ]可以通过使LHS成为表达而不是符号来避免:

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
Run Code Online (Sandbox Code Playgroud)

  • 不客气,@ Christoph_J.还有,几个想法.首先我认为在这种情况下,循环_might_会更好,因为它允许您利用data.table的modify-by-reference`:=`运算符.(我可能会在以后运行一些基准来检查这个,如果我这样做,我会给你的答案添加结果).其次,要探索`substitute`等,你可能想在`j`中调用`browser()`,如下所示:`for(i in ......){DT [,browser() ]}`.然后你可以在'内部'探索DT,尝试不同的东西(比如`quote(i)`,`eval(quote(i)`,`as.symbol(eval(quote(i))`,`eval(解析(text = i))`等) (6认同)

Chr*_*h_J 5

不幸的是,在我发布问题后发现了一种变通方法,如下所示:

DT[, .SD, .SDcols = patterns('_')] - DT[, RF]
Run Code Online (Sandbox Code Playgroud)

这也可以在更复杂的设置中使用,在该设置中您还需要保留其他列,但需要付出额外的努力:

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])
Run Code Online (Sandbox Code Playgroud)