如何在R中基于ID和数据框计算多组指定时间窗口的移动平均值?
批量计算多组特定时间窗口的温度移动平均值解决方案
需求说明
为每个ID计算对应阶段日期前4天的温度平均值,要求时间窗口内必须包含完整的4天有效数据(无缺失、日期范围在温度数据的覆盖区间内),否则返回NA。例如ID A的阶段1结束日期为12,需计算9-12日的温度平均值;若结束日期超过温度数据的最大日期(12),或窗口起始日期小于1,均返回NA。
数据准备
ID阶段日期数据
IDDate <- data.frame(ID = c("A","B","C"), Stage1 = c(12, 13, 10), Stage2 = c(14, 30, 12))
| ID | 阶段1 | 阶段2 |
|---|---|---|
| A | 12 | 14 |
| B | 13 | 30 |
| C | 10 | 12 |
每日温度数据
IDTemp <- data.frame(Day = c(1:12), A = c(-3,-2,1,4,2,3,10,15,5,4,6,4), B = c(-4,2,0,3,12,10,9,8,9,3,1,2), C = c(4,1,2,5,5,2,3,2,1,5,6,1))
| 日期 | A | B | C |
|---|---|---|---|
| 1 | -3 | -4 | 4 |
| 2 | -2 | 2 | 1 |
| 3 | 1 | 0 | 2 |
| 4 | 4 | 3 | 5 |
| 5 | 2 | 12 | 5 |
| 6 | 3 | 10 | 2 |
| 7 | 10 | 9 | 3 |
| 8 | 15 | 8 | 2 |
| 9 | 5 | 9 | 1 |
| 10 | 4 | 3 | 5 |
| 11 | 6 | 1 | 6 |
| 12 | 4 | 2 | 1 |
解决方案
使用dplyr和tidyr包进行数据整理与批量计算,步骤如下:
- 加载依赖包
library(dplyr) library(tidyr)
- 转换温度数据为长格式(便于按ID和日期分组处理)
temp_long <- IDTemp %>% pivot_longer(cols = -Day, names_to = "ID", values_to = "Temperature")
- 转换ID阶段数据为长格式(将Stage1、Stage2转为行记录,并计算窗口起始日期)
stage_long <- IDDate %>% pivot_longer(cols = starts_with("Stage"), names_to = "Stage", values_to = "EndDay") %>% mutate(StartDay = EndDay - 3) # 前4天的起始日期为结束日期减3
- 合并数据并计算符合要求的平均值
result <- stage_long %>% left_join(temp_long, by = "ID") %>% # 筛选当前阶段窗口内的日期 filter(Day >= StartDay, Day <= EndDay) %>% # 按ID和阶段分组 group_by(ID, Stage) %>% # 检查窗口内是否有完整4天数据且无缺失,是则计算平均值,否则返回NA summarise(Average_Temp = ifelse(n() == 4 & all(!is.na(Temperature)), mean(Temperature), NA), .groups = "drop") %>% # 转换回宽格式,匹配预期结果结构 pivot_wider(names_from = Stage, values_from = Average_Temp, names_prefix = "阶段") %>% rename( "阶段1温度平均值" = "阶段Stage1", "阶段2温度平均值" = "阶段Stage2" )
结果验证
运行上述代码后,得到结果如下:
| ID | 阶段1温度平均值 | 阶段2温度平均值 |
|---|---|---|
| A | 4.75 | NA |
| B | NA | NA |
| C | 2.75 | 3.25 |
完全符合预期:
- ID A的阶段2结束日期14超出温度数据的最大日期12,返回NA;
- ID B的两个阶段结束日期均超出温度数据范围,均返回NA;
- ID C的两个阶段窗口均包含完整4天有效数据,计算得到对应平均值。
内容的提问来源于stack exchange,提问作者Wayne Schmitt
相关产品推荐
相关产品推荐

