在具有多列的数据框中填充缺失日期

pad missing dates in a dataframe with several columns

如何在超过 2 列的数据框中插入缺失的日期? 在我的数据中,每个日期都有 sp1 和 sp2 之间的观察值。如果某一天在 sp1 和 sp2 之间没有观测值,则该日期将丢失。

这是我的 df 的一部分:

the_date    sp1 sp2 win     loss    sp1_name    sp2_name
4/1/13      A   B   8       8         A_name    B_name
4/2/13      A   B   6       10        A_name    B_name
4/3/13      A   B   7       5         A_name    B_name
4/5/13      A   B   7       5         A_name    B_name
4/6/13      A   B   6       2         A_name    B_name
4/7/13      A   B   15      10        A_name    B_name
4/1/13      A   C   3       8         A_name    C_name
4/2/13      A   C   2       12        A_name    C_name
4/3/13      A   C   9       7         A_name    C_name
4/4/13      A   C   14      8         A_name    C_name
4/6/13      A   C   9       10        A_name    C_name
4/1/13      A   D   13      13        A_name    D_name
4/2/13      A   D   13      5         A_name    D_name
4/3/13      A   D   7       1         A_name    D_name
4/4/13      A   D   15      11        A_name    D_name
4/5/13      A   D   3       11        A_name    D_name
4/6/13      A   D   12      11        A_name    D_name
4/7/13      A   D   9       9         A_name    D_name

例如,缺少 A-B 的 4/4/13。我想要在我的输出中插入那些缺失的日期和所有相应的列,并将 0 分配给输赢。所以我的输出看起来像这样添加了 * 的行):

the_date    sp1 sp2 win     loss    sp1_name    sp2_name
4/1/13      A   B   8       8         A_name    B_name
4/2/13      A   B   6       10        A_name    B_name
4/3/13      A   B   7       5         A_name    B_name
*4/4/13     A   B   0       0         A_name    B_name
4/5/13      A   B   7       5         A_name    B_name
4/6/13      A   B   6       2         A_name    B_name
4/7/13      A   B   15      10        A_name    B_name
4/1/13      A   C   3       8         A_name    C_name
4/2/13      A   C   2       12        A_name    C_name
4/3/13      A   C   9       7         A_name    C_name
4/4/13      A   C   14      8         A_name    C_name
*4/5/13     A   C   0       0         A_name    C_name
4/6/13      A   C   9       10        A_name    C_name
*4/7/13     A   C   0       0         A_name    C_name
4/1/13      A   D   13      13        A_name    D_name
4/2/13      A   D   13      5         A_name    D_name
4/3/13      A   D   7       1         A_name    D_name
4/4/13      A   D   15      11        A_name    D_name
4/5/13      A   D   3       11        A_name    D_name
4/6/13      A   D   12      11        A_name    D_name
4/7/13      A   D   9       9         A_name    D_name

我知道如果我们有一个 2 列数据框(值、日期),我们可以通过将数据框与全范围时间合并来用缺失的日期填充数据框。但是,我的数据框有超过 2 列。

此外,这只是我的一部分数据,所以我还有其他日期的其他组合:

sp1 sp2 
B    C
B    A
B    D
C    A
C    B
C    D
D    B
D    C
D    A

有什么线索吗?

这是一种dplyr方法。鉴于您的数据集很大,您可能需要考虑 data.table 方法。

d <- read.table(textConnection("the_date    sp1 sp2 win     loss    sp1_name    sp2_name
4/1/13      A   B   8       8         A_name    B_name
4/2/13      A   B   6       10        A_name    B_name
4/3/13      A   B   7       5         A_name    B_name
4/5/13      A   B   7       5         A_name    B_name
4/6/13      A   B   6       2         A_name    B_name
4/7/13      A   B   15      10        A_name    B_name
4/1/13      A   C   3       8         A_name    C_name
4/2/13      A   C   2       12        A_name    C_name
4/3/13      A   C   9       7         A_name    C_name
4/4/13      A   C   14      8         A_name    C_name
4/6/13      A   C   9       10        A_name    C_name
4/1/13      A   D   13      13        A_name    D_name
4/2/13      A   D   13      5         A_name    D_name
4/3/13      A   D   7       1         A_name    D_name
4/4/13      A   D   15      11        A_name    D_name
4/5/13      A   D   3       11        A_name    D_name
4/6/13      A   D   12      11        A_name    D_name
4/7/13      A   D   9       9         A_name    D_name"),
stringsAsFactors = FALSE, header = TRUE)

d$the_date <- as.Date(d$the_date, "%m/%d/%y")

更新

我意识到我下面的原始答案并不完全正确。例如,它没有用 4/7/13 填充 A C 组。考虑到这一点,我想出了一个更好而且我认为更快的方法。

#Step one combine sp1 and sp2 into one group
d$group <- paste0(d$sp1,d$sp2)

#Step two find min and max date in the database

min_d <- min(d$the_date)
max_d <- max(d$the_date)

#Step three use dplyr
d %>%
  do(expand.grid(unique(.$group), seq(min_d, max_d, 1))) %>% 
  rename(group = Var1, the_date = Var2) %>%
  left_join(d) %>%
  arrange(group) %>%
  select(-group)

原创

#Step one combine sp1 and sp2 into one group
d$group <- paste0(d$sp1,d$sp2)

#Step two use dplyr.  
d %>%
  group_by(group) %>%
  summarise(min = min(the_date), max = max(the_date)) %>%
  rowwise() %>%
  do(data.frame(group = .$group, the_date = seq(.$min, .$max, 1))) %>%
  left_join(d) %>%
  select(-group)

总的来说,您的问题与 this 相似。查看更多 information/ideas.

这是使用 padr 中的 padfill_by_value 的解决方案:

library(dplyr)
library(tidyr)
library(padr)

df %>%
  mutate(the_date = as.Date(the_date, "%m/%d/%y")) %>%
  group_by(sp1, sp2) %>%
  pad() %>%              
  fill(sp1_name:sp2_name) %>%      
  fill_by_value(win, loss)

结果:

# A tibble: 20 x 7
# Groups:   sp1, sp2 [3]
     the_date    sp1    sp2   win  loss sp1_name sp2_name
       <date> <fctr> <fctr> <dbl> <dbl>   <fctr>   <fctr>
 1 2013-04-01      A      B     8     8   A_name   B_name
 2 2013-04-02      A      B     6    10   A_name   B_name
 3 2013-04-03      A      B     7     5   A_name   B_name
 4 2013-04-04      A      B     0     0   A_name   B_name
 5 2013-04-05      A      B     7     5   A_name   B_name
 6 2013-04-06      A      B     6     2   A_name   B_name
 7 2013-04-07      A      B    15    10   A_name   B_name
 8 2013-04-01      A      C     3     8   A_name   C_name
 9 2013-04-02      A      C     2    12   A_name   C_name
10 2013-04-03      A      C     9     7   A_name   C_name
11 2013-04-04      A      C    14     8   A_name   C_name
12 2013-04-05      A      C     0     0   A_name   C_name
13 2013-04-06      A      C     9    10   A_name   C_name
14 2013-04-01      A      D    13    13   A_name   D_name
15 2013-04-02      A      D    13     5   A_name   D_name
16 2013-04-03      A      D     7     1   A_name   D_name
17 2013-04-04      A      D    15    11   A_name   D_name
18 2013-04-05      A      D     3    11   A_name   D_name
19 2013-04-06      A      D    12    11   A_name   D_name
20 2013-04-07      A      D     9     9   A_name   D_name

数据:

df = structure(list(the_date = structure(c(1L, 2L, 3L, 5L, 6L, 7L, 
1L, 2L, 3L, 4L, 6L, 1L, 2L, 3L, 4L, 5L, 6L, 7L), .Label = c("4/1/13", 
"4/2/13", "4/3/13", "4/4/13", "4/5/13", "4/6/13", "4/7/13"), class = "factor"), 
    sp1 = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "A", class = "factor"), 
    sp2 = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 
    2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("B", "C", "D"
    ), class = "factor"), win = c(8L, 6L, 7L, 7L, 6L, 15L, 3L, 
    2L, 9L, 14L, 9L, 13L, 13L, 7L, 15L, 3L, 12L, 9L), loss = c(8L, 
    10L, 5L, 5L, 2L, 10L, 8L, 12L, 7L, 8L, 10L, 13L, 5L, 1L, 
    11L, 11L, 11L, 9L), sp1_name = structure(c(1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "A_name", class = "factor"), 
    sp2_name = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 
    2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("B_name", 
    "C_name", "D_name"), class = "factor")), .Names = c("the_date", 
"sp1", "sp2", "win", "loss", "sp1_name", "sp2_name"), class = "data.frame", row.names = c(NA, 
-18L))