如何基于多段起止时间计算去重后的活跃总天数?
计算去重后的活跃总天数解决方案
问题背景
现有包含用户活跃周期起止时间的数据集,需要计算每个用户去重后的活跃总天数——即重叠或重复的日期区间只计数一次。原始代码直接累加各周期天数,导致重复计数,期望结果为 A=2,B=4,C=6。
原始数据
data <- data.frame( ID = c("A","A","B","B","C","C","C"), start = c("2022-09-01", "2022-09-01", "2022-09-04", "2022-09-05", "2022-09-25", "2022-09-30", "2022-09-30"), end = c("2022-09-01", "2022-09-02", "2022-09-05", "2022-09-07", "2022-09-27", "2022-09-30", "2022-10-02") )
问题分析
原代码直接计算每个周期的天数并累加,但未处理重叠/重复的日期区间:
- 比如ID A的两个区间
[2022-09-01,2022-09-01]和[2022-09-01,2022-09-02],原代码累加得到1+2=3,但实际去重后仅为2天。
解决方案
通过合并重叠/相邻的时间区间,再计算总天数,实现去重计数:
library(tidyverse) library(lubridate) # 转换日期格式为lubridate可处理的类型 data <- data %>% mutate( start = ymd(start), end = ymd(end) ) # 分组计算去重活跃天数 active_days_result <- data %>% group_by(ID) %>% # 将每个用户的所有活跃周期转为时间区间列表 summarise(intervals = list(interval(start, end)), .groups = "drop") %>% # 合并重叠或相邻的区间 mutate(merged_intervals = map(intervals, ~ reduce(., interval_union))) %>% # 计算每个合并后区间的天数并求和(+1是因为包含起止当天) mutate(active_days = map_dbl(merged_intervals, ~ sum(as.numeric(. / days(1)) + 1))) %>% # 保留所需列 select(ID, active_days) # 输出结果 print(active_days_result)
运行结果
# A tibble: 3 × 2 ID active_days <chr> <dbl> 1 A 2 2 B 4 3 C 6
代码逻辑说明
interval(start, end):将每个起止时间对转为lubridate时间区间对象;reduce(., interval_union):对每个用户的区间列表进行迭代合并,自动处理重叠或相邻的区间;as.numeric(. / days(1)) + 1:将合并后的区间转为天数(区间长度除以1天得到天数差,加1是因为要包含起止当天),最后求和得到去重后的总活跃天数。
内容的提问来源于stack exchange,提问作者KintensT
相关产品推荐
相关产品推荐

