如何在R语言中跨年份按年度周段对日期分组?
按年度内7天周期统一分组的实现方案
核心需求
将不同年份数据集里的日期,按年度内7天区间划分,且不同年份的同区间日期(如2020-02-21与2021-02-21)归属同一分组,组标签格式为MM-DD至MM-DD。
预处理:清理无效日期
示例数据中存在2020-02-31、2021-02-29这类无效日期,需先修正为有效日期,否则无法转换为Date类型:
# 修正x1的无效日期 x1$day[x1$day == "2020-02-31"] <- "2020-02-29" x1$day <- as.Date(x1$day, "%Y-%m-%d") # 修正x2的无效日期 x2$day[x2$day == "2021-02-31"] <- "2021-02-28" x2$day[x2$day == "2021-02-29"] <- "2021-02-28" x2$day <- as.Date(x2$day, "%Y-%m-%d")
方法一:按年度连续7天分组(从每年1月1日起算)
基于日期的年内日序切割,确保每年的第1-7天、8-14天等区间标签统一。
library(lubridate) # 定义分组函数 group_by_yearly_7days <- function(df) { # 计算年内第几天 df$yday <- yday(df$day) # 生成7天间隔的切割点(覆盖闰年366天) breaks <- seq(1, 367, by = 7) # 切割年内日序,左闭右开区间 df$group_interval <- cut(df$yday, breaks = breaks, include.lowest = TRUE, right = FALSE) # 提取区间起始日序,转换为对应日期并生成标签 start_yday <- as.integer(gsub("\\((\\d+),.*", "\\1", df$group_interval)) start_yday[start_yday == 0] <- 1 # 修正第一组的起始值 start_date <- as.Date(paste0(year(df$day), "-01-01")) + start_yday - 1 end_date <- start_date + 6 df$week_group <- paste0(format(start_date, "%m-%d"), "至", format(end_date, "%m-%d")) # 移除中间变量(可选) df <- df[, !names(df) %in% c("yday", "group_interval")] return(df) } # 批量处理数据集 x1_processed <- group_by_yearly_7days(x1) x2_processed <- group_by_yearly_7days(x2)
方法二:按自然周对齐分组(匹配示例区间)
如果需要像示例中2020-01-17归属01-15至01-21这类自然周区间,可通过将所有日期映射到同一基准年(如闰年2020),再按周切割,确保不同年份的同周区间标签一致。
library(lubridate) # 定义分组函数,可指定周起始日(1=周一,7=周日,示例中用4=周三) group_by_aligned_week <- function(df, week_start = 4) { # 将日期映射到基准年(2020为闰年,覆盖所有日期) base_day <- ymd(paste0(2020, "-", format(df$day, "%m-%d"))) # 按周切割,指定周起始日 df$cut_group <- cut(base_day, breaks = "week", week_start = week_start) # 提取区间并生成统一标签 df$week_group <- gsub("2020-", "", df$cut_group) df$week_group <- gsub("[\\(\\)]", "", df$week_group) df$week_group <- gsub(",", "至", df$week_group) # 移除中间变量(可选) df <- df[, !names(df) %in% "cut_group"] return(df) } # 处理数据集,示例中周起始为周三(week_start=4) x1_processed <- group_by_aligned_week(x1) x2_processed <- group_by_aligned_week(x2)
验证结果
处理后,x1中的2020-01-17与x2中的2021-01-17会被分到同一分组01-15至01-21,符合需求。
内容的提问来源于stack exchange,提问作者MatthewR
相关产品推荐
相关产品推荐

