我有一个大型数据集,其中包含一些需要关注的核心变量,因此需要计算许多不同的运算。我在数据表cols
中有这些变量dt
的向量,并且我试图使用lapply
创建新变量。在创建需要使用数据表中多个现有变量的新变量时遇到麻烦,这些变量具有围绕核心变量构建的名称。这是一个示例(代码贯穿此处):
dt = data.table( id = c(1,1,2,2,3,3), x = 1:6, y = 7:12, z = 13:18) ## example data
cols = c("x","y","z") ## my list of variables
dt[ , paste0(cols, ".avg") := lapply(.SD, function(x) mean(x, na.rm = T)), by = .(id), .SDcols = cols]
我想继续以这种方式创建新变量,但是我很难参考我通过前面的lapply
步骤创建的新列。我想计算列x
和x.avg
之间的差,但是我一直遇到错误。我尝试过以下几种变化,所有这些都会导致错误:
dt[ , paste0(cols,".diff") := lapply(.SD, function(x) x-eval(paste0(x,".avg"))), .SDcols = cols]
Error in x-eval(paste0(x,".avg")) :
non-numeric argument to binary operator
我想要一个lapply
步骤,该步骤等效于以下步骤:
dt[ ':=' (x.diff = x-x.avg,
y.diff = y-y.avg,
z.diff = z-z.avg)]
谢谢!
答案 0 :(得分:2)
使用set()
代替.SDcols
...
cols <- c("x", "y", "z")
for (col in cols) {
set(dt, j = paste0(col, ".diff"), value = dt[[col]] - dt[[paste0(col, ".avg")]])
}
答案 1 :(得分:2)
如果您想坚持使用[]
,可以将Map
与mget
一起使用
dt[, paste0(cols, '.diff') := Map(function(var, avg) var - avg,
mget(cols),
mget(paste0(cols, '.avg')))]
dt
# id x y z x.avg y.avg z.avg x.diff y.diff z.diff
# 1: 1 1 7 13 1.5 7.5 13.5 -0.5 -0.5 -0.5
# 2: 1 2 8 14 1.5 7.5 13.5 0.5 0.5 0.5
# 3: 2 3 9 15 3.5 9.5 15.5 -0.5 -0.5 -0.5
# 4: 2 4 10 16 3.5 9.5 15.5 0.5 0.5 0.5
# 5: 3 5 11 17 5.5 11.5 17.5 -0.5 -0.5 -0.5
# 6: 3 6 12 18 5.5 11.5 17.5 0.5 0.5 0.5
在此示例中,您的匿名函数只是减法,因此您可以更紧凑地编写为
dt[, paste0(cols, '.diff') := Map('-', mget(cols), mget(paste0(cols, '.avg')))]