Как добавить строки с периодами времени между заданным периодом времени? - PullRequest
4 голосов
/ 07 мая 2019

У меня есть набор данных с периодами времени, которые могут перекрываться, показывая мне, если кто-то присутствовал (example_df).Я хочу получить набор данных, который разбивает большой период времени (с 2014-01-01 по 2014-10-31) на меньшие периоды времени, когда кто-то присутствовал (present = 1), и периоды времени, когда никто не присутствовал (present = 0).Результат должен выглядеть следующим образом: result_df

Пример кадра данных

example_df <- data.frame(ID = 1, 
                     start = c(as.Date("2014-01-01"), as.Date("2014-03-05"), as.Date("2014-06-13"), as.Date("2014-08-15")), 
                     end = c(as.Date("2014-04-07"), as.Date("2014-04-12"), as.Date("2014-08-05"), as.Date("2014-10-02")), 
                     present = 1) 

Результат должен выглядеть следующим образом

result_df <- data.frame(ID = 1, 
                     start = c(as.Date("2014-01-01"), as.Date("2014-04-12"), as.Date("2014-06-13"), as.Date("2014-08-05"), as.Date("2014-08-15"), as.Date("2014-10-02")), 
                     end = c(as.Date("2014-04-12"), as.Date("2014-06-13"), as.Date("2014-08-05"), as.Date("2014-08-15"), as.Date("2014-10-02"), as.Date("2014-10-31")), 
                     present = c(1, 0, 1, 0, 1, 0)) 

Я понятия не имею, как решить эту проблему, так кактребуется разделить периоды времени или добавить строки (или что-то еще?).Любая помощь очень ценится!

Ответы [ 2 ]

3 голосов
/ 07 мая 2019

Я надеюсь, что смогу быть полезным, так как я тоже боролся с этим.

Как и в примере IceCreamToucan, это предполагает независимость от идентификатора человека. Этот подход использует dplyr для просмотра перекрытий в диапазонах дат, а затем выравнивает их. Другие примеры этого подхода были описаны в stackoverflow и используют dplyr. Конечный результат включает временные диапазоны, в которых присутствует человек.

library(tidyr)
library(dplyr)

pres <- example_df %>%
  group_by(ID) %>%
  arrange(start) %>% 
  mutate(indx = c(0, cumsum(as.numeric(lead(start)) > cummax(as.numeric(end)))[-n()])) %>%
  group_by(ID, indx) %>%
  summarise(start = min(start), end = max(end), present = 1) %>%
  select(-indx)

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

result <- pres

for (i in unique(pres$ID)) {
  pres_i <- subset(pres, ID == i)
  if (nrow(pres_i) > 1) {
    adding <- data.frame(ID = i, start = pres_i$end[-nrow(pres_i)]+1, end = pres_i$start[-1]-1, present = 0)
    adding <- adding[adding$start <= adding$end, ]
    result <- bind_rows(result, adding)
  }
}
result[order(result$ID, result$start), ]

# A tibble: 5 x 4
# Groups:   ID [1]
     ID start      end        present
  <dbl> <date>     <date>       <dbl>
1     1 2014-01-01 2014-04-12       1
2     1 2014-04-13 2014-06-12       0
3     1 2014-06-13 2014-08-05       1
4     1 2014-08-06 2014-08-14       0
5     1 2014-08-15 2014-10-02       1
1 голос
/ 07 мая 2019

Предполагая, что вы хотите сделать это отдельно для каждого ID, вы можете создать таблицу данных со всеми датами, для которых кто-то присутствовал, и объединить ее с таблицей всех дат за этот период времени.Результат не совсем одинаков, потому что текущий и несуществующий периоды не перекрываются.

library(data.table)
setDT(example_df)


example_df[, {
  pres <- unique(unlist(Map(`:`, start, end)))
  class(pres) <- 'Date'
  all <- min(pres):max(pres)
  class(all) <- 'Date'
  pres <- data.table(day = pres)
  all <- data.table(day = all)
  out.full <- pres[all, on = .(day), .(day = i.day, present = +!is.na(x.day))]
  out.full[, .(start = min(day), end = max(day)), 
           by = .(present, rid = rleid(present))][, -'rid']
  }, by = ID]

#    ID present      start        end
# 1:  1       1 2014-01-01 2014-04-12
# 2:  1       0 2014-04-13 2014-06-12
# 3:  1       1 2014-06-13 2014-08-05
# 4:  1       0 2014-08-06 2014-08-14
# 5:  1       1 2014-08-15 2014-10-02
...