首页 > 解决方案 > 满足条件的连续事件之间的R间隔 - data.table方式

问题描述

我有一个连续事件的数据集,按 id 分组并按事件开始日期(开始)排序。每个事件可以有 2 个状态 (cond),a 和 b。我需要计算 2 个 CONSECUTIVE 事件(开始 - 结束)之间的间隔,但前提是较新的事件符合某个标准:cond !="b"。如果不是,则该事件的 interval=NA 并移至下一个。这是一个玩具数据集:

dt=data.table(stringsAsFactors=FALSE,
      id = c(111, 111, 111, 111, 222, 222, 222, 222, 333, 333, 333, 333),
    cond=c("a", "a", "a", "a", "a", "b", "a", "a", "a", "b", "b", "b"),
   start = c(as.Date( "11/19/2020", format="%m/%d/%Y"),as.Date( "11/27/2020", format="%m/%d/%Y"),as.Date( "12/5/2020", format="%m/%d/%Y"),as.Date( "12/13/2020", format="%m/%d/%Y"),as.Date( "12/21/2020", format="%m/%d/%Y"),as.Date( "12/29/2020", format="%m/%d/%Y"),as.Date( "1/6/2021", format="%m/%d/%Y"),as.Date( "1/14/2021", format="%m/%d/%Y"),as.Date( "1/22/2021", format="%m/%d/%Y"),as.Date( "1/30/2021", format="%m/%d/%Y"),as.Date( "2/7/2021", format="%m/%d/%Y"),as.Date( "2/15/2021", format="%m/%d/%Y")),
     end = c(as.Date( "11/24/2020", format="%m/%d/%Y"),as.Date( "12/2/2020", format="%m/%d/%Y"),as.Date( "12/10/2020", format="%m/%d/%Y"),as.Date( "12/18/2020", format="%m/%d/%Y"),as.Date( "12/26/2020", format="%m/%d/%Y"),as.Date( "1/3/2021", format="%m/%d/%Y"),as.Date( "1/11/2021", format="%m/%d/%Y"),as.Date( "1/19/2021", format="%m/%d/%Y"),as.Date( "1/27/2021", format="%m/%d/%Y"),as.Date( "2/4/2021", format="%m/%d/%Y"),as.Date( "2/12/2021", format="%m/%d/%Y"),as.Date( "2/20/2021", format="%m/%d/%Y")
))

结果应如下所示:

    id cond      start        end interval
1  111    a 11/19/2020 11/24/2020        3
2  111    a 11/27/2020  12/2/2020        3
3  111    a  12/5/2020 12/10/2020        3
4  111    a 12/13/2020 12/18/2020       NA
5  222    a 12/21/2020 12/26/2020       NA
6  222    b 12/29/2020   1/3/2021        3
7  222    a   1/6/2021  1/11/2021        3
8  222    a  1/14/2021  1/19/2021       NA
9  333    a  1/22/2021  1/27/2021       NA
10 333    b  1/30/2021   2/4/2021       NA
11 333    b   2/7/2021  2/12/2021       NA
12 333    b  2/15/2021  2/20/2021       NA

因此,条件 cond!="b" 仅适用于“开始”行;我希望这样的事情会起作用:

dt[,interval:= shift(start[cond!="b"],n = 1L,type="lead") -end ,id]

但事实并非如此。我也尝试过滚动连接:

dt[,row_id:=rowid(id)]
dt[, interval := 
     .SD[.(cond!="b", id = id, row_id = row_id +1), on=.(id,row_id), roll=-Inf, x.start]-end]

这也不能满足我的需要。我觉得 data.table 应该能够很容易地处理这个任务。我只是不知道怎么做。任何帮助将不胜感激。

标签: rdata.table

解决方案


要获得价值,您可以从每个日期interval中减去下一个start日期。将所有值转到下一个值所在的位置。endidintervalNAcond'b'

library(data.table)

dt[, interval := as.integer(shift(start, type = 'lead') - end), id]
dt[shift(cond, type = 'lead') == 'b', interval := NA]
dt

#     id cond      start        end interval
# 1: 111    a 2020-11-19 2020-11-24        3
# 2: 111    a 2020-11-27 2020-12-02        3
# 3: 111    a 2020-12-05 2020-12-10        3
# 4: 111    a 2020-12-13 2020-12-18       NA
# 5: 222    a 2020-12-21 2020-12-26       NA
# 6: 222    b 2020-12-29 2021-01-03        3
# 7: 222    a 2021-01-06 2021-01-11        3
# 8: 222    a 2021-01-14 2021-01-19       NA
# 9: 333    a 2021-01-22 2021-01-27       NA
#10: 333    b 2021-01-30 2021-02-04       NA
#11: 333    b 2021-02-07 2021-02-12       NA
#12: 333    b 2021-02-15 2021-02-20       NA

推荐阅读