如何在R中统计满足条件的连续有效工作日天数及次数
问题需求
给定包含itinerary(行程)、service(服务提供商)、date(日期)、flag(布尔标记)的数据集,需完成:
- 筛选出存在至少3个连续有效工作日(周五与周一视为连续)且flag=1的行程
- 统计这类连续有效工作日区间的出现次数
最小可用数据集
# 生成连续日期并剔除周末 days <- rep(seq(as.Date('2024-03-01'), as.Date('2024-03-14'), '1 day'), 1, each = 10) days <- days[!weekdays(days) %in% c('Saturday','Sunday')] # 创建最小工作数据集 set.seed(1337) df <- tibble( itinerary = rep(101:110, 10), service = rep(c("CIA", "CIA", "FBI", "FBI", "FBI", "FBI", "NSA", "NSA", "CIA", "FBI"), 10), date = days, flag = sample(c(0,1), 100, replace = TRUE)) # 查看数据集前6行 > head(df) # A tibble: 6 × 4 itinerary service date flag <int> <chr> <date> <dbl> 1 101 CIA 2024-03-01 1 2 102 CIA 2024-03-01 0 3 103 FBI 2024-03-01 1 4 104 FBI 2024-03-01 0 5 105 FBI 2024-03-01 1 6 106 FBI 2024-03-01 1
已尝试方案
方案1:基于日期差值分组(存在缺陷)
该方案通过日期差值判断连续性,但无法识别周五与周一的连续关系:
df_working <- df %>% group_by(itinerary, service, flag) %>% mutate(grp = cumsum(c(TRUE, diff(date) != 1))) %>% group_by(grp, .add = TRUE) %>% summarise( len = n(), start_date = first(date), end_date = last(date), .groups = 'drop' ) # 查看结果前6行 > head(df_working) # A tibble: 6 × 7 itinerary service flag grp len start_date end_date <int> <chr> <dbl> <int> <int> <date> <date> 1 101 CIA 0 1 1 2024-03-05 2024-03-05 2 101 CIA 0 2 1 2024-03-08 2024-03-08 3 101 CIA 0 3 2 2024-03-11 2024-03-12 4 101 CIA 1 1 1 2024-03-01 2024-03-01 5 101 CIA 1 2 1 2024-03-04 2024-03-04 6 101 CIA 1 3 2 2024-03-06 2024-03-07
方案2:基于有效日期序列分组(可行但冗余)
通过构建有效工作日的连续序列解决了周五-周一连续问题,但代码较为繁琐:
# 提取数据中所有唯一有效日期并生成连续序号 days_unique <- unique(days) %>% as_tibble() %>% arrange() %>% rename(date = value) %>% mutate(seq = row_number()) # 关联序号后分组计算连续天数 df_test <- df %>% left_join(days_unique, join_by(date)) %>% group_by(itinerary, service, flag) %>% mutate(grp = cumsum(c(TRUE, diff(seq)) != 1)) %>% group_by(grp, .add = TRUE) %>% mutate(cons_days = ifelse(seq == first(seq), last(seq) - seq +1, 0)) %>% summarise( cons_days = max(cons_days), start_date = first(date), end_date = last(date), .groups = 'drop' ) # 查看结果前6行 > head(df_test) # A tibble: 6 × 7 itinerary service flag grp cons_days start_date end_date <int> <chr> <dbl> <int> <dbl> <date> <date> 1 101 CIA 0 0 1 2024-03-05 2024-03-05 2 101 CIA 0 1 3 2024-03-08 2024-03-12 3 101 CIA 1 0 2 2024-03-01 2024-03-04 4 101 CIA 1 1 2 2024-03-06 2024-03-07 5 101 CIA 1 2 2 2024-03-13 2024-03-14 6 102 CIA 0 0 2 2024-03-01 2024-03-04
优化后的简洁稳健方案
直接基于有效工作日逻辑生成连续分组,无需额外关联序号表:
library(dplyr) library(lubridate) # 1. 筛选flag=1数据减少计算量,按行程、服务、日期排序 # 2. 生成有效工作日连续分组:周五到周一视为连续 result <- df %>% filter(flag == 1) %>% arrange(itinerary, service, date) %>% group_by(itinerary, service) %>% mutate( # 修正周五到周一的日期差值,将其视为连续工作日 workday_diff = as.integer(date - lag(date)) - case_when( wday(lag(date)) == 5 & wday(date) == 2 ~ 2, # 周五到周一实际间隔3天,减去2天转为连续标记 TRUE ~ 0 ), grp = cumsum(c(TRUE, workday_diff != 1)) ) %>% # 按分组统计连续天数、起止日期 group_by(itinerary, service, grp, .add = FALSE) %>% summarise( consecutive_days = n(), start_date = first(date), end_date = last(date), .groups = "drop" ) %>% # 筛选连续天数≥3的记录 filter(consecutive_days >= 3) # 统计每个行程的连续情况次数 summary_result <- result %>% group_by(itinerary) %>% summarise( total_consecutive_periods = n(), .groups = "drop" )
结果查看
查看符合条件的连续工作日区间:
> head(result)
查看各行程的连续情况统计:
> summary_result
内容的提问来源于stack exchange,提问作者Morrigan
相关产品推荐
相关产品推荐

