Разверните строки по дате с использованием даты начала и окончания
Рассмотрим кадр данных формы
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
Ответы
Ответ 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