R: добавление повторяющихся строк, в которых дата изменяется на один день до заданной даты

#r #datetime #dplyr #duplicates

#r #datetime #dplyr #дубликаты

Вопрос:

У меня есть большой фрейм данных (df), где «DateTime» определяет время события (Event = 1) для каждого животного (1-2), с которым связан ряд других переменных (например, переменная). Я хочу настроить эти данные для анализа пропорциональных рисков Кокса и должен соответствующим образом удлинить набор данных.

Для каждого животного я хочу создать новую повторяющуюся строку для каждого дня обратно к одной установленной дате для всех птиц (9/27 в этом примере). Все остальные переменные останутся такими же, как и входные данные, за исключением «События», которое будет равно нулю только в новых строках.

Недавно изучал tidyverse, но, честно говоря, не уверен, с чего начать.

Ввод:

 df <- data.frame(DateTime = DateTime, Event = 1, Animal = 1:2, Variable = c(2.4, 1.5))
df

             DateTime Event Animal Variable
1 2019-10-01 20:21:12     1      1      2.4
2 2019-09-29 20:42:20     1      2      1.5
  

Желаемый результат:

 DateTime2 <- as.POSIXct(c("2019-09-27 20:21:12",  "2019-09-28 20:21:12", "2019-09-29 20:21:12", "2019-09-30 20:21:12", "2019-10-01 20:21:12","2019-09-27 20:42:20", "2019-09-28 20:42:20", "2019-09-29 20:42:20" ), tz = "", format = "%Y-%m-%d %H:%M:%OS")
df2 <- data.frame(DateTime = DateTime2, Event = (c(0,0,0,0,1,0,0,1)), Animal = c(1,1,1,1,1,2,2,2), Variable = c(2.4,2.4,2.4,2.4,2.4, 1.5,1.5,1.5))
df2
             DateTime Event Animal Variable
1 2019-09-27 20:21:12     0      1      2.4
2 2019-09-28 20:21:12     0      1      2.4
3 2019-09-29 20:21:12     0      1      2.4
4 2019-09-30 20:21:12     0      1      2.4
5 2019-10-01 20:21:12     1      1      2.4
6 2019-09-27 20:42:20     0      2      1.5
7 2019-09-28 20:42:20     0      2      1.5
8 2019-09-29 20:42:20     1      2      1.5
  

Ответ №1:

Опция tidyverse :

 library(tidyverse)

initDate <- as.Date('2019-09-27')

df %>%
  mutate(daysSince = as.integer(as.Date(DateTime) - initDate)   1L) %>%
  uncount(daysSince) %>%
  group_by(across(-Event)) %>%
  mutate(DateTime = paste((as.Date(DateTime) - rev(1:n()))   1L, format(DateTime, '%H:%M:%S')),
         Event = replace(Event, row_number() != n(), 0L)
  )
  

Вывод:

 # A tibble: 8 x 4
# Groups:   DateTime, Animal, Variable [8]
  DateTime            Event Animal Variable
  <chr>               <dbl>  <int>    <dbl>
1 2019-09-27 20:21:12     0      1      2.4
2 2019-09-28 20:21:12     0      1      2.4
3 2019-09-29 20:21:12     0      1      2.4
4 2019-09-30 20:21:12     0      1      2.4
5 2019-10-01 20:21:12     1      1      2.4
6 2019-09-27 20:42:20     0      2      1.5
7 2019-09-28 20:42:20     0      2      1.5
8 2019-09-29 20:42:20     1      2      1.5
  

Комментарии:

1. Спасибо — пришлось обновлять пакеты, но сейчас это тоже работает.

2. Интеллектуальное решение!

Ответ №2:

Один из способов сделать это в базе R — создать последовательность дат для каждой даты в вашем DateTime столбце. Эта последовательность будет действовать как столбец DateTime для нового фрейма данных (один новый фрейм данных на строку исходного фрейма данных). Другие поля было бы очень просто создать оттуда.

Мы можем создать эти фреймы данных в виде списка, а затем rbind собрать их все вместе, чтобы получить наш результат. Например:

 df2 <- do.call(rbind, lapply(seq(nrow(df)), function(i) {
  dt <- rev(seq(df$DateTime[i], as.POSIXct("2019-09-27"), by = "-1 day"))
  data.frame(DateTime = dt, Event = c(rep(0, length(dt) - 1), 1),
             Animal = df$Animal[i], Variable = df$Variable[i])}))

df2
#>              DateTime Event Animal Variable
#> 1 2019-09-27 20:21:12     0      1      2.4
#> 2 2019-09-28 20:21:12     0      1      2.4
#> 3 2019-09-29 20:21:12     0      1      2.4
#> 4 2019-09-30 20:21:12     0      1      2.4
#> 5 2019-10-01 20:21:12     1      1      2.4
#> 6 2019-09-27 20:42:20     0      2      1.5
#> 7 2019-09-28 20:42:20     0      2      1.5
#> 8 2019-09-29 20:42:20     1      2      1.5
  

Комментарии:

1. Отлично. Спасибо, я проработаю это позже сегодня и удостоверюсь, что я это понимаю, но это определенно работает.