R语言按日期滚动计算截至当日前分星期小时平均销售额
dplyr 按日期滚动版本化分组统计实现
你原有全量数据的统计逻辑可以直接复用,核心是给每个计算日期单独截取「当日之前的历史数据」作为计算输入,最终合并所有日期的计算结果即可。
原有全量统计的参考代码如下,后续滚动计算完全沿用这套口径:
# 原全量统计逻辑 df %>% group_by(Day_of_Week, Hour) %>% summarise( Average_Orders_Date_and_Hour = mean(Sales, na.rm = TRUE), .groups = "drop" ) %>% mutate(Percent_of_Total = Average_Orders_Date_and_Hour / max(Average_Orders_Date_and_Hour))
方法1:直观遍历实现(易读易修改)
逻辑最直白,适合数据量不大的场景,方便快速调整逻辑:
- 先取出数据集中所有唯一的日期,按时间先后排序
- 逐个遍历日期,每次筛选出早于当前日期的所有历史数据
- 对筛选出的历史数据跑原有统计逻辑,给结果加上当前版本日期标记
- 合并所有日期的统计结果,得到最终长表
完整代码:
library(dplyr) library(purrr) # 提取所有日期并升序排列 all_dates <- sort(unique(df$Date)) rolling_stat <- map_dfr(all_dates, function(cur_date){ # 截取当前日期之前的历史数据(不含当日) hist_df <- df %>% filter(Date < cur_date) # 跑原有分组统计逻辑 cur_res <- hist_df %>% group_by(Day_of_Week, Hour) %>% summarise( Average_Orders_Date_and_Hour = mean(Sales, na.rm = TRUE), .groups = "drop" ) %>% mutate(Percent_of_Total = Average_Orders_Date_and_Hour / max(Average_Orders_Date_and_Hour)) # 标记当前统计对应的版本日期 cur_res %>% mutate(version_date = cur_date) }) # 可选:过滤掉最早日期(无历史数据)的空结果 rolling_stat <- rolling_stat %>% filter(!is.na(Average_Orders_Date_and_Hour))
最终输出的结果里,每个version_date对应84行统计值(7个星期值*12个小时段),完全符合每日留存统计结果的需求。
方法2:嵌套累计实现(大数据量性能更优)
如果数据集时间跨度大、行数多,每次遍历全表筛选的效率偏低,可以用累计嵌套的方式减少重复数据扫描:
- 先按日期分组,把每日数据嵌套成子表
- 按时间顺序逐行累计拼接历史数据,维护滚动的历史数据池
- 对每个日期对应的历史数据池跑统计逻辑,最后展开成长表
完整代码:
library(dplyr) library(tidyr) library(purrr) rolling_stat <- df %>% # 按日期嵌套每日数据 nest(day_data = -Date) %>% arrange(Date) %>% # 逐行累计拼接历史数据 mutate( history_pool = accumulate(day_data, bind_rows, .init = NULL)[-n()-1], # 对每个历史池跑统计逻辑 stat_res = map(history_pool, function(hist){ hist %>% group_by(Day_of_Week, Hour) %>% summarise( Average_Orders_Date_and_Hour = mean(Sales, na.rm = TRUE), .groups = "drop" ) %>% mutate(Percent_of_Total = Average_Orders_Date_and_Hour / max(Average_Orders_Date_and_Hour)) }) ) %>% # 展开结果得到长表 select(version_date = Date, stat_res) %>% unnest(stat_res) %>% # 过滤最早日期的空结果 filter(!is.na(Average_Orders_Date_and_Hour))
注意事项
- 如果历史数据存在某星期/时段缺失的情况,可以在统计完成后加一行
complete(Day_of_Week, Hour, fill = list(Average_Orders_Date_and_Hour = 0))补全行,保证每个版本日期固定返回84行结果 - 核心统计口径和你原来的全量计算代码完全一致,不需要调整统计规则,避免口径偏差
- 如果需要排除异常值、加其他过滤条件,直接在原有统计逻辑的位置加就行,不需要改动滚动框架
内容的提问来源于stack exchange,提问作者hachiko
相关产品推荐
相关产品推荐

