【问题标题】:How to check if a date range in my dataframe overlaps with any (ID-specific) range in another dataframe如何检查我的数据框中的日期范围是否与另一个数据框中的任何(特定于 ID)范围重叠
【发布时间】:2019-07-14 22:56:56
【问题描述】:

我有 2 个数据框 (DF),每个都包含标识符和日期范围。在两个 DF 中,每个 ID 都可以有多个日期范围。

我想要做的是从第一个 DF (DF.A) 中选择第二个 DF (DF.B) 中存在任意长度重叠间隔的行。

df.A <- data.frame("ID" =       c(1,1,1,2,3,3),
                   "Start.A" =  c("2019-01-01", "2019-03-15", "2019-06-10", "2017-01-01", "2015-05-10", "2015-05-15"),
                   "End.A" =    c("2019-01-31", "2019-04-15", "2019-07-09", "2017-01-31", "2015-06-10", "2015-06-02"))


df.B <- data.frame("ID" =       c(1,1,1,3,3),
                   "Start.B" =  c("2019-01-01", "2019-02-01", "2019-03-01", "2015-06-01", "2015-07-01"),
                   "End.B" =    c("2019-01-31", "2019-02-28", "2019-03-31", "2015-06-30", "2015-07-31"))

数据框 A:

ID       Start.A       End.A
1        2019-01-01    2019-01-31 
1        2019-03-15    2019-04-15 
1        2019-06-10    2019-07-09
2        2017-01-01    2017-01-31
3        2015-05-10    2015-06-10
3        2015-05-15    2015-06-02

数据框 B:

ID       Start.B       End.B
1        2019-01-01    2019-01-31
1        2019-02-01    2019-02-28
1        2019-03-01    2019-03-31
3        2015-06-01    2015-06-30
3        2015-07-01    2015-07-31

我想要的输出是:

ID       Start.A       End.A
1        2019-01-01    2019-01-31 
1        2019-03-15    2019-04-15 
3        2015-05-10    2015-06-10
3        2015-05-15    2015-06-02

如果我有一对一的匹配,我想我可以毫无问题地做到这一点,但正如我所提到的,在两个 DF 中,每个 ID 都有很多观察结果。我已经尝试过尝试应用 lubridate 的间隔,但我正在努力解决如何查找重叠,同时处理必须在 DF.B 中查找所有相应 ID 以进行潜在匹配的额外复杂性。

这是一个非常大的数据集(DF.A 中 > 500 万个观测值和 DF.B 中 > 200 万个观测值),因此速度至关重要。任何有关转换数据以使此操作尽可能快的建议也将不胜感激。

如果有帮助:对于给定的 ID,DF.A 的观测值可能与 DF.A 中的其他观测值重叠(例如上面玩具示例中的 ID 3)。相反,DF.B 区间之间不能有重叠。

【问题讨论】:

    标签: r date match


    【解决方案1】:

    这个怎么样?

    library(data.table)
    df.A <- data.table("ID" =       c(1,1,1,2,3,3),
                       "Start.A" =  c("2019-01-01", "2019-03-15", "2019-06-10", "2017-01-01", "2015-05-10", "2015-05-15"),
                       "End.A" =    c("2019-01-31", "2019-04-15", "2019-07-09", "2017-01-31", "2015-06-10", "2015-06-02"))
    
    
    df.B <- data.table("ID" =       c(1,1,1,3,3),
                       "Start.B" =  c("2019-01-01", "2019-02-01", "2019-03-01", "2015-06-01", "2015-07-01"),
                       "End.B" =    c("2019-01-31", "2019-02-28", "2019-03-31", "2015-06-30", "2015-07-31"))
    
    

    还有

    DF = merge(df.A, df.B , by ='ID',allow.cartesian = TRUE)
    
    DF$SEQ_DATE.A = apply(DF[,c('Start.A','End.A'), with=F],1, function(x){paste(x,collapse = ',')})
    
    DF$SEQ_DATE.A = unlist(lapply(strsplit(DF$SEQ_DATE.A,','),function(x){
      out = seq(as.Date(x[1]),as.Date(x[2]),by = 'day')
      out = paste(out, collapse = '|')
      return(out)
    }
    ))
    
    DF$SEQ_DATE.B = apply(DF[,c('Start.B','End.B'), with=F],1, function(x){paste(x,collapse = ',')})
    
    DF$SEQ_DATE.B = unlist(lapply(strsplit(DF$SEQ_DATE.B,','),function(x){
      out = seq(as.Date(x[1]),as.Date(x[2]),by = 'day')
      out = paste(out, collapse = '|')
      return(out)
    }
    ))
    
    DF$Result= apply(DF[,c('SEQ_DATE.A','SEQ_DATE.B'), with = F], 1, function(x){grepl(x[1],x[2])})
    

    结果如下图:

    > DF[,-c('SEQ_DATE.A','SEQ_DATE.B'), with =F][Result == 'TRUE']
    
       ID    Start.A      End.A    Start.B      End.B Result
    1:  1 2019-01-01 2019-01-31 2019-01-01 2019-01-31   TRUE
    2:  1 2019-03-15 2019-04-15 2019-03-01 2019-03-31   TRUE
    3:  3 2015-05-10 2015-06-10 2015-06-01 2015-06-30   TRUE
    4:  3 2015-05-15 2015-06-02 2015-06-01 2015-06-30   TRUE
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-02
      • 2021-09-22
      • 2017-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多