首页 > 解决方案 > 按组的多个第一个和最后一个非 NA 值

问题描述

我有以下数据表:

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,我想过滤一个系列的第一个和最后一个,它date由第二列定义(即非 NA)。我可以执行以下操作,这将按组为我提供第一个和最后一个非 NA 行。然而,问题是该系列每组出现不止一次。changeyes

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

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

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

标签: rdplyrdata.table

解决方案


id一种方法是为由andchange组合标识的每个条纹赋予唯一的组 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

推荐阅读