R语言实现分时段滑动平均填补气象数据缺失值
嘿,我明白你的问题了!之前用rollapply之类的函数没搞定,核心原因是没抓住「只取对应时刻数据」这个关键点——你需要先把每天同一时段的观测归为一组,再在每组内做滑动平均,而不是对整个连续时间序列用大窗口。我给你分两步解决:先搞定示例,再扩展到你实际的30分钟14天滑动平均需求。
先解决你的示例问题
你的示例要求用6小时滑动平均补缺,偶数时段用偶数数据填补,奇数时段用奇数数据填补。我们先给每个小时打上「奇偶时段标识」,再分组处理:
library(dplyr) library(zoo) # 你的示例数据 data <- data.frame( hour = c(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23), values = c(1,3,1,3,1,3,1,3,1,NA,1,3,1,3,NA,3,1,3,1,3,1,3,1,3) ) # 第一步:给每个小时打上奇偶时段标识(0=偶数时段,1=奇数时段) data <- data %>% mutate(period_id = hour %% 2) # 第二步:定义补缺函数,包含最小有效数据点判断 fill_with_rollmean <- function(x, window_width, min_valid) { rollapply( x, width = window_width, align = "center", # 中心对齐,取当前点前后的同时段数据 FUN = function(y) { valid_count <- sum(!is.na(y)) # 只有有效数据数达标才填补,否则返回NA if (valid_count >= min_valid) mean(y, na.rm = TRUE) else NA }, fill = NA # 首尾超出窗口的部分保持NA ) } # 第三步:按时段分组,应用补缺函数 data_filled <- data %>% group_by(period_id) %>% # 窗口宽度3=当前点+前后1个同时段数据(对应6小时跨度),最小有效数设为2 mutate(gap_fill = fill_with_rollmean(values, window_width = 3, min_valid = 2)) %>% ungroup() # 查看结果:hour=9的NA会被补为3,hour=14的NA会被补为1,符合你的预期 print(data_filled)
扩展到30分钟分辨率14天滑动平均需求
针对你实际的数月30分钟气象数据,核心思路是给每个30分钟时段打唯一标识(比如每天的第1到第48个30分钟),然后按标识分组,用14天的同时段数据做滑动平均:
library(dplyr) library(zoo) library(lubridate) # 假设你的数据框是df,包含datetime(POSIXct格式)和values列 # 第一步:给每个30分钟时段打唯一标识(1-48,对应每天的00:00到23:30) df <- df %>% mutate( period_id = (hour(datetime) * 2) + ifelse(minute(datetime) == 30, 2, 1) ) # 第二步:定义14天滑动平均补缺函数 fill_14day_rollmean <- function(x, window_width = 14, min_valid = 7) { rollapply( x, width = window_width, # 对应14天的同时段数据 align = "center", # 取当前天前后各6天+当天,共14个数据 FUN = function(y) { valid_count <- sum(!is.na(y)) if (valid_count >= min_valid) mean(y, na.rm = TRUE) else NA }, fill = NA # 首尾超出窗口的部分保持NA ) } # 第三步:按时段分组补缺 df_filled <- df %>% group_by(period_id) %>% mutate(values_filled = fill_14day_rollmean(values)) %>% ungroup()
关键注意事项
- 时间序列补全:如果你的原始数据有缺失的日期/时段,先要用
tidyr::complete(datetime = seq(min(datetime), max(datetime), by = "30 mins"))补全为连续的时间序列,否则分组后的序列会有间隔,滑动窗口会取到非连续的日期数据。 - 窗口调整:如果你要的是「前后7天」(共15个数据点:当天+前7天+后7天),把
window_width改成15即可,align="center"会自动匹配前后7个数据。 - 最小有效数:根据你的需求调整
min_valid参数,比如要求至少10个有效数据才填补,就设为10。
内容的提问来源于stack exchange,提问作者jls
相关产品推荐
相关产品推荐

