如何用dplyr的group_by()按n天分组计算样本n日平均值?
基于dplyr实现自定义n天间隔的平均值计算
问题描述
我曾用dplyr的group_by()函数计算样本结果的周、月、年度平均值,但在计算4日或10日这类自定义天数的平均值时遇到了难题。此外我的数据存在日期间隔问题,需要筛选出间隔在±n天内的数据计算平均值后再合并。
样本数据
data_test <- tibble('WBID' = c("10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "11A", "11A", "11A", "11A", "11A", "11A", "11A", "11A", "11A", "11A", "11A", "11A", "12A", "12A", "12A", "12A", "12A", "12A", "12A", "12A", "12A", "12A", "12A", "12A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A"), 'Station' = c("A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C"), 'SampleDate' = c('2010-03-01','2010-03-02', '2010-03-03','2010-03-04','2010-03-05','2010-03-06','2011-03-01','2011-03-02','2011-03-03','2011-03-04','2011-03-05','2011-03-06', '2010-03-01','2010-03-02', '2010-03-03','2010-03-04','2010-03-05','2010-03-06','2011-03-01','2011-03-02','2011-03-03','2011-03-04','2011-03-05','2011-03-06', '2010-03-01','2010-03-02', '2010-03-03','2010-03-04','2010-03-05','2010-03-06','2011-03-01','2011-03-02','2011-03-03','2011-03-04','2011-03-05','2011-03-06', '2010-03-01','2010-03-02', '2010-03-03','2010-03-04','2010-03-05','2010-03-06','2011-03-01','2011-03-02','2011-03-03','2011-03-04','2011-03-05','2011-03-06'), 'Result' = c(7, 7, 2, 1, 5, 7, 7, 1, 5, 2, 4, 7, 1, 7, 9, 3, 9, 4, 1, 9, 3, 6, 4, 3, 8, 2, 9, 7, 3, 6, 1, 1, 1, 2, 6, 8, 4, 1, 7, 8, 1, 5, 3, 4, 6, 3, 2, 3))
原有周均值计算代码
# 按站点计算7天平均值 data_test <- data_test %>% group_by(WBID, Station, Week = format(SampleDate, "%Y-%U")) %>% mutate(Result_7day = mean(Result))
期望结果(n=4时)
data_test <- tibble('WBID' = c("10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "11A", "11A", "11A", "11A", "11A", "11A", "11A", "11A", "11A", "11A", "11A", "11A", "12A", "12A", "12A", "12A", "12A", "12A", "12A", "12A", "12A", "12A", "12A", "12A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A", "10A"), 'Station' = c("A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C"), 'SampleDate' = c('2010-03-01','2010-03-02', '2010-03-03','2010-03-04','2010-03-05','2010-03-06','2011-03-01','2011-03-02','2011-03-03','2011-03-04','2011-03-05','2011-03-06', '2010-03-01','2010-03-02', '2010-03-03','2010-03-04','2010-03-05','2010-03-06','2011-03-01','2011-03-02','2011-03-03','2011-03-04','2011-03-05','2011-03-06', '2010-03-01','2010-03-02', '2010-03-03','2010-03-04','2010-03-05','2010-03-06','2011-03-01','2011-03-02','2011-03-03','2011-03-04','2011-03-05','2011-03-06', '2010-03-01','2010-03-02', '2010-03-03','2010-03-04','2010-03-05','2010-03-06','2011-03-01','2011-03-02','2011-03-03','2011-03-04','2011-03-05','2011-03-06'), 'Result' = c(7, 7, 2, 1, 5, 7, 7, 1, 5, 2, 4, 7, 1, 7, 9, 3, 9, 4, 1, 9, 3, 6, 4, 3, 8, 2, 9, 7, 3, 6, 1, 1, 1, 2, 6, 8, 4, 1, 7, 8, 1, 5, 3, 4, 6, 3, 2, 3), 'Result_4day' = c(4.25, 4.25, 4.25, 4.25, 3.75, 3.75, 3.75, 3.75, 3.75, 3.75, 3, 4.5, 5, 5, 5, 5, 7, 6.25, 4.75, 4.75, 4.75, 4.75, 5.5, 4, 6.5, 6.5, 6.5, 6.5, 5.25, 6.25, 1.25, 1.25, 1.25, 1.25, 2.5, 4.25, 5, 5, 5, 5, 4.25, 5.25, 4, 4, 4, 4, 3.75, 3.5))
解决方案
方案1:基于固定n天块的分组(适合连续日期)
先将SampleDate转换为日期类型,再计算每个日期所属的n天分组块,最后用group_by分组计算平均值,完全贴合你期望的固定块分组逻辑:
library(dplyr) library(lubridate) # 转换日期格式为Date类型 data_test <- data_test %>% mutate(SampleDate = ymd(SampleDate)) # 定义需要计算的天数n n <- 4 # 按WBID、Station和n天块分组计算平均值 data_test <- data_test %>% group_by(WBID, Station, # 生成n天分组键:以每个分组内的最早日期为起点,每n天划分为一个块 n_day_block = floor_date(SampleDate - min(SampleDate, na.rm = TRUE), paste(n, "days")) + min(SampleDate, na.rm = TRUE)) %>% mutate(Result_nday = mean(Result)) %>% ungroup()
方案2:处理日期间隔的滑动窗口平均值(±n天范围)
如果数据存在日期间断,需要计算每个日期前后±n天内所有有效数据的平均值,可以用rowwise结合范围筛选实现:
n <- 4 data_test <- data_test %>% group_by(WBID, Station) %>% rowwise() %>% # 筛选当前日期前后n天内的所有Result值并计算平均 mutate(Result_nday_slide = mean(Result[between(SampleDate, !!SampleDate - days(n), !!SampleDate + days(n))])) %>% ungroup()
结果验证
对于n=4的场景,方案1可以直接得到你提供的期望结果;如果数据存在日期间隔,方案2会自动忽略超出±4天范围的数据,只计算有效区间内的平均值,更适配你的补充需求。
内容的提问来源于stack exchange,提问作者nps-randy
相关产品推荐
相关产品推荐

