如何根据索引日期的时间段填充按 ID 分组的缺失值

How to fill missing values grouped on id and based on time period from index date

我想根据 ID 组内的一段时间为 data.frame 填充缺失值。

对于同一 ID 组中的最新 registration_dat,我想填写 ID 组中的先前值,但前提是 registration_dat 与最新的 [=26] 相差 1 年以内=] 在 ID 组中。

我的数据示例:

ID registration_dat  value1      value2
1  2020-03-04          NA          NA
1  2019-05-06          33          25
1  2019-01-02          32          21
3  2021-10-31          NA          NA
3  2018-10-12          33          NA
3  2018-10-10          25          35
4  2020-01-02          NA          NA
4  2019-10-31          32          83
4  2019-09-20          33          56
8  2019-12-12          NA          NA
8  2019-10-31          NA          43
8  2019-08-12          32          46

期望的输出:

ID registration_dat  value1      value2
1  2020-03-04          33          25
1  2019-05-06          33          25
1  2019-01-02          32          21
3  2021-10-31          NA          NA
3  2018-10-12          33          NA
3  2018-10-10          25          35
4  2020-01-02          32          83
4  2019-10-31          32          83
4  2019-09-20          33          56
8  2019-12-12          32          43
8  2019-10-31          NA          43
8  2019-08-12          32          46

我稍后会过滤数据,以便根据最新的注册日期获得一个唯一 ID,并且我希望这一行的缺失数据尽可能少,因此我想对数据框中的所有列执行此操作。但是,如果 NA 值与最新注册日期相差超过 1 年,我不希望用以前日期的值填充 NA 值。我的数据框有 14 列和 300 万多行,所以我需要它处理比示例中显示的大得多的 data.frame。

如果有任何想法,我将不胜感激!

您可以制作一个小函数(f,如下所示)来处理每个值列。

  1. 做一个分组ID,生成一个rowid(这只是为了保留你原来的顺序)
dat <- dat %>% 
  mutate(rowid = row_number()) %>% 
  arrange(registration_dat) %>% 
  group_by(ID)
  1. 创建一个包含 dfval 列的函数,以及 returns 并用 val 固定
  2. 更新 df
f <- function(df, val) {
  bind_rows(
    df %>% filter(is.na({{val}}) & row_number()!=n()),
    df %>% filter(!is.na({{val}}) | row_number()==n()) %>% 
      mutate({{val}} := if_else(is.na({{val}}) & registration_dat-lag(registration_dat)<365, lag({{val}}),{{val}}))
  )
}
  1. 将函数应用于感兴趣的列
dat = f(dat,value1)
dat = f(dat,value2)
  1. 如果需要,恢复原始订单
dat %>% arrange(rowid) %>% select(-rowid)

输出:

      ID registration_dat value1 value2
   <int> <date>            <int>  <int>
 1     1 2020-03-04           33     25
 2     1 2019-05-06           33     25
 3     1 2019-01-02           32     21
 4     3 2021-10-31           NA     NA
 5     3 2018-10-12           33     NA
 6     3 2018-10-10           25     35
 7     4 2020-01-02           32     83
 8     4 2019-10-31           32     83
 9     4 2019-09-20           33     56
10     8 2019-12-12           32     46
11     8 2019-10-31           NA     43
12     8 2019-08-12           32     46

更新:

OP 想要每个 ID 的最后一行(即最后 registration_dat)。有 300 万行和 14 个值列,我会使用 data.table 并执行如下操作:

library(data.table)

f <- function(df) {
  df = df[df[1,registration_dat]-registration_dat<=365]
  df[1,value:=df[2:.N][!is.na(value)][1,value]][1]
}

dcast(
  melt(setDT(dat), id=c("ID", "registration_dat"))[order(-registration_dat),f(.SD), by=.(ID,variable)],
  ID+registration_dat~variable, value.var="value"
)

输出:

      ID registration_dat value1 value2
   <int>           <Date>  <int>  <int>
1:     1       2020-03-04     33     25
2:     3       2021-10-31     NA     NA
3:     4       2020-01-02     32     83
4:     8       2019-12-12     32     43

您可以使用across()同时操作多个列。请注意,我使用 date1 - years(1) <= date2 而不是 date1 - 365 <= date2 来确定日期是否在最近日期的 1 年内,这可以考虑闰年(366 天)。

library(dplyr)
library(lubridate)

df %>%
  group_by(ID) %>%
  arrange(desc(registration_dat), .by_group = TRUE) %>%
  mutate(across(starts_with("value"),
    ~ if_else(row_number() == 1 & is.na(.x) & registration_dat - years(1) <= registration_dat[which.max(!is.na(.x))],
              .x[which.max(!is.na(.x))], .x))) %>%
  ungroup()

# # A tibble: 12 x 4
#       ID registration_dat value1 value2
#    <int> <date>            <int>  <int>
#  1     1 2020-03-04           33     25
#  2     1 2019-05-06           33     25
#  3     1 2019-01-02           32     21
#  4     3 2021-10-31           NA     NA
#  5     3 2018-10-12           33     NA
#  6     3 2018-10-10           25     35
#  7     4 2020-01-02           32     83
#  8     4 2019-10-31           32     83
#  9     4 2019-09-20           33     56
# 10     8 2019-12-12           32     43
# 11     8 2019-10-31           NA     43
# 12     8 2019-08-12           32     46

数据
df <- structure(list(ID = c(1L, 1L, 1L, 3L, 3L, 3L, 4L, 4L, 4L, 8L,
8L, 8L), registration_dat = structure(c(18325, 18022, 17898,
18931, 17816, 17814, 18263, 18200, 18159, 18242, 18200, 18120
), class = "Date"), value1 = c(NA, 33L, 32L, NA, 33L, 25L, NA,
32L, 33L, NA, NA, 32L), value2 = c(NA, 25L, 21L, NA, NA, 35L,
NA, 83L, 56L, NA, 43L, 46L)), class = "data.frame", row.names = c(NA,-12L))