Подтвердить что ты не робот

Разверните строки по дате с использованием даты начала и окончания

Рассмотрим кадр данных формы

       idnum      start        end
1993.1    17 1993-01-01 1993-12-31
1993.2    17 1993-01-01 1993-12-31
1993.3    17 1993-01-01 1993-12-31

с start и end имеет тип Date

 $ idnum : int  17 17 17 17 27 27
 $ start : Date, format: "1993-01-01" "1993-01-01" "1993-01-01" "1993-01-01" ...
 $ end   : Date, format: "1993-12-31" "1993-12-31" "1993-12-31" "1993-12-31" ...

Я хотел бы создать новый dataframe, который вместо этого ежемесячно наблюдает за каждой строкой, за каждый месяц между start и end (включая границы):

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

idnum       month
   17  1993-01-01
   17  1993-02-01
   17  1993-03-01
...
   17  1993-11-01
   17  1993-12-01

Я не уверен, какой формат month должен иметь, я в какой-то момент хочу сгруппировать по idnum, month для регрессий в остальной части набора данных.

До сих пор для каждой отдельной строки seq(from=test[1,'start'], to=test[1, 'end'], by='1 month') дает мне правильную последовательность - но как только я попытаюсь применить ее ко всему кадру данных, это не сработает:

> foo <- apply(test, 1, function(x) seq(x['start'], to=x['end'], by='1 month'))
Error in to - from : non-numeric argument to binary operator
4b9b3361

Ответ 1

Использование data.table:

require(data.table) ## 1.9.2+
setDT(df)[, list(idnum=idnum, month=seq(start,end,by="month")), by=1:nrow(df)]

setDT преобразует df в data.table. Затем для каждой строки by=1:nrow(df) мы создаем idnum и month по мере необходимости.

Ответ 2

Использование dplyr:

test %>%
    group_by(idnum) %>%
    summarize(start=min(start),end=max(end)) %>%
    do(data.frame(idnum=.$idnum, month=seq(.$start,.$end,by="1 month")))

Обратите внимание, что здесь я не генерирую последовательность между start и end для каждой строки, вместо этого это последовательность между min(start) и max(end) для каждого idnum. Если вы хотите первый:

test %>%
    rowwise() %>%
    do(data.frame(idnum=.$idnum, month=seq(.$start,.$end,by="1 month")))

Ответ 3

Возможно, вы можете попробовать:

Обновление

Основываясь на комментариях @Ananda Mahto

 res1 <- melt(setNames(lapply(1:nrow(test), function(x) seq(test[x, "start"],
 test[x, "end"], by = "1 month")), test$idnum))

Кроме того,

  res2 <- setNames(do.call(`rbind`,
          with(test, 
          Map(`expand.grid`,idnum,
          Map(`seq`, start, end, by='1 month')))), c("idnum", "month"))


  head(res1)
 #  idnum      month
 #1    17 1993-01-01
 #2    17 1993-02-01
 #3    17 1993-03-01
 #4    17 1993-04-01
 #5    17 1993-05-01
 #6    17 1993-06-01

Ответ 4

tidyverse ответ

Данные

df <- structure(list(idnum = c(17L, 17L, 17L), start = structure(c(8401, 
8401, 8401), class = "Date"), end = structure(c(8765, 8765, 8765
), class = "Date")), class = "data.frame", .Names = c("idnum", 
"start", "end"), row.names = c(NA, -3L))

Ответ и вывод

library(tidyverse)
df %>%
  nest(start, end) %>%
  mutate(data = map(data, ~seq(unique(.x$start), unique(.x$end), 1))) %>%
  unnest(data)

# # A tibble: 365 x 2
   # idnum       data
   # <int>     <date>
 # 1    17 1993-01-01
 # 2    17 1993-01-02
 # 3    17 1993-01-03
 # 4    17 1993-01-04
 # 5    17 1993-01-05
 # 6    17 1993-01-06
 # 7    17 1993-01-07
 # 8    17 1993-01-08
 # 9    17 1993-01-09
# 10    17 1993-01-10
# # ... with 355 more rows