填写缺失的情况,直到每组具体情况

Fill in missing cases till specific condition per group

我正在尝试创建一个数据框,按主题显示我的数据集之间的所有月份。这是数据的示例:

dat <- data.frame(c(1, 1, 1, 2, 3, 3, 3, 4, 4, 4), c(rep(30, 2), rep(25, 5), rep(20, 3)), c('2017-01-01', '2017-02-01', '2017-04-01', '2017-02-01', '2017-01-01', '2017-02-01', '2017-03-01', '2017-01-01',
                    '2017-02-01', '2017-04-01'))
colnames(dat) <- c('id', 'value', 'date')
dat$Out.Of.Study <- c("", "", "Out", "Out", "", "", "Out", "", "", "Out")

dat

  id value       date Out.Of.Study
1   1    30 2017-01-01             
2   1    30 2017-02-01             
3   1    25 2017-04-01          Out
4   2    25 2017-02-01          Out
5   3    25 2017-01-01             
6   3    25 2017-02-01             
7   3    25 2017-03-01          Out
8   4    20 2017-01-01             
9   4    20 2017-02-01             
10  4    20 2017-04-01          Out

如果我想显示没有收集数据的月份之间(但受试者仍在研究中),我可以使用 complete() 函数。但是,问题是我根据数据集中标识的最小和最大月份获取每个主题 ID 的所有缺失月份:

## Add Dates by Group

library(tidyr)

complete(dat, id, date)

   id       date value Out.Of.Study
1   1 2017-01-01    30             
2   1 2017-02-01    30             
3   1 2017-03-01    NA         <NA>
4   1 2017-04-01    25          Out
5   2 2017-01-01    NA         <NA>
6   2 2017-02-01    25          Out
7   2 2017-03-01    NA         <NA>
8   2 2017-04-01    NA         <NA>
9   3 2017-01-01    25             
10  3 2017-02-01    25             
11  3 2017-03-01    25          Out
12  3 2017-04-01    NA         <NA>
13  4 2017-01-01    20             
14  4 2017-02-01    20             
15  4 2017-03-01    NA         <NA>
16  4 2017-04-01    20          Out

这个问题是我不希望缺失的月份超过受试者最后观察到的月份(基本上,我有受试者被审查并且需要从研究中删除)或出现在之前受试者开始研究的月份。例如,主题 2 只是“2017-02-01”月份的参与者。为此,我希望数据能够表示这是他们在那里的唯一月份,而不是用之后的额外月份和之前的额外月份来表示,如上所示。受试者3也是如此,虽然没有参加研究,但还有一个月的时间。

也许 complete() 不是解决此问题的最佳方法?

我仍然会使用 complete(可能是此处使用的正确方法),但之后它会将超过行的行子集化为 "Out"。您可以使用 dplyr::between.

执行此操作
dat %>%
    group_by(id) %>%
    complete(date) %>%
    # Filter rows that are between 1 and the one that has "Out"
    filter(between(row_number(), 1, which(Out.Of.Study == "Out")))

      id date       value Out.Of.Study
   <dbl> <fct>      <dbl> <chr>       
 1     1 2017-01-01    30 ""          
 2     1 2017-02-01    30 ""          
 3     1 2017-03-01    NA NA          
 4     1 2017-04-01    25 Out         
 5     2 2017-01-01    NA NA          
 6     2 2017-02-01    25 Out         
 7     3 2017-01-01    25 ""          
 8     3 2017-02-01    25 ""          
 9     3 2017-03-01    25 Out         
10     4 2017-01-01    20 ""          
11     4 2017-02-01    20 ""          
12     4 2017-03-01    NA NA          
13     4 2017-04-01    20 Out   

这可以通过为每个 id 单独创建一个月份序列并通过 dat 加入序列来完成缺失的月份来解决。

1。 data.table

(这个问题被标记为 tidyr。但由于我对 data.table 更熟悉,所以我先尝试了这个。)

library(data.table)
# coerce date strings to class Date 
setDT(dat)[, date := as.Date(date)]
# create sequence of months for each id
sdt <- dat[, .(date = seq(min(date), max(date), "month")), by = id]
# join
dat[sdt, on = .(id, date)]
    id value       date Out.Of.Study
 1:  1    30 2017-01-01             
 2:  1    30 2017-02-01             
 3:  1    NA 2017-03-01         <NA>
 4:  1    25 2017-04-01          Out
 5:  2    25 2017-02-01          Out
 6:  3    25 2017-01-01             
 7:  3    25 2017-02-01             
 8:  3    25 2017-03-01          Out
 9:  4    20 2017-01-01             
10:  4    20 2017-02-01             
11:  4    NA 2017-03-01         <NA>
12:  4    20 2017-04-01          Out

请注意,根据 OP 的要求,id == 2 只有一行。

此方法需要将 date 从因子强制转换为 class Date 以确保完成所有缺失的月份。

这也比依赖数据集中可用的 date 因素更安全。为了便于说明,我们假设 id == 4 在月份 2017-06-01(六月)而不是 2017-04-01(四月)中是 Out。那么整个数据集中就没有月份2017-05-01(五月),最后的结果是不完整的

不创建临时变量 sdt 代码变为

library(data.table)
setDT(dat)[, date := as.Date(date)][
  dat[, .(date = seq(min(date), max(date), "month")), by = id], on = .(id, date)]

2。 tidyr / dplyr

library(dplyr)
library(tidyr)

# coerce date strings to class Date 
dat <- dat %>%
  mutate(date = as.Date(date))

dat %>% 
  # create sequence of months for each id
  group_by(id) %>%
  expand(date = seq(min(date), max(date), "month")) %>% 
  # join to complete the missing month for each id
  left_join(dat, by = c("id", "date"))
# A tibble: 12 x 4
# Groups:   id [?]
      id date       value Out.Of.Study
   <dbl> <date>     <dbl> <chr>       
 1     1 2017-01-01    30 ""          
 2     1 2017-02-01    30 ""          
 3     1 2017-03-01    NA NA          
 4     1 2017-04-01    25 Out         
 5     2 2017-02-01    25 Out         
 6     3 2017-01-01    25 ""          
 7     3 2017-02-01    25 ""          
 8     3 2017-03-01    25 Out         
 9     4 2017-01-01    20 ""          
10     4 2017-02-01    20 ""          
11     4 2017-03-01    NA NA          
12     4 2017-04-01    20 Out

有一个不更新的变体dat:

library(dplyr)
library(tidyr)
dat %>%
  mutate(date = as.Date(date)) %>% 
  right_join(group_by(., id) %>%
               expand(date = seq(min(date), max(date), "month")),
             by = c("id", "date"))