首页 文章

R / lubridate:计算两个时期之间的重叠天数

提问于
浏览
0

我想计算两个时间段之间的重叠天数 . 一个句点在开始和结束日期中固定,另一个在数据框中记录为开始日期和结束日期 .

编辑:我正在处理具有发布日期(df $ start)和未发布日期(df $ end)的广告 . 我想知道的是他们在特定月份在线的天数(my.start = 2018-01-01,my.end = 2018-08-31) .

library(dplyr)
library(lubridate)

my.start <- ymd("2018-08-01")
my.end <- ymd("2018-08-31")

df <- data.frame(start = c("2018-07-15", "2018-07-20", "2018-08-15", "2018-08-20", "2018-09-01"), 
                 end   = c("2018-07-20", "2018-08-05", "2018-08-19", "2018-09-15", "2018-09-15"))

# strings to dates
df <- mutate(df, start = ymd(start), end = ymd(end))

# does not work - calculate overlap in days
df <- mutate(df, overlap = intersect(interval(my.start, my.end), interval(start, end)))

结果应为0,5,4,12,0天:

my.start |-------------------------------| my.end

|-----| (0)
        |---------| (5)
                            |----| (4)
                                   |------------------| (12)
                                             |---------------| (0)

在Excel中,我会使用

=MAX(MIN(my.end, end) - MAX(my.start, start) + 1, 0)

但这也不起作用:

# does not work - calculate via min/max
df <- mutate(df, overlap = max(min(my.end, end) - max(my.start, start) + 1, 0))

在我尝试在日期使用 as.numeric() 的Excel方法之前,我想知道是否有更聪明的方法来做到这一点 .

编辑:实际上,Excel数字方法似乎也没有两个工作(所有结果都为零):

# does not work - calculate via numeric

ms.num <- as.numeric(my.start)
me.num <- as.numeric(my.end)

df <- df %>% 
  mutate(s.num = as.numeric(start),
         e.num = as.numeric(end),

         overlap = max(min(e.num, me.num) - max(s.num, ms.num) + 1, 0))

编辑:@akrun的方法似乎适用于ymd日期 . 但是,它似乎不适用于ymd_hms次:

library(dplyr)
library(lubridate)
library(purrr)

my.start <- ymd("2018-08-01")
my.end <- ymd("2018-08-31")

df <- data.frame(start = c("2018-07-15 10:00:00", "2018-07-20 10:00:00", "2018-08-15 10:00:00", "2018-08-20 10:00:00", "2018-09-01 10:00:00"), 
                 end   = c("2018-07-20 10:00:00", "2018-08-05 10:00:00", "2018-08-19 10:00:00", "2018-09-15 10:00:00", "2018-09-15 10:00:00"))

# strings to dates
df <- mutate(df, start = ymd_hms(start), end = ymd_hms(end))

# leads to 0 results
df %>% mutate(overlap = map2(start, end, ~ sum(seq(.x, .y, by = '1 day') %in% seq(my.start, my.end, by = '1 day'))))

2 回答

  • 3

    我想你可能会遇到 maxmin vs pmaxpmin 的问题:

    library(dplyr)
    
    df %>%
      mutate(overlap = pmax(pmin(my.end, end) - pmax(my.start, start) + 1,0))
    
           start        end overlap
    1 2018-07-15 2018-07-20  0 days
    2 2018-07-20 2018-08-05  5 days
    3 2018-08-15 2018-08-19  5 days
    4 2018-08-20 2018-09-15 12 days
    5 2018-09-01 2018-09-15  0 days
    
  • 3

    我们可以使用 pmin/pmax 来获取两组 vectormin/max

    df %>% 
       mutate(overlap = ifelse(my.start > end, 0, pmin(my.end, end) - 
                                     pmax(my.start, start) + 1))
    #       start        end overlap
    #1 2018-07-15 2018-07-20   0
    #2 2018-07-20 2018-08-05   5
    #3 2018-08-15 2018-08-19   5
    #4 2018-08-20 2018-09-15  12
    #5 2018-09-01 2018-09-15   0
    

    如果我们想要使用OP代码中的相同选项,即 min/max ,使用 rowwise() 或使用 map2 ,我们循环遍历行

    library(purrr)
    df %>% 
      mutate(overlap = map2_dbl(start, end, ~
            max( as.integer(min(my.end, .y) - max(my.start, .x) + 1), 0)))
    

    注意到OP的实际数据有时间成分 . 在这种情况下,通过转换为 Date 类来更改上述解决方案

    df %>% 
       mutate(overlap = map2_dbl(start, end, ~
         max(as.integer(min(my.end, as.Date(.y)) - max(my.start, as.Date(.x)) + 1), 0)))
    

相关问题