在R中的数据框中插入值为零的行

3
考虑这样一个碎片化的数据集:
   ID       Date Value
1   1 2012-01-01  5065
4   1 2012-01-04  1508
5   1 2012-01-05  9489
6   1 2012-01-06  7613
7   2 2012-01-07  6896
8   2 2012-01-08  2643
11  3 2012-01-02  7294
12  3 2012-01-03  8726
13  3 2012-01-04  6262
14  3 2012-01-05  2999
15  3 2012-01-06 10000
16  3 2012-01-07  1405
18  3 2012-01-09  8372

注意到数据集中缺少(2,3,9,10,17)的观测值。我想要的是,用"Value"=0填补数据集中一些缺失的数据,如下所示:

   ID       Date Value
1   1 2012-01-01  5920
2   1 2012-01-02     0
3   1 2012-01-03     0
4   1 2012-01-04  8377
5   1 2012-01-05  7810
6   1 2012-01-06  6452
7   2 2012-01-07  3483
8   2 2012-01-08  5426
9   2 2012-01-09     0
11  3 2012-01-02  7854
12  3 2012-01-03  1948
13  3 2012-01-04  7141
14  3 2012-01-05  5402
15  3 2012-01-06  6412
16  3 2012-01-07  7043
17  3 2012-01-08     0
18  3 2012-01-09  3270

重点是只有在有相同(分组)ID的过去观察结果时才应该插入零。由于完整数据集非常大,我想避免任何循环。
有什么建议吗?要重现数据框,请参见以下内容:
df <- data.frame(matrix(0, nrow = 18, ncol = 3,
                  dimnames = list(NULL, c("ID","Date","Value"))) )
df[,1] = c(1,1,1,1,1,1,2,2,2,3,3,3,3,3,3,3,3,3) 
df[,2] = seq(as.Date("2012-01-01"),
             as.Date("2012-01-9"), 
             by=1)
df[,3] = sample(1000:10000,18,replace=T)
df = df[-c(2,3,9,10,17),]

你想按照ID分组来做这件事吗? - Rui Barradas
我想这是最有意义的,是的。 - Lucas E
这个问题会有所帮助:https://stackoverflow.com/questions/53674579/how-to-check-if-an-id-comes-into-data-on-a-particular-date-that-it-stays-until-a/53674919#53674919 - Mike
3个回答

6

Tidyverse有一个很好用的函数complete,可以轻松扩展数据。我们还可以使用fill参数在同一步骤中将NAs替换为零。

library(tidyverse)

df %>% group_by(ID) %>% 
  complete(Date = seq(min(Date), max(Date), "day"), fill = list(Value = 0)) 

# A tibble: 16 x 3
# Groups:   ID [3]
      ID Date       Value
   <dbl> <date>     <dbl>
 1     1 2012-01-01  1047
 2     1 2012-01-02     0
 3     1 2012-01-03     0
 4     1 2012-01-04  8147
 5     1 2012-01-05  1359
 6     1 2012-01-06  1892
 7     2 2012-01-07  3362
 8     2 2012-01-08  8988
 9     3 2012-01-02  2731
10     3 2012-01-03  9794

...

4

这里已经有一些很好的答案了,但我建议查看 padr 包。

library(dplyr)
library(padr)

df %>% 
  pad(start_val = as.Date("2012-01-01"),
      end_val =   as.Date("2012-01-09"),
      group = "ID") %>% 
  fill_by_value(Value)

该包还提供了一些非常直观的函数来总结日期列。


有趣,是否有一种简单的方法可以根据组动态地使完成范围变化?例如,ID == 1 中的最大值为 "2012-01-07",而对于 ID == 3,最大值为 "2012-01-10"。在此解决方案中,我们统一扩展每个组,但是我们能否根据组的 min/max 值动态扩展每个组呢? - Mako212
很高兴了解到padr包。 - Rui Barradas
1
如果您没有指定 start_valend_valpad 函数应自动调整以查找每个组的 min/max 日期!此外,如果您愿意,pad 将尊重 dplyr::group_by 而不是在 pad 中指定为参数。 - Dave Gruenewald
1
我喜欢这个,非常易读简洁,很高兴知道这个包!df %>% group_by(ID) %>% pad() %>% replace_na(list(Value = 0)) - Mako212
@Mako212 很高兴能帮忙! - Dave Gruenewald
显示剩余2条评论

3
以下是基于R的解决方案。它使用split将输入分成子数据框,然后使用lapply处理每个子数据框。
result <- lapply(split(df, df$ID), function(DF){
  Date <- seq(min(DF$Date), max(DF$Date), by = "days")
  DF2 <- data.frame(ID = rep(DF$ID[1], length.out = length(Date)))
  DF2$Date <- Date
  DF2$Value <- 0
  DF2$Value[Date %in% DF$Date] <- DF$Value
  DF2
})

result <- do.call(rbind, result)
row.names(result) <- NULL
result

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接