Расширьте даты начала и окончания на несбалансированную месячную панель с помощью dplyr - PullRequest
0 голосов
/ 21 мая 2018

У меня есть даты начала и окончания событий, которые я хочу расширить на ежемесячную панель, и я хотел узнать, есть ли в dplyr какой-либо инструмент для решения этой проблемы.Следующий код делает то, что я хочу сделать с ddply().Сначала создается пример tibble data.frame (называемый «широким»), где «id» представляет отдельное лицо, а «HomeNum» - это событие для этого человека.Следующая строка создает переменную «date», которая представляет собой месячный ряд от «StartDate» до «FinishDate» внутри каждого «id» по группе «HomeNum».

library(plyr)
library(dplyr)
library(tibble)
wide = 
    tibble(
        id = c(1, 1, 2, 2, 2),
        HomeNum = c(0,1,0,1,2),
        StartDate = as.Date(c("2001-01-01", "2001-03-01", "2000-04-01", "2001-02-01", "2002-08-01")),
        FinishDate = as.Date(c("2001-02-01", "2002-05-01", "2001-01-01", "2002-07-01", "2002-12-01"))
    )
panel = 
    ddply(wide, 
          ~id+HomeNum, 
          transform, 
          date = seq.Date(StartDate, FinishDate, by = "month")
    )

Я предполагаю, что dplyr, как«следующая итерация plyr» должна иметь какой-то способ реализовать подобное решение (и вывести tibble), но следующее не сработало:

panel = 
    wide %>% 
    group_by(id, HomeNum) %>% 
    mutate(date = seq.Date(StartDate, FinishDate, by = "month")) 

и вернуло

Error in mutate_impl(.data, dots) :
    Column `date` must be length 1 (the group size), not 2

Честно говоря, я удивлен, что решение ddply() работает и не выдает подобную ошибку.

Моя реализация с ddply() похожа на ответы на этот вопрос .

Ответы [ 2 ]

0 голосов
/ 22 мая 2018

Использование unnest в списке дат было проблемой в предыдущих версиях tidyr.Я получил эту же ошибку и нашел обходной путь, но он больше не требовался, как только я обновил до tidyr 0.8.1.Это проблема, которая задокументирована в нескольких выпусках на GitHub - # 4507 * и # 450 - те, на которые я смотрел.

Если у вас есть версия, которая не можетЕсли вы используете не вложенные даты, вы можете использовать ответ @ hpesoj626, конвертируя даты в строки, отменяя их, а затем конвертируя строки обратно в даты.

library(tidyverse)

wide <- tibble(
    id = c(1, 1, 2, 2, 2),
    HomeNum = c(0,1,0,1,2),
    StartDate = as.Date(c("2001-01-01", "2001-03-01", "2000-04-01", "2001-02-01", "2002-08-01")),
    FinishDate = as.Date(c("2001-02-01", "2002-05-01", "2001-01-01", "2002-07-01", "2002-12-01"))
  )

# with previous versions of tidyr
wide %>%
  group_by(id, HomeNum) %>%
  mutate(date = list(seq.Date(StartDate, FinishDate, by = "month") %>% as.character())) %>%
  tidyr::unnest() %>%
  mutate(date = as.Date(date))
#> # A tibble: 50 x 5
#> # Groups:   id, HomeNum [5]
#>       id HomeNum StartDate  FinishDate date      
#>    <dbl>   <dbl> <date>     <date>     <date>    
#>  1     1       0 2001-01-01 2001-02-01 2001-01-01
#>  2     1       0 2001-01-01 2001-02-01 2001-02-01
#>  3     1       1 2001-03-01 2002-05-01 2001-03-01
#>  4     1       1 2001-03-01 2002-05-01 2001-04-01
#>  5     1       1 2001-03-01 2002-05-01 2001-05-01
#>  6     1       1 2001-03-01 2002-05-01 2001-06-01
#>  7     1       1 2001-03-01 2002-05-01 2001-07-01
#>  8     1       1 2001-03-01 2002-05-01 2001-08-01
#>  9     1       1 2001-03-01 2002-05-01 2001-09-01
#> 10     1       1 2001-03-01 2002-05-01 2001-10-01
#> # ... with 40 more rows

В противном случае решение, подобное тому, которое они опубликовали, должно работать:

# with tidyr 0.8.1
wide %>%
  group_by(id, HomeNum) %>%
  mutate(date = list(seq.Date(StartDate, FinishDate, by = "month"))) %>%
  tidyr::unnest()
#> # A tibble: 50 x 5
#> # Groups:   id, HomeNum [5]
#>       id HomeNum StartDate  FinishDate date      
#>    <dbl>   <dbl> <date>     <date>     <date>    
#>  1     1       0 2001-01-01 2001-02-01 2001-01-01
#>  2     1       0 2001-01-01 2001-02-01 2001-02-01
#>  3     1       1 2001-03-01 2002-05-01 2001-03-01
#>  4     1       1 2001-03-01 2002-05-01 2001-04-01
#>  5     1       1 2001-03-01 2002-05-01 2001-05-01
#>  6     1       1 2001-03-01 2002-05-01 2001-06-01
#>  7     1       1 2001-03-01 2002-05-01 2001-07-01
#>  8     1       1 2001-03-01 2002-05-01 2001-08-01
#>  9     1       1 2001-03-01 2002-05-01 2001-09-01
#> 10     1       1 2001-03-01 2002-05-01 2001-10-01
#> # ... with 40 more rows

Другой вариант - gather данные в длинном формате, где наблюдения имеют type столбец с указанием даты начала или окончания.Затем используйте complete, чтобы заполнить пропущенные даты между минимальной и максимальной датами каждой группы.При сборе сохраняется столбец type, который заполняется как NA для добавляемых дат.Затем вы можете удалить столбец type, если он больше не нужен.

wide %>%
  gather(key = type, value = date, StartDate, FinishDate) %>%
  group_by(id, HomeNum) %>%
  complete(date = seq.Date(min(date), max(date), by = "month"))
#> # A tibble: 50 x 4
#> # Groups:   id, HomeNum [5]
#>       id HomeNum date       type      
#>    <dbl>   <dbl> <date>     <chr>     
#>  1     1       0 2001-01-01 StartDate 
#>  2     1       0 2001-02-01 FinishDate
#>  3     1       1 2001-03-01 StartDate 
#>  4     1       1 2001-04-01 <NA>      
#>  5     1       1 2001-05-01 <NA>      
#>  6     1       1 2001-06-01 <NA>      
#>  7     1       1 2001-07-01 <NA>      
#>  8     1       1 2001-08-01 <NA>      
#>  9     1       1 2001-09-01 <NA>      
#> 10     1       1 2001-10-01 <NA>      
#> # ... with 40 more rows

Создан в 2018-05-22 с помощью пакета prex (v0.2.0).

0 голосов
/ 21 мая 2018

Вы можете привести элементы date к спискам и unnest.

library(tidyverse)
wide %>%
  group_by(id, HomeNum) %>%
  mutate(date = list(seq.Date(StartDate, FinishDate, by = "month"))) %>%
  unnest(date)
...