使用lubridate合并重叠的时间段

6

我想将lubridate intervals合并,如果它们重叠,则从时间上最先出现的内部中取最小值,在时间上最后出现的内部中取最大值,并进行汇总以创建跨越整个时间段的新interval。这是一个reprex:

library(lubridate, warn.conflicts = FALSE)
library(dplyr, warn.conflicts = FALSE)
library(tibble)

dat <- tibble(
  animal = rep(c("elk", "wolf", "moose"), each = 2),
  date_interval = c(
    interval(as.Date("2020-04-01"), as.Date("2020-04-05")),
    interval(as.Date("2020-04-10"), as.Date("2020-04-15")),
    interval(as.Date("2020-03-01"), as.Date("2020-04-01")),
    interval(as.Date("2020-02-15"), as.Date("2020-03-15")),
    interval(as.Date("2020-10-01"), as.Date("2020-11-01")),
    interval(as.Date("2020-09-15"), as.Date("2020-10-15"))
  )
)

dat
#> # A tibble: 6 x 2
#>   animal date_interval                 
#>   <chr>  <Interval>                    
#> 1 elk    2020-04-01 UTC--2020-04-05 UTC
#> 2 elk    2020-04-10 UTC--2020-04-15 UTC
#> 3 wolf   2020-03-01 UTC--2020-04-01 UTC
#> 4 wolf   2020-02-15 UTC--2020-03-15 UTC
#> 5 moose  2020-10-01 UTC--2020-11-01 UTC
#> 6 moose  2020-09-15 UTC--2020-10-15 UTC

好的,所以在 wolfmoose 级别中,我们有重叠的区间。假设这是相同的狼和驼鹿,下面这样会重复计算天数:

dat %>%
  group_by(animal) %>%
  mutate(time = time_length(date_interval)) %>%
  summarise(time_cumu = sum(time))
#> `summarise()` ungrouping output (override with `.groups` argument)
#> # A tibble: 3 x 2
#>   animal time_cumu
#>   <chr>      <dbl>
#> 1 elk       777600
#> 2 moose    5270400
#> 3 wolf     5184000

这是我想得到的输出类型,它可以总结重叠的区间:
tibble(
  animal = c("elk", "elk", "wolf", "moose"),
  date_interval = c(
    interval(as.Date("2020-04-01"), as.Date("2020-04-05")),
    interval(as.Date("2020-04-10"), as.Date("2020-04-15")),
    interval(as.Date("2020-02-15"), as.Date("2020-04-01")),
    interval(as.Date("2020-09-15"), as.Date("2020-11-01"))
  )
)
#> # A tibble: 4 x 2
#>   animal date_interval                 
#>   <chr>  <Interval>                    
#> 1 elk    2020-04-01 UTC--2020-04-05 UTC
#> 2 elk    2020-04-10 UTC--2020-04-15 UTC
#> 3 wolf   2020-02-15 UTC--2020-04-01 UTC
#> 4 moose  2020-09-15 UTC--2020-11-01 UTC

有什么想法?


1
每组变量是否总是只有2个条目,还是可能会更多? - starja
1
这可能不止这些。 - boshek
2个回答

6

Lubridate库中似乎没有将时间区间向量合并为不重叠区间的函数。

这是一种实现方式:

int_merge <- function(x) {
  if(length(x) == 1) return(x)
  x <- x[order(int_start(x))]
  y <- x[1]
  for(i in 2:length(x)){
    if(int_overlaps(y[length(y)], x[i]))
      y[length(y)] <- interval(start = min(int_start(c(y[length(y)], x[i]))),
                               end = max(int_end(c(y[length(y)], x[i]))))
    else
      y <- c(y, x[i])
  }
  return(y)
}

这使您可以做到:

dat %>% 
   group_by(animal) %>% 
   summarize(date_interval = int_merge(date_interval))

#> # A tibble: 4 x 2
#> # Groups:   animal [3]
#>   animal date_interval                 
#>   <chr>  <Interval>                    
#> 1 elk    2020-04-01 UTC--2020-04-05 UTC
#> 2 elk    2020-04-10 UTC--2020-04-15 UTC
#> 3 moose  2020-09-15 UTC--2020-11-01 UTC
#> 4 wolf   2020-02-15 UTC--2020-04-01 UTC

2
这是使用dplyr 1.0现在可能的(多行输出)摘要的很酷的用法! - Calum You
1
@CalumYou 我也是这么想的。在v1.0之前,你需要使用split-apply-rbind来完成这个任务。 - Allan Cameron
1
在这种情况下,您可以直接对间隔进行求和,以规避旧版dplyr的问题。 - starja

0
bed_merge()函数是valr包中值得一看的功能。它能够快速而轻松地完成工作!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接