data.table эквивалент tidyr :: в комплекте с group_by

Вопрос:

У меня есть следующий фрейм данных:

library(tidyverse)
df <- data_frame(
id = c(1, 1, 2, 2),
date1 = as.Date(c("2013-01-01", "2013-02-01", "2015-04-01", "2015-05-01")),
date2 = as.Date(c("2012-12-09", "2012-12-09", "2015-03-10", "2015-03-10"))
)

# A tibble: 4 x 3
id      date1      date2
<dbl>     <date>     <date>
1     1 2013-01-01 2012-12-09
2     1 2013-02-01 2012-12-09
3     2 2015-04-01 2015-03-10
4     2 2015-05-01 2015-03-10

И я хочу завершить этот фрейм данных таким образом, что для каждого id будет другое значение date1. Это другое значение date1 вычисляется как следующий месяц. Также есть значение date2 которое одинаково для всех id. С tidyr::complete это действие может быть выполнено следующим образом:

df %>%
group_by(id) %>%
complete(date1 = seq.Date(from = min(date1), length.out = 3, by = "month"), date2 = date2[1])

# A tibble: 6 x 3
# Groups:   id [2]
id      date1      date2
<dbl>     <date>     <date>
1     1 2013-01-01 2012-12-09
2     1 2013-02-01 2012-12-09
3     1 2013-03-01 2012-12-09
4     2 2015-04-01 2015-03-10
5     2 2015-05-01 2015-03-10
6     2 2015-06-01 2015-03-10

Поскольку у меня около 150 тыс. Групп в моих исходных данных, решение tidyr занимает больше часа, чтобы закончить. Я предполагаю, что скорость будет data.table с использованием data.table. Можно ли сделать то же самое в data.table?

Аналогичные вопросы задавали в data.table эквиваленте tidyr :: complete(), но без предложения group_by.

Лучший ответ:

На основе некоторого первоначального бенчмаркинга подход data.table кажется более быстрым

library(data.table)
setDT(df)[, .(date1 = seq(min(date1), length.out = 3, by = 'month'), date2 = date2[1]), id]

Ориентиры

 df <- data_frame(
  id = rep(1:3000, each = 2), 
  date1 = rep(as.Date(c("2013-01-01", "2013-02-01", "2015-04-01", "2015-05-01")),
  length.out = 6000), 
  date2 = rep(as.Date(c("2012-12-09", "2012-12-09", "2015-03-10", "2015-03-10")), 
   length.out = 6000))

system.time({
df %>% 
  group_by(id) %>% 
  complete(date1 = seq.Date(from = min(date1), 
          length.out = 3, by = "month"), date2 = date2[1])
})
#user  system elapsed 
#64.05   21.27   86.05 

system.time({
setDT(df)[, .(date1 = seq(min(date1), length.out = 3, by = 'month'), date2 = date2[1]), id]
})
#user  system elapsed 
#  0.14    0.00    0.14 

Ответ №1

Если вам нужна скорость, поддерживая ее как можно более тощий:

library(data.table)
library(lubridate)

> dt[, .SD
][, .(date1=max(date1)), .(id, date2)
][, date1Inc := date1 + months(1)
][, rbind(dt, .SD[, .(id, date1=date1Inc, date2)])
][order(id, date1)
]

id      date1      date2
1:  1 2013-01-01 2012-12-09
2:  1 2013-02-01 2012-12-09
3:  1 2013-03-01 2012-12-09
4:  2 2015-04-01 2015-03-10
5:  2 2015-05-01 2015-03-10
6:  2 2015-06-01 2015-03-10
>
>

Оцените статью
TechArks.Ru
Добавить комментарий