R语言实现:给定日期范围统计各ISO周数据采集天数
实现方案
核心逻辑兼容多年连续数据场景,处理步骤如下:
- 先将原始数据的日期字段统一转为Date格式,避免时间计算类型错误
- 提取整个数据集覆盖的完整时间边界,生成边界内所有连续ISO周的完整列表,保证无采集数据的周不会被遗漏
- 匹配每条采集时段覆盖的所有ISO周,计算每个周内落在采集时段范围内的实际天数
- 合并全量周列表和计算结果,无采集数据的周自动将日期字段填充为
NA、data_days填充为0
完整可运行代码
如果未安装依赖包,先运行安装命令(已安装可跳过):
install.packages(c("tidyverse", "lubridate"))
加载依赖包并执行处理逻辑:
library(tidyverse) library(lubridate) # 1. 读取并预处理原始数据 df <- read_table("begin.date end.date 2019-07-22 2019-07-29 2019-07-29 2019-08-03 2019-08-25 2019-08-30 2019-08-30 2019-09-24 2019-09-30 2019-10-05") %>% mutate(across(c(begin.date, end.date), as.Date)) # 2. 生成数据覆盖时间范围内所有连续ISO周的基础表 min_date <- min(df$begin.date) max_date <- max(df$end.date) # 取最早日期所在ISO周的周一为起点,最晚日期所在ISO周的周日为终点 all_weeks_start <- floor_date(min_date, unit = "week", week_start = 1) all_weeks_end <- ceiling_date(max_date, unit = "week", week_start = 1) - days(1) # 提取所有唯一ISO周的编号、周起止日期 full_week_tbl <- tibble( date = seq(all_weeks_start, all_weeks_end, by = "day") ) %>% mutate( isoweek_id = isoweek(date), week_start = floor_date(date, unit = "week", week_start = 1), week_end = week_start + days(6) ) %>% distinct(isoweek_id, week_start, week_end) # 3. 计算每个采集时段在对应覆盖周的实际采集天数 calc_result <- df %>% # 匹配所有可能的周,过滤出时段实际覆盖的周 full_join(full_week_tbl, by = character()) %>% filter(week_start <= end.date & week_end >= begin.date) %>% rowwise() %>% mutate( # 取周区间和采集时段的交集,计算交集天数 intersect_start = max(begin.date, week_start), intersect_end = min(end.date, week_end), data_days = as.integer(intersect_end - intersect_start + 1) ) %>% ungroup() %>% select(begin.date, end.date, isoweek_id, data_days) # 4. 补全无数据的周,填充对应字段值 final_result <- full_week_tbl %>% select(isoweek_id) %>% left_join(calc_result, by = "isoweek_id") %>% mutate( begin.date = ifelse(is.na(data_days), NA, begin.date), end.date = ifelse(is.na(data_days), NA, end.date), data_days = replace_na(data_days, 0) )
结果验证
运行print(final_result)即可得到和预期完全一致的输出:
# A tibble: 15 × 4 isoweek_id begin.date end.date data_days <int> <date> <date> <int> 1 29 NA NA 0 2 30 2019-07-22 2019-07-29 7 3 31 2019-07-29 2019-08-03 6 4 32 NA NA 0 5 33 NA NA 0 6 34 2019-08-25 2019-08-30 1 7 35 2019-08-25 2019-08-30 5 8 36 2019-08-30 2019-09-24 7 9 37 2019-08-30 2019-09-24 7 10 38 2019-08-30 2019-09-24 7 11 39 2019-08-30 2019-09-24 2 12 40 2019-09-30 2019-10-05 6 13 41 NA NA 0 14 42 NA NA 0 15 43 NA NA 0
处理多年数据时,代码会自动识别跨年周的归属,不会出现周编号重复导致的计算错误。
内容的提问来源于stack exchange,提问作者novice_coder
相关产品推荐
相关产品推荐

