我有以下项目数据框架:
id | 开始日期 | 结束日期 |
---|---|---|
01 | 2019年6月11日 | 2021 年 4 月 7 日 |
02 | 2021 年 8 月 12 日 | 2022 年 1 月 18 日 |
03 | 2019/10/24 | 2019年12月3日 |
04 | 2021 年 9 月 20 日 | 2021 年 11 月 11 日 |
05 | 2021 年 11 月 11 日 | 2021 年 11 月 11 日 |
我还有一个日期列表:
date_list <- c(1/1/2020, 1/1/2021, 1/1,2022)
我想计算在这些特定日期内有多少项目处于“活跃”状态。
例如: 2020 年 1 月 1 日,只有 1 个项目处于活动状态,即项目#1,因为它在 2020 年 1 月 1 日之前开始并在 2020 年 1 月 1 日之后结束。换句话说,该日期是一个活跃的项目。
for (date in date-list) {
projects %>% filter(start_date <= date & end_date > date) %>% count()
}
这花费了太长时间,因为我正在处理数千个日期的列表和数千个项目的列表。
您可以首先构建一个给定日期的所有开放项目的表。这是一种方法来做到这一点
number_open <- rbind(
data.frame(date=dd$end_date+1, open=-1),
data.frame(date=dd$start_date, open=1)
) %>%
arrange(date) %>%
summarize(open=sum(open), .by=date) %>%
mutate(open=cumsum(open))
返回
date open
1 2019-06-11 1
2 2019-10-24 2
3 2019-12-04 1
4 2021-04-08 0
5 2021-08-12 1
6 2021-09-20 2
7 2021-11-11 3
8 2021-11-12 1
9 2022-01-19 0
因此,对于每个日期,我们都可以看到项目数量何时发生变化。 我们可以使用
findInterval
对日期列表进行排序,以查找给定日期的开放事件数量
date_list <- as.Date(c("1/1/2020", "1/1/2021", "1/1/2022"), "%m/%d/%Y")
number_open$open[findInterval(date_list, number_open$date)]
# [1] 1 1 1
因此,每个日期都有 1 个项目处于开放状态。
执行此操作的快速方法是使用
data.table::foverlaps()
。
library(data.table)
# Set keys for join
setkey(projects, start_date, end_date)
setkey(date_dt, date, dummy_date)
project_dates <- foverlaps(projects, date_dt, type="any")
setorder(project_dates, id, start_date)
setcolorder(project_dates, c("id", "start_date", "end_date", "date"))
project_dates[, dummy_date := NULL]
project_dates
# id start_date end_date date
# <int> <IDat> <IDat> <IDat>
# 1: 1 2019-06-11 2021-04-07 2020-01-01
# 2: 1 2019-06-11 2021-04-07 2021-01-01
# 3: 2 2021-08-12 2022-01-18 2022-01-01
# 4: 3 2019-10-24 2019-12-03 <NA>
# 5: 4 2021-09-20 2021-11-11 <NA>
# 6: 5 2021-11-11 2021-11-11 <NA>