Как получить перекрывающиеся значения для интервалов дат в R

У меня есть фрейм данных, который выглядит так:

w<-read.table(header=TRUE, text="
start.date   end.date   manager
2006-05-01   2007-04-30 a
2006-09-30   2007-12-31 b
1999-09-30   2007-12-31 c
2008-01-01   2012-04-30 d
2008-01-01   2020-02-28 e
2009-05-01   2016-04-08 f")

Я хотел бы получить фрейм данных, который возвращает, какие менеджеры работали в течение каждого месяца в течение периода, например

df<-read.table(header=TRUE, text="
month    manager1  manager2  manager3  manager4
01-2006  a         b         c         NA
02-2006  a         b         c         d
03-2006  b         c         d         NA
04-2006  b         d         NA        NA")

Я начал с определения функции datseq, которая возвращает количество месяцев между start.date и end.date.

datseq <- function(t1, t2) { 
  format(seq.Date(from = as.Date(t1,"%Y-%m-%d"), 
             to = as.Date(t2,"%Y-%m-%d"),by="month"), 
         "%m/%Y") 

но тогда я не могу создать правильный цикл для получения желаемого результата. Заранее спасибо всем ответившим!


person Edoardo Poli    schedule 25.03.2021    source источник
comment
Посмотрите на data.table::foverlaps()   -  person mharinga    schedule 29.03.2021


Ответы (1)


Поскольку вам нужно знать только перекрытие на уровне месяца, а не на уровне дня, вы можете считать, что менеджеры начали работу в первый день и ушли в последний день месяца. Этого можно добиться с помощью floor_date и ceiling_date из пакета lubridate.

library(lubridate)

w.extended <- w

w.extended$start.date <- floor_date(as.Date(w.extended$start.date), "month")
w.extended$end.date <- ceiling_date(as.Date(w.extended$end.date), "month") - 1

#List of months
timeperiod <- seq(min(w.extended$start.date),
                  by = "month", 
                  to = max(w.extended$end.date))

Затем вы можете использовать a %within% b из пакета lubridate, который может проверить, попадает ли дата в список интервалов. Примените эту функцию к каждому месяцу с указанными вами интервалами.

df <- data.frame(t(sapply(timeperiod, 
                          function(x){
                            managersWorking <- x %within% interval(w.extended$start.date, 
                                                                   w.extended$end.date)
                            c(as.character(x), managersWorking)
                            })),
                 stringsAsFactors = F)

#Replace the 'character' format of columns to the appropriate one
df[-1] <- apply(df[-1], 2, as.logical)
df[,1]<- format(as.Date(df[,1]), "%Y/%m")

colnames(df) <- c("month", paste0("manager.", w$manager))

head(df)
#    month manager.a manager.b manager.c manager.d manager.e manager.f
#1 1999/09     FALSE     FALSE      TRUE     FALSE     FALSE     FALSE
#2 1999/10     FALSE     FALSE      TRUE     FALSE     FALSE     FALSE
#3 1999/11     FALSE     FALSE      TRUE     FALSE     FALSE     FALSE
#4 1999/12     FALSE     FALSE      TRUE     FALSE     FALSE     FALSE
#5 2000/01     FALSE     FALSE      TRUE     FALSE     FALSE     FALSE
#6 2000/02     FALSE     FALSE      TRUE     FALSE     FALSE     FALSE

Необработанные данные:

w <- read.table(header=TRUE, text="
start.date   end.date   manager
2006-05-01   2007-04-30 a
2006-09-30   2007-12-31 b
1999-09-30   2007-12-31 c
2008-01-01   2012-04-30 d
2008-01-01   2020-02-28 e
2009-05-01   2016-04-08 f")
w
#  start.date   end.date manager
#1 2006-05-01 2007-04-30       a
#2 2006-09-30 2007-12-31       b
#3 1999-09-30 2007-12-31       c
#4 2008-01-01 2012-04-30       d
#5 2008-01-01 2020-02-28       e
#6 2009-05-01 2016-04-08       f
person marcguery    schedule 26.03.2021