在R中按组基于日期填充NA:取30天内最近非NA值(平局选早)
按ID分组基于日期填充NA值的解决方案
需求:对DataFrame中整数变量x的NA值,按id分组后进行填充,规则如下:
- 基于日期列,选取当前观测值前后30天内最近的非NA值
- 若存在多个非NA值与当前日期距离相同,选择日期更早的对应数值
- 此前找到的方法无法处理连续NA的情况,需要适配该场景
示例数据:
df <- data.frame( id=c(1,1,1,1,2,2,2,3,3,3,4,4), dates = c("2023-09-01", "2023-09-02", "2023-09-05", "2023-09-06","2023-09-10" , "2023-09-11", "2023-09-12", "2023-09-14", "2023-09-16", "2023-09-20", "2023-09-27", "2023-09-28"), x = c(10, NA, NA, 20, 20, NA, 30, 15, NA, NA, 40, NA) )
期望输出的x列结果:
x1 <- c(10, 10, 20, 20, 20, 20, 30, 15, 15, 15, 40, 40)
方法一:使用dplyr + lubridate实现
适合中小型数据集,代码可读性强:
library(dplyr) library(lubridate) library(purrr) # 转换日期格式为Date类型 df_processed <- df %>% mutate(dates = ymd(dates)) %>% group_by(id) %>% mutate(x_filled = map_dbl(row_number(), function(i) { # 非NA值直接保留 if (!is.na(x[i])) return(x[i]) current_date <- dates[i] # 筛选同组内前后30天的非NA记录 valid_records <- which(!is.na(x) & abs(dates - current_date) <= days(30)) # 无符合条件的记录则保留NA if (length(valid_records) == 0) return(NA) # 计算日期差,找到最小差值的最早记录 date_diffs <- abs(dates[valid_records] - current_date) min_diff_pos <- which(date_diffs == min(date_diffs))[1] x[valid_records[min_diff_pos]] })) %>% ungroup() # 查看填充结果 df_processed$x_filled
方法二:使用data.table实现
适合大数据集,运行效率更高:
library(data.table) setDT(df) # 转换日期格式 df[, dates := as.Date(dates)] # 按id分组处理NA填充 df[, x_filled := sapply(.I, function(i) { if (!is.na(x[i])) return(x[i]) current_date <- dates[i] # 筛选同组内前后30天的非NA记录 valid_dt <- .SD[!is.na(x) & abs(dates - current_date) <= 30] if (nrow(valid_dt) == 0) return(NA) # 计算日期差,取最小差值的最早记录 valid_dt[, diff := abs(dates - current_date)] valid_dt[diff == min(diff)][1, x] }), by = id] # 查看填充结果 df$x_filled
两种方法最终输出的x_filled列均与期望的x1一致。
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

