lapply-创建带有.SDcols变体的新变量

时间:2020-03-10 17:06:50

标签: r data.table lapply

我有一个大型数据集,其中包含一些需要关注的核心变量,因此需要计算许多不同的运算。我在数据表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步骤创建的新列。我想计算列xx.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)]

谢谢!

2 个答案:

答案 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)

如果您想坚持使用[],可以将Mapmget一起使用

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')))]