代码之家  ›  专栏  ›  技术社区  ›  Fino

为什么不能在data.table中使用.I的特定函数添加列?

  •  0
  • Fino  · 技术社区  · 5 年前

    最近我看到一个问题(找不到链接)是这样的

    我想在data.frame上添加一个列,该列在删除当前观测值时计算不同列的方差。

    dt = data.table(
      id = c(1:13),
      v = c(9,5,8,1,25,14,7,87,98,63,32,12,15)
    )
    

    所以,用一个 for()

    res = NULL
    for(i in 1:13){
      res[i] = var(dt[-i,v])
    }
    

    我尝试在data.table中使用负索引 .I ,但令我惊讶的是,以下这些都不起作用:

    #1
    dt[,var := var(dt[,v][-.I])]
    
    #2
    dt[,var := var(dt$v[-.I])]
    
    #3 
    fun = function(x){
      v = c(9,5,8,1,25,14,7,87,98,63,32,12,15)
      var(v[-x])
    }
    dt[,var := fun(.I)]
    
    #4
    fun = function(x){
      var(dt[-x,v])
    }
    dt[,var := fun(.I)]
    

        id  v var
     1:  1  9  NA
     2:  2  5  NA
     3:  3  8  NA
     4:  4  1  NA
     5:  5 25  NA
     6:  6 14  NA
     7:  7  7  NA
     8:  8 87  NA
     9:  9 98  NA
    10: 10 63  NA
    11: 11 32  NA
    12: 12 12  NA
    13: 13 15  NA
    

    我错过了什么?我以为是因为 .I.一

    fun = function(x,c){
      x*c
    }
    dt[,dummy := fun(.I,2)]
    
        id  v var
     1:  1  9   2
     2:  2  5   4
     3:  3  8   6
     4:  4  1   8
     5:  5 25  10
     6:  6 14  12
     7:  7  7  14
     8:  8 87  16
     9:  9 98  18
    10: 10 63  20
    11: 11 32  22
    12: 12 12  24
    13: 13 15  26
    

    工作正常。

    为什么我不能用 .I.一 在这个特定的场景中?

    1 回复  |  直到 5 年前
        1
  •  7
  •   Henrik plannapus    5 年前

    你可以用 .BY

    list 中每个项包含长度为1的向量 by

    dt[ , var_v := dt[id != .BY$id,  var(v)], by = id]
    

    by = id ). 在每次计算中,使用 id != .BY$id 在“内心” i

    all.equal(dt$var_v, res)
    # [1] TRUE
    

    为什么你的代码不能工作?因为。。。

    .I 是一个等于 seq_len(nrow(x)) ,

    …你的 -.I 不仅删除 观察,它移除 全部的 一行从“v”开始。

    从你的尝试开始的一个小的说明(没有任务 :=

    # your attempt
    dt[ , var(dt[, v][-.I])]
    # [1] NA
    
    # without the `var`, indexing only
    dt[ , dt[ , v][-.I]]
    # numeric(0)
    # an empty vector
    
    # same indexing written in a simpler way
    dt[ , v[-.I]]
    # numeric(0)
    
    # even more simplified, with a vector of values
    # and its corresponding indexes (equivalent to .I)
    v <- as.numeric(11:14)
    i <- 1:4
    v[i]
    # [1] 11 12 13 14
    
    x[-i]
    # numeric(0)
    
        2
  •  2
  •   r2evans    5 年前

    这里有一个野蛮的想法:

    exvar <- function(x, na.rm = FALSE) sapply(seq_len(length(x)), function(i) var(x[-i], na.rm = na.rm))
    dt[,var := exvar(v)]
    dt
    #     id  v      var
    #  1:  1  9 1115.538
    #  2:  2  5 1098.265
    #  3:  3  8 1111.515
    #  4:  4  1 1077.841
    #  5:  5 25 1153.114
    #  6:  6 14 1132.697
    #  7:  7  7 1107.295
    #  8:  8 87  822.447
    #  9:  9 98  684.697
    # 10: 10 63 1040.265
    # 11: 11 32 1153.697
    # 12: 12 12 1126.424
    # 13: 13 15 1135.538