Заполните пропущенные случаи до определенного условия для группы - PullRequest
0 голосов
/ 15 сентября 2018

Я пытаюсь создать фрейм данных, который показывает все промежуточные месяцы для моего набора данных по темам. Вот пример того, как выглядят данные:

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(). Однако проблема в том, что я получаю все пропущенные месяцы для каждого идентификатора субъекта на основе минимального и максимального месяца, указанного в наборе данных:

## 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() не лучший способ сделать это?

Ответы [ 2 ]

0 голосов
/ 16 сентября 2018

Эту проблему можно решить путем создания последовательности месяцев отдельно для каждого 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

Обратите внимание, что для id == 2 есть только одна строка в соответствии с запросом OP.

Этот подход требует приведения date от фактора к классу Date, чтобы убедиться, что все пропущенные месяцы будут завершены.

Это также безопаснее, чем полагаться на доступные date коэффициенты в наборе данных. Для иллюстрации предположим, что id == 4 равно Out в месяце 2017-06-01 (июнь) вместо 2017-04-01 (апрель). Тогда во всем наборе данных не будет месяца 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"))
0 голосов
/ 15 сентября 2018

Я бы по-прежнему использовал 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   
...