使用 R 测试日期是否出现在多个日期范围内

Test if date occurs in multiple date ranges with R

我有一个包含多个日期范围(准确地说是 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 函数以及各种 Whosebug 问题,但找不到好的解决方案。

自己编写 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

您可以从第一个数据框创建日期范围的向量,然后使用 %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% 一起使用。

在您的第一个 "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")