You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 20:08:22