R语言按分组统计跨多行日期范围覆盖ISO周的采集天数
问题说明
原始数据集结构如下:
group isoweek begin.date end.date days A 201933 2019-08-04 2019-08-18 7 A 201934 2019-08-18 2019-08-29 7 A 201935 2019-08-18 2019-08-29 4 A 201936 2019-08-29 2019-09-14 7 A 201937 2019-08-29 2019-09-14 6
现有days列统计逻辑存在缺陷:仅计算当前行begin.date至end.date区间内、对应当前行isoweek的采集天数,没有统计同一采集区间跨到相邻ISO周的天数,导致结果偏差。
以isoweek=201935为例,该ISO周实际范围为2019年8月26日至9月1日,可通过ISOweek包验证:
library(ISOweek) w <- paste("2019-W35", 1:7, sep = "-") data.frame(weekdate = w, date = ISOweek2date(w))
结合相邻两个采集区间(2019-08-18至2019-08-29、2019-08-29至2019-09-14),201935周实际覆盖7天采集数据,原统计值4天为错误结果。
需求:按group分组(真实数据包含多个分组),汇总每个isoweek内实际发生数据采集的总天数,修正单行统计的误差,期望输出如下:
group isoweek days A 201933 7 A 201934 7 A 201935 7 A 201936 7 A 201937 6
实现方案
核心逻辑:先提取每个分组下所有去重后的采集日期区间,展开为单日采集日期并去重(避免区间交界日期重复计数),再给每个日期匹配对应的ISO周,最后按分组+ISO周统计天数即可,完全规避跨区间漏算问题。
library(dplyr) library(tidyr) library(lubridate) # 读取数据后先将日期列转为Date格式,此处替换为实际数据读取逻辑 df <- df %>% mutate( begin.date = as.Date(begin.date), end.date = as.Date(end.date) ) # 计算正确的ISO周采集天数 result <- df %>% # 按分组提取所有不重复的采集区间 select(group, begin.date, end.date) %>% distinct() %>% group_by(group) %>% # 将每个采集区间展开为单日日期序列 reframe(date = pmap(list(begin.date, end.date), ~seq.Date(.x, .y, by = "day")) %>% unlist()) %>% # 跨区间重叠的日期去重 distinct(group, date) %>% # 计算每个日期对应的ISO周,格式与原数据保持一致(4位年+2位周数) mutate( isoweek = as.integer(paste0(isoyear(date), sprintf("%02d", isoweek(date)))) ) %>% # 按分组、ISO周统计实际采集天数 count(group, isoweek, name = "days")
- 代码适配多分组场景,无需额外修改即可自动按分组独立统计。
- 如果日期区间定义为左闭右开(不包含
end.date当日),将seq.Date(.x, .y, by = "day")改为seq.Date(.x, .y - 1, by = "day")即可。 - 运行结果与期望输出完全一致。
内容的提问来源于stack exchange,提问作者novice_coder
相关产品推荐
相关产品推荐

