在R中计算分组id指定7天日期窗口的滚动求和最大值
问题描述
现有包含id、date、value字段的数据表如下:
| id | date | value |
|---|---|---|
| 7 | 2023-01-01 | 1 |
| 7 | 2023-01-03 | 1 |
| 7 | 2023-01-04 | 3 |
| 7 | 2023-01-05 | 2 |
| 7 | 2023-01-06 | 1 |
| 7 | 2023-01-07 | 5 |
| 7 | 2023-01-10 | 3 |
| 7 | 2023-01-14 | 2 |
| 15 | 2023-01-01 | 1 |
| 15 | 2023-01-02 | 1 |
| 15 | 2023-01-04 | 2 |
| 15 | 2023-01-07 | 2 |
| 15 | 2023-01-12 | 1 |
| 15 | 2023-01-13 | 1 |
| 15 | 2023-01-14 | 10 |
需求是为每个id计算任意7天日期窗口内的滚动求和最大值(窗口示例:1/1至1/7、1/2至1/8等)。已知预期结果:
- id=7的最大值为14(对应窗口1/4-1/10,求和3+2+1+5+3)
- id=15的最大值为12(对应窗口1/8-1/14,求和1+1+10)
尝试用runner库实现时未得到预期结果,补充说明:若最大值不在前几个窗口时,以下代码可正常运行:
library(runner) df %>% group_by(id) %>% mutate(rsum = runner(value, k=7, idx=date, f=function(x) sum(x), na_pad=T)) %>% filter(!is.na(rsum)) %>% summarise(max_rsum = max(rsum))
问题原因
你使用的代码核心问题在于:k=7在runner中默认是取最近7个观测值,而非7天日期区间。即便指定了idx=date,k=7依然按观测数量计算窗口,导致窗口范围不符合需求。
解决方案
以下提供两种符合需求的实现方式:
方案一:用runner指定日期区间窗口
通过at参数明确窗口终点,结合k=7定义7天日期范围,计算每个终点对应的窗口求和:
library(runner) library(dplyr) # 确保date为日期类型 df$date <- as.Date(df$date) df %>% group_by(id) %>% # 以现有日期作为窗口终点 mutate(window_end = date) %>% # 计算每个终点往前7天内的value求和 mutate(rolling_sum = runner( x = value, idx = date, at = window_end, f = sum, k = 7, lag = 0 # 窗口范围为[window_end-6天, window_end] )) %>% # 提取每个id的最大求和值 summarise(max_rsum = max(rolling_sum))
方案二:补全日期序列后计算滚动求和
先补全每个id的连续日期(缺失日期的value填0),再用滑动窗口求和:
library(dplyr) library(tidyr) library(zoo) df$date <- as.Date(df$date) df %>% group_by(id) %>% # 生成id对应的所有连续日期 complete(date = seq(min(date), max(date), by = "day")) %>% # 缺失日期的value填充为0 replace_na(list(value = 0)) %>% # 计算7天滚动求和(窗口为当前日期及前6天) mutate(rolling_sum = rollsum(value, k = 7, align = "right", fill = NA)) %>% # 提取最大值 summarise(max_rsum = max(rolling_sum, na.rm = TRUE))
两种方案均能得到预期结果:id=7的max_rsum为14,id=15的max_rsum为12。
内容的提问来源于stack exchange,提问作者Bea
相关产品推荐
相关产品推荐

