在R中基于日期列按条件用最近非NA值填充列中NA
解决方案
核心逻辑
针对每个含NA的行,在指定范围内(当前日期前后30天)筛选非NA记录,按「日期差绝对值最小优先,差值相同时更早日期优先」的规则选取填充值;同时兼容分组数据场景。
代码实现(dplyr版,易读性强)
library(dplyr) # 加载示例数据并转换日期格式 df <- data.frame( dates = c("2023-09-01", "2023-09-02", "2023-09-05", "2023-09-06", "2023-09-10", "2023-09-11", "2023-09-14", "2023-09-16", "2023-09-20", "2023-09-27", "2023-09-28"), x = c(10, NA, 20, NA, NA, 30, NA, NA, NA, 40, NA) ) %>% mutate(dates = as.Date(dates)) # 执行填充(若有分组,添加group_by(你的分组列)即可) filled_df <- df %>% rowwise() %>% mutate( x_filled = ifelse(!is.na(x), x, { # 筛选当前日期前后30天内的非NA候选值 candidates <- filter(df, !is.na(x), dates >= !!cur_data()$dates - 30, dates <= !!cur_data()$dates + 30) # 按规则排序后取第一个值 candidates %>% mutate(diff_days = abs(dates - !!cur_data()$dates)) %>% arrange(diff_days, dates) %>% slice(1) %>% pull(x) }) ) %>% ungroup() # 查看结果 filled_df$x_filled # 输出:[1] 10 10 20 20 30 30 30 30 40 40 40
分组场景适配
如果数据存在分组(比如有group列),只需在rowwise()前添加分组逻辑:
# 模拟分组数据 grouped_df <- df %>% mutate(group = rep(c("A", "B"), length.out = nrow(df))) # 分组填充 filled_grouped_df <- grouped_df %>% group_by(group) %>% rowwise() %>% mutate( x_filled = ifelse(!is.na(x), x, { candidates <- filter(cur_group(), !is.na(x), dates >= !!cur_data()$dates - 30, dates <= !!cur_data()$dates + 30) candidates %>% mutate(diff_days = abs(dates - !!cur_data()$dates)) %>% arrange(diff_days, dates) %>% slice(1) %>% pull(x) }) ) %>% ungroup()
大数据量优化方案(data.table版,性能更高)
如果数据量极大,逐行处理效率偏低,可使用data.table的滚动连接特性:
library(data.table) setDT(df)[, dates := as.Date(dates)] # 提取非NA记录作为参考表 ref_df <- df[!is.na(x)] # 先向后找最近的候选值,再向前补充,自动处理优先级 df[, x_filled := x] df[ref_df, x_filled := i.x, on = .(dates <= dates), roll = -30] df[ref_df, x_filled := fcoalesce(x_filled, i.x), on = .(dates >= dates), roll = 30] # 查看结果 df$x_filled
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

