代码之家  ›  专栏  ›  技术社区  ›  mr.bjerre

展开R中数据表中组内的最后观察值

  •  1
  • mr.bjerre  · 技术社区  · 6 年前

    想象一个 data.table 在里面 R 像这样

    dtable = data.table(
      id = c(1, 1, 1, 2, 2, 2),
      time = c(1, 2, 3, 2, 3, 4),
      value_a = c(NA, 'Yes', NA, 'No', NA, 'Yes'),
      value_b = c('No', 'Yes', NA, NA, NA, NA)
    )
    cols <- c("value_a", "value_b")
    

    其计算结果为

       id time value_a value_b
    1:  1    1    <NA>      No
    2:  1    2     Yes     Yes
    3:  1    3    <NA>    <NA>
    4:  2    2      No    <NA>
    5:  2    3    <NA>    <NA>
    6:  2    4     Yes    <NA>
    

    对于每个 id time 我希望扩展最新观察到的( <NA> 对应于无观察)值。一、 e.我正在寻找一种有效的方法来创建结果表:

       id time value_a value_b
    1:  1    1    <NA>      No
    2:  1    2     Yes     Yes
    3:  1    3     Yes     Yes
    4:  2    2      No    <NA>
    5:  2    3      No    <NA>
    6:  2    4     Yes    <NA>
    

    我的数据集非常大,所以 效率 这很重要。

    2 回复  |  直到 6 年前
        1
  •  2
  •   YOLO    6 年前

    这应该更快。
    使用 na.locf (正向填充NA)来自 zoo 软件包,您可以执行以下操作:

    dtable[, c('value_a','value_b') := lapply(.SD, na.locf, na.rm=F), .SDcols = c('value_a','value_b'), .(id)]
    
    print(dtable)
    
       id time value_a value_b
    1:  1    1      NA      No
    2:  1    2     Yes     Yes
    3:  1    3     Yes     Yes
    4:  2    2      No      NA
    5:  2    3      No      NA
    6:  2    4     Yes      NA
    
        2
  •  0
  •   mr.bjerre    6 年前

    受@chinsoon12的启发,我想出了以下解决方案

    cols <- c("value_a", "value_b")
    dtable[, (cols) := lapply(.SD, function(x) {
      if (.N > 1) {
        na_idx = which(is.na(x))
        value_idx = which(!is.na(x))
    
        # determine if there are any non NA values
        if (length(value_idx) > 0){
    
          # update all NAs observed after an actual observed observation
          if (length(na_idx[na_idx > min(value_idx)]) > 0)
            na_idx[na_idx > min(value_idx)] <- sapply(na_idx[na_idx > min(value_idx)], function(i) max(value_idx[value_idx < i]))
    
          # build new index array to use for return
          replace_with_idx <- c(na_idx, value_idx)
          return(x[replace_with_idx[order(replace_with_idx)]])
        } else {
          NA  # if all NA
        }
      }
      x  # if only one observed value
    }), 
    by=id, .SDcols=cols]