【问题标题】:Insert rows with zeros in data frames in R [duplicate]在R中的数据框中插入带零的行[重复]
【发布时间】:2018-12-12 02:43:18
【问题描述】:

考虑这样一个碎片化的数据集:

   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),]

【问题讨论】:

标签: r dataframe row zero


【解决方案1】:

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

...

【讨论】:

    【解决方案2】:

    这里已经有一些可靠的答案,但我建议查看包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的值动态扩展每个组吗?
    • 很高兴知道包裹padr
    • 如果您没有指定start_valend_valpad 函数应该会自动调整以找到每个组的min/max 日期!此外,如果您愿意,pad 将尊重 dplyr::group_by - 而不是在 pad 中指定为参数
    • @DaveGruenewald 很好,很漂亮
    • 我喜欢这个,非常可读和简洁,很高兴知道这个包! df %&gt;% group_by(ID) %&gt;% pad() %&gt;% replace_na(list(Value = 0))
    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-26
      • 1970-01-01
      • 1970-01-01
      • 2021-12-20
      • 1970-01-01
      • 2020-04-03
      相关资源
      最近更新 更多