使用lapply并获取

时间:2018-06-15 15:08:54

标签: r data.table lapply

有人可以帮助我理解为什么下面的两个版本的lapply操作使用和不使用get()都不会产生相同的结果?使用get()时,结果列会混淆。

dt <- data.table(v1 = c(1,2), v2 = c(3,4), type = c('A', 'B'))

   v1 v2 type
1:  1  3    A
2:  2  4    B

col_in <- c('v2', 'v1')
col_out <- paste0(col_in, '.new')

访问&#39;输入&#39;硬编码的方式

dt[, (col_out) := lapply(.SD, function(x){x * min(x[type == 'A'])}), .SDcols = col_in]

产生预期结果:

   v1 v2 type v2.new v1.new
1:  1  3    A      9      1
2:  2  4    B     12      2

然而,当访问&#39;键入&#39;通过get()

dt[, (col_out) := lapply(.SD, function(x){x * min(x[get('type') == 'A'])}), .SDcols = col_in]

v1.new的预期值位于v2.new,反之亦然:

   v1 v2 type v2.new v1.new
1:  1  3    A      1      9
2:  2  4    B      2     12

注意:这是一个最小的玩具示例,我从一个我试图实现的更复杂的操作中提炼出来。 &#39;类型的名称&#39;变量作为输入参数给出。

2 个答案:

答案 0 :(得分:3)

有趣!感谢分享!似乎使用get需要一些内部排序(bug?)。

避免这种情况的两种方法:

  1. 将类型=='A'部分移到dt [,lapply(...)]

    之外
    referenceRows <- which(dt[,type == 'A'])
    referenceRows <- which(dt[,get('type') == 'A'])
    dt[, lapply(.SD, function(x){x * min(x[referenceRows])}), .SDcols = col_in]
    
       v1 v2 type v2.new v1.new
    1:  1  3    A      9      1
    2:  2  4    B     12      2
    
  2. 首先创建新列,然后使用setnames确保为新列分配了正确的列名。最后用cbind将这两个部分绑定在一起:

    dtNew <- dt[, lapply(.SD, function(x){x * min(x[type == 'A'])}), .SDcols = col_in]
    setnames(dtNew, col_in, col_out)
    cbind(dt, dtNew)
    
    
       v1 v2 type v2.new v1.new
    1:  1  3    A      9      1
    2:  2  4    B     12      2
    
  3. 相同的结果(尽管排序方式不同):

        dtNew <- dt[, lapply(.SD, function(x){x * min(x[get('type') == 'A'])}), .SDcols = col_in]
        setnames(dtNew, col_in, col_out)
        cbind(dt, dtNew)
    
    
           v1 v2 type v1.new v2.new
        1:  1  3    A      1      9
        2:  2  4    B      2     12
    

答案 1 :(得分:2)

另一种方法是使用称为语言的计算(与data.table不相关)的酷R功能代替get并生成所需的j参数作为语言对象使用substitute函数。
分组时也可以使用。

library(data.table)
dt <- data.table(v1 = c(1,2), v2 = c(3,4), type = c('A', 'B'))
col_in <- c('v2', 'v1')
col_out <- paste0(col_in, '.new')

col_where <- 'type'
qj <- substitute(.col_out := lapply(.SD, function(x){x * min(x[.col_where == 'A'])}),
                 list(.col_out=col_out, .col_where=as.name(col_where)))
print(qj)
#`:=`(c("v2.new", "v1.new"), lapply(.SD, function(x) {
#    x * min(x[type == "A"])
#}))

dt[, eval(qj), .SDcols = col_in][]
#      v1    v2   type v2.new v1.new
#   <num> <num> <char>  <num>  <num>
#1:     1     3      A      9      1
#2:     2     4      B     12      2

R language definition: Computing-on-the-language chapter中有关此功能的更多信息。