如何计算主时间区间与其他区间的非重复重叠时长(Tidyverse优先)
计算主时间区间与多区间的非重复重叠时长
问题背景
需计算主时间区间与第二、第三区间的非重复重叠时长,重复重叠部分仅统计一次。当前逐分钟枚举的方法效率低下,寻求基于Tidyverse的高效解决方案。
示例数据
library(tidyverse) library(lubridate) main_start <- c("2024-01-01 4:50:00 PM", "2024-03-22 11:00:00 AM") main_end <- c("2024-01-01 11:40:00 PM", "2024-03-22 9:00:00 PM") second_start <- c("2024-01-01 2:00:00 PM", "2024-03-22 12:00:00 PM") second_end <- c("2024-01-02 12:15:00 AM", "2024-03-22 8:00:00 PM") third_start <- c("2024-01-01 8:00:00 AM", "2024-03-22 8:00:00 AM") third_end <- c("2024-01-01 5:00:00 PM", "2024-03-22 5:00:00 PM") df <- tibble::tibble(main_start, main_end, second_start, second_end, third_start, third_end) %>% mutate(main_start = ymd_hms(main_start), main_end = ymd_hms(main_end), second_start = ymd_hms(second_start), second_end = ymd_hms(second_end), third_start = ymd_hms(third_start), third_end = ymd_hms(third_end))
需求详情
- 统计主区间与第二/第三区间的总重叠时长,重复重叠部分仅计算一次
- 行1预期结果:6小时50分钟(主区间4:50 PM-11:40 PM完全被另外两个区间覆盖)
- 行2预期结果:9小时(主区间11:00 AM-9:00 PM的重叠区间为11:00 AM-8:00 PM)
高效解决方案
核心思路:先提取主区间与每个子区间的重叠部分,再合并这些重叠区间(消除内部重复),最后计算合并后区间的总时长。
实现代码
# 定义辅助函数:计算主区间与多个子区间的非重复重叠时长 calc_unique_overlap <- function(main_start, main_end, sub_starts, sub_ends) { main_int <- interval(main_start, main_end) # 生成每个子区间与主区间的重叠区间 overlaps <- map2(sub_starts, sub_ends, ~intersect(interval(.x, .y), main_int)) # 过滤空区间 overlaps <- keep(overlaps, ~!is.na(.x)) if (length(overlaps) == 0) { return(duration(0)) } # 合并重叠或相邻的区间 merged <- reduce(overlaps, ~union(.x, .y)) # 计算总时长 sum(int_length(merged)) %>% duration(units = "seconds") } # 应用到数据框 df_result <- df %>% rowwise() %>% mutate( unique_overlap = calc_unique_overlap( main_start, main_end, sub_starts = c(second_start, third_start), sub_ends = c(second_end, third_end) ), # 转换为易读的小时+分钟格式 overlap_hm = sprintf("%d小时%d分钟", hour(unique_overlap), minute(unique_overlap)) ) %>% ungroup() # 查看结果 df_result %>% select(main_start, main_end, unique_overlap, overlap_hm)
结果验证
运行代码后,输出结果符合预期:
- 行1:
unique_overlap为24600s (~6.83 hours),对应6小时50分钟 - 行2:
unique_overlap为32400s (~9 hours),对应9小时
代码说明
- 辅助函数
calc_unique_overlap:- 生成主时间区间,计算每个子区间与主区间的重叠部分
- 使用
reduce(..., union)合并重叠/相邻区间,自动消除重复部分 - 计算合并后所有区间的总时长,返回
duration类型
- 数据框处理:
- 用
rowwise()逐行处理数据 - 转换结果为易读的小时+分钟格式,便于查看
- 用
内容的提问来源于stack exchange,提问作者Indescribled
相关产品推荐
相关产品推荐

