【问题标题】:Test if date occurs in multiple date ranges with R使用 R 测试日期是否出现在多个日期范围内
【发布时间】:2016-10-22 08:59:48
【问题描述】:

我有一个包含多个日期范围(确切地说是 45 个)的数据框:

Range  Start       End
1      2014-01-01  2014-02-30
2      2015-01-10  2015-03-30
3      2016-04-20  2016-10-12
...    ...         ...

它们永远不会重叠

我还有一个包含各种事件日期 (200K+) 的数据框:

Event  Date
1      2014-01-02
2      2014-03-20
3      2015-04-01
4      2016-08-18
...    ...

我想测试这些日期是否在这些范围内:

Event  Date        InRange
1      2014-01-02  TRUE
2      2014-03-20  FALSE
3      2015-04-01  FALSE
4      2016-08-18  TRUE
...

执行此测试的最佳方法是什么?我查看了 lubridate 的 betweeninterval 函数以及各种 Stackoverflow 问题,但找不到好的解决方案。

【问题讨论】:

    标签: r date intervals date-arithmetic


    【解决方案1】:

    编写您自己的function 以检查日期列表是否在多个间隔中。

    date.in <- function(x){
    m <- NULL
    for (i in 1:NROW(df)){m <- c(m,  ifelse(x>=df[i,1] & x<=df[i,2], TRUE, FALSE))}
    any(m)}
    

    数据:

    df <- data.frame(start=c("2014-01-01", "2015-01-10", "2016-04-20"), 
           end=c("2014-02-30", "2015-03-30", "2016-10-12"))
    df[] <- lapply(df, as.character)
    
    s <- c("2014-01-02", "2014-03-20", "2015-04-01", "2016-08-18")
    

    使用字符串s进行测试。

    as.character(lapply(s, date.in))#TRUE FALSE FALSE TRUE
    

    【讨论】:

      【解决方案2】:

      在您的第一个“data.frame”中具有有序的非重叠间隔,您可以测试每个事件日期是否高于$Start 及其各自的$End。使用findInterval 减少关系比较和所需的内存。

      findInterval(events$Date, ranges$Start) > findInterval(events$Date, ranges$End)
      #[1]  TRUE FALSE FALSE  TRUE
      

      有数据(修改“2014-02-30”):

      ranges = structure(list(Range = 1:3, Start = structure(c(16071, 16445, 
      16911), class = "Date"), End = structure(c(16129, 16524, 17086
      ), class = "Date")), .Names = c("Range", "Start", "End"), row.names = c(NA, 
      -3L), class = "data.frame")
      
      events = structure(list(Event = 1:4, Date = structure(c(16072, 16149, 
      16526, 17031), class = "Date")), .Names = c("Event", "Date"), row.names = c(NA, 
      -4L), class = "data.frame")
      

      【讨论】:

        【解决方案3】:

        您可以从第一个数据框创建日期范围的向量,然后使用%in% 运算符检查您的事件的每个日期是否在此日期范围内。假设您的第一个数据框是dateRange,第二个是events,则将上述逻辑放在一行中:

        events$InRange <- events$Date %in% unlist(Map(`:`, dateRange$Start, dateRange$End))
        
        events
          Event       Date InRange
        1     1 2014-01-02    TRUE
        2     2 2014-03-20   FALSE
        3     3 2015-04-01   FALSE
        4     4 2016-08-18    TRUE
        

        我们使用Map 创建日期范围向量。 Map 结合 : 运算符创建从 StartEnd 的日期范围列表。在接近list(2014-01-01 : 2014-02-30, 2015-01-10 : 2015-03-30, 2016-04-20 : 2016-10-12 ...)(象征性地,无效)的某个地方,使用unlist,我们将其展平为日期范围的向量,然后可以方便地与%in% 一起使用。

        【讨论】:

        • 一个很棒的班轮 - 很有魅力!!!你能解释一下 unlist 和 Map 部分吗?
        • 刚刚更新了说明。如果还不清楚,请查看Map(:, c(1,2), c(3,4)) 的输出,您将看到它是如何工作的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-02
        相关资源
        最近更新 更多