R Развернуть диапазон дат в данные панели по группам

У меня есть диапазоны дат, сгруппированные по двум переменным (id и type), которые в настоящее время хранятся во фрейме данных с именем data. Моя цель — расширить диапазон дат таким образом, чтобы у меня была строка для каждого дня в диапазоне дат, который включает одни и те же id и type.

Вот фрагмент, воспроизводящий пример фрейма данных:

data <- structure(list(id = c(1, 1, 1, 1, 1, 2, 2, 2, 2, 2), type = c("a", 
"a", "b", "c", "b", "a", "c", "d", "e", "f"), from = structure(c(1235199600, 
1235545200, 1235545200, 1235631600, 1235631600, 1242712800, 1242712800, 
1243058400, 1243058400, 1243231200), class = c("POSIXct", "POSIXt"
), tzone = ""), to = structure(c(1235372400, 1235545200, 1235631600, 
1235890800, 1236236400, 1242712800, 1243058400, 1243231200, 1243144800, 
1243576800), class = c("POSIXct", "POSIXt"), tzone = "")), .Names = c("id", 
"type", "from", "to"), row.names = c(700L, 753L, 2941L, 2178L, 
 2959L, 679L, 2185L, 12L, 802L, 1796L), class = "data.frame")

Это визуальное представление набора данных:

id  type  from        to
1   a     2009-02-21  2009-02-23
1   a     2009-02-25  2009-02-25
1   b     2009-02-25  2009-02-26
1   c     2009-02-25  2009-03-01
1   b     2009-05-26  2009-03-05
2   a     2009-05-26  2009-05-19
2   c     2009-05-19  2009-05-23
2   d     2009-05-19  2009-05-25
2   e     2009-05-23  2009-05-24
2   f     2009-05-25  2009-05-29

Вот визуальное представление предполагаемого результата:

id  type  date
1   a     2009-02-21
1   a     2009-02-22
1   a     2009-02-23
1   b     2009-02-25
1   b     2009-02-26
1   c     2009-02-26
1   c     2009-02-27
1   c     2009-02-28
1   c     2009-03-01
...
2   f     2009-05-25
2   f     2009-05-26
2   f     2009-05-27
2   f     2009-05-28
2   f     2009-05-29

Я нашел несколько похожих сообщений (ссылка и ссылка), которые помогли мне стать отправной точкой. Я попытался использовать решение plyr:

data2 <- adply(data, 1, summarise, date = seq(data$from, data$to))[c('id', 'type')]

Однако это приводит к ошибке:

Error: 'from' must be of length 1

Я также попытался использовать решение data.table:

data[, list(date = seq(from, to)), by = c('id', 'type')]

Однако это дает мне другую ошибку:

Error in `[.data.frame`(data, , list(date = seq(from, to)), by = c("id",  : 
unused argument (by = c("id", "type"))

Будем очень признательны за любые мысли о том, как решить эти ошибки (или использовать другой подход).


person Entropy    schedule 05.06.2014    source источник


Ответы (2)


1) by Вот ответ из трех строк с использованием by из базы R. Сначала мы преобразуем даты в класс "Date", что дает data2. Затем мы применяем f, который выполняет реальную работу над каждой строкой, и, наконец, мы rbind результирующих строк вместе:

data2 <- transform(data, from = as.Date(from), to = as.Date(to))

f <- function(x) with(x, data.frame(id, type, date = seq(from, to, by = "day")))
do.call("rbind", by(data, 1:nrow(data), f))

2) data.table Используя тот же data2 с data.table, делаем так:

library(data.table)

dt <- data.table(data2)
dt[, list(id, type, date = seq(from, to, by = "day")), by = 1:nrow(dt)]

2a) data.table или, альтернативно, это, где dt из (2), а f из (1):

dt[, f(.SD), by = 1:nrow(dt)]

3) dplyr с dplyr выдает предупреждение, но в остальном работает там, где data2 и f взяты из (1):

data2 %>% rowwise() %>% do(f(.))

ОБНОВЛЕНИЯ Некоторые улучшения.

person G. Grothendieck    schedule 05.06.2014
comment
Блестяще-спасибо! Дополнительный кредит за включение нескольких реализаций решения. - person Entropy; 06.06.2014

Вот один из способов выполнить такое преобразование с использованием базовых функций.

do.call(rbind,Map(function(id,type,from,to) {
    dts <- seq(from=from, to=to, by="1 day")
    dur <- length(dts)
    data.frame(
        id=rep(id, dur), 
        type=rep(type,dur),
        date=dts
    )
}, data$id, data$type, data$from, data$to))

И первый кусок вывода

   id type                date
1   1    a 2009-02-21 02:00:00
2   1    a 2009-02-22 02:00:00
3   1    a 2009-02-23 02:00:00
4   1    a 2009-02-25 02:00:00
5   1    b 2009-02-25 02:00:00
6   1    b 2009-02-26 02:00:00
7   1    c 2009-02-26 02:00:00
8   1    c 2009-02-27 02:00:00
9   1    c 2009-02-28 02:00:00
10  1    c 2009-03-01 02:00:00
11  1    b 2009-02-26 02:00:00
person MrFlick    schedule 05.06.2014