如何在循环调用中使用data.table生成变量的线性组合和更新表?

mar*_*bel 4 r data.table

一些玩具数据

set.seed(123)
df <- data.frame(what_ever = rnorm(5, 50, 1),
                 this_is = rnorm(5, 30, 1),
                 wtf_nnn = rnorm(5, 20, 1),
                 hat_ever = rnorm(5, 50, 1),
                 who_is = rnorm(5, 30, 1),
                 mmm_nnn = rnorm(5, 20, 1)                 
                 )


library(data.table)
DT <- data.table(df)

str(DT)
Classes ‘data.table’ and 'data.frame':  5 obs. of  6 variables:
Run Code Online (Sandbox Code Playgroud)

如何data.table 使用循环生成以下结果的新变量?

New_Var_1 = what_ever/hat_ever
New_Var_2 = this_is/who_is
New_Var_3 = wtf_nnn/mmm_nnn
Run Code Online (Sandbox Code Playgroud)

在这里,我订购列名称

nm <- names(df)
nm1 <- nm[1:3]
nm2 <- nm[4:6]
Run Code Online (Sandbox Code Playgroud)

我想以这种方式更新DT,并循环通过

i <- 1

New_Var_names <- paste("New_Var_", i, sep = "")
New_Var <- sprintf("%s/%s", nm1[i], nm2[i])
Run Code Online (Sandbox Code Playgroud)

这三种尝试都不起作用.

DT[,New_Var_names := New_Var]
DT[,cat(New_Var_names) := cat(New_Var)]
DT[,eval(New_Var_names) := eval(New_Var)]
Run Code Online (Sandbox Code Playgroud)

Aru*_*run 5

我建议使用seta for-loop来执行此操作,但在当前稳定版(CRAN)1.8.10版中,set不添加新列.所以,我会做类似的事情:

require(data.table)
out_names <- paste("newvar", 1:3, sep="_")
DT[, c(out_names) := 0]

invar1 <- names(DT)[1:3]
invar2 <- names(DT)[4:6]

for (i in seq_along(invar1)) {
    set(DT, i=NULL, j=out_names[i], value=DT[[invar1[i]]]/DT[[invar2[i]]])
}
Run Code Online (Sandbox Code Playgroud)

在当前的devel版本(1.8.11)中,set可以添加新列.因此,您不需要使用分配:=.那是:

require(data.table)
out_names <- paste("newvar", 1:3, sep="_")

invar1 <- names(DT)[1:3]
invar2 <- names(DT)[4:6]

for (i in seq_along(invar1)) {
    set(DT, i=NULL, j=out_names[i], value=DT[[invar1[i]]]/DT[[invar2[i]]])
}
Run Code Online (Sandbox Code Playgroud)

为了完整性,另一种方法是:

EVAL = function(...)eval(parse(text=paste0(...)))  # helper function

New_Var_names <- paste("New_Var_", i, sep = "")
New_Var <- sprintf("%s/%s", nm1[i], nm2[i])

for (i in 1:3)
    EVAL("DT[,", New_Var_names[i], ":=", New_Var[i], "]")
Run Code Online (Sandbox Code Playgroud)

这是更普遍的,你也可以改变运营商/sprintf和改变by=太条款等它类似于构建一个动态SQL语句,如果没有什么帮助.如果要记录正在执行的动态查询,可以cat在定义中添加a EVAL.