R语言通过平滑峰值填充时间序列NA值的技术咨询
R时间序列连续NA按峰值均分填充实现方案
测试数据
df <- data.frame(date = seq(from=as.POSIXct(as.Date("2020-10-01")), to= as.POSIXct(as.Date("2020-10-02")) , by = 'hour'), val = c(15,20,18,22,17,NA,NA,NA,80,14,23,16,19,21,NA,NA,60,18,15,20,22,19,NA,35,18))
实现思路
核心逻辑严格匹配需求规则:
- 用游程编码识别连续NA段,每段连续NA和其后紧邻的峰值归为同一分组
- 峰值除以分组总长度(连续NA个数+1个峰值位)得到均分值
- 把分组内所有NA位置和原峰值位置统一替换为均分值,全程保证序列总和不变,同时峰值拆分后序列无突兀跳变,最大程度保留原序列趋势、季节性特征。
实现代码
# base R实现,无需额外依赖包 # 1. 游程编码识别连续NA段 rle_val <- rle(is.na(df$val)) # 2. 定位所有连续NA段的索引 na_runs <- which(rle_val$values) # 3. 遍历处理每一组NA+峰值分组 for (i in seq_along(na_runs)) { # 计算当前NA段的起止行号 na_start <- ifelse(na_runs[i] == 1, 1, sum(rle_val$lengths[1:(na_runs[i]-1]) + 1 na_end <- sum(rle_val$lengths[1:na_runs[i]]) # 取对应峰值 peak_val <- df$val[na_end + 1] # 计算均分值 group_total <- na_end - na_start + 2 avg_val <- peak_val / group_total # 批量替换分组内所有值 df$val[na_start:(na_end + 1)] <- avg_val }
效果验证
# 对比填充前后总和 original_sum <- sum(df$val, na.rm = TRUE) filled_sum <- sum(df$val) cat("原序列非NA总和:", original_sum, "\n填充后序列总和:", filled_sum, "\n")
运行后可验证两者数值完全相等,符合总和不变要求。
内容的提问来源于stack exchange,提问作者DAL
相关产品推荐
相关产品推荐

