【问题标题】:Multiple first and last non-NA values by group按组的多个第一个和最后一个非 NA 值
【发布时间】:2020-11-28 16:27:48
【问题描述】:

我有以下data.table:

require(data.table)
dt = data.table(
  id = c(rep('Grp 1', 31), rep('Grp 2', 31)),
  date = rep(as.IDate(as.IDate('2020-01-01') : as.IDate('2020-01-31')), 2),
  change = c(rep(NA, 5), rep('yes', 5), rep(NA, 10), rep('yes', 3), rep(NA, 8),
             rep(NA, 2), rep('yes', 8), rep(NA, 8), rep('yes', 5), rep(NA, 8))
)

对于每个组id,我想过滤一个系列的第一个和最后一个dates,它由第二列change定义为yes(即非NA)。我可以执行以下操作,这将按组为我提供第一个和最后一个非 NA 行。但是,问题是该系列每组出现不止一次。

dt[ !is.na(change),
    .(head(date, 1),
      tail(date, 1)),
    .(id) ]

这些是我想要过滤的行索引:

dt[c(6,10,21,23,34,41,50,54)]

【问题讨论】:

    标签: r dplyr data.table


    【解决方案1】:

    一种方法是为每个由idchange 组合标识的条纹提供唯一的组ID。我们可以使用rleid 来生成这样的游程类型ID。考虑这样的事情

    dt[,
       gid := rleid(id, change)
    ][!is.na(change),
      as.list(range(date)),
      by = .(id, gid)
    ][, 
      gid := NULL
    ]
    

    请注意,我还假设您想要日期范围,而不是真正的第一个和最后一个元素。如果日期不按时间顺序排列,您的方法将失败。输出如下所示

          id         V1         V2
    1: Grp 1 2020-01-06 2020-01-10
    2: Grp 1 2020-01-21 2020-01-23
    3: Grp 2 2020-01-03 2020-01-10
    4: Grp 2 2020-01-19 2020-01-23
    

    rleid 是这样工作的

    > rleid(c(1, 1, 2, 3, 3), c("a", "b", "b", "d", "d"))
    [1] 1 2 3 4 4
    

    【讨论】:

      【解决方案2】:

      这是dplyr的选项

      library(dplyr)
      library(data.table)
      dt %>%
           group_by(grp = rleid(id, change), id) %>% 
           filter(!is.na(change)) %>%
           summarise(V1 = min(date, na.rm = TRUE),
                     V2 = max(date, na.rm = TRUE), .groups = 'drop') 
      

      -输出

      # A tibble: 4 x 4
      #    grp id    V1         V2        
      #  <int> <chr> <date>     <date>    
      #1     2 Grp 1 2020-01-06 2020-01-10
      #2     4 Grp 1 2020-01-21 2020-01-23
      #3     7 Grp 2 2020-01-03 2020-01-10
      #4     9 Grp 2 2020-01-19 2020-01-23
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-03
        • 2022-11-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多