3

我正在寻找一个union时间间隔的实现,它能够处理本身不是间隔的联合。

我注意到lubridate包括一个union时间间隔的函数,但它总是返回一个间隔,即使联合不是一个间隔(即它返回由两个开始日期的最小值和两个结束日期的最大值定义的间隔,忽略不由任一区间覆盖):

library(lubridate)
int1 <- new_interval(ymd("2001-01-01"), ymd("2002-01-01"))
int2 <- new_interval(ymd("2003-06-01"), ymd("2004-01-01"))
union(int1, int2)
# Union includes intervening time between intervals.
# [1] 2001-01-01 UTC--2004-01-01 UTC

我也看过这个interval包,但它的文档没有提到union.

我的最终目标是使用复杂的联合%within%

my_int %within% Reduce(union, list_of_intervals)

因此,如果我们考虑一个具体的例子,假设list_of_intervals是:

[[1]] 2000-01-01 -- 2001-01-02 
[[2]] 2001-01-01 -- 2004-01-02 
[[3]] 2005-01-01 -- 2006-01-02 

then my_int <- 2001-01-01 -- 2004-01-01is not %within%the list_of_intervalsso it should returnFALSEmy_int <- 2003-01-01 -- 2006-01-01is so it should be TRUE

但是,我怀疑复杂联合的用途不止于此。

4

2 回答 2

3

如果我正确理解您的问题,您希望从一组可能重叠的区间开始,并获取代表输入集 UNION 的区间列表,而不仅仅是跨越输入集的最小值和最大值的单个区间. 这是我的同一个问题。

在以下位置提出了类似的问题:区间的联合

...但接受的响应因时间间隔重叠而失败。但是,hosolmaz(我是 SO 新手,所以不知道如何链接到该用户)发布了修复问题的修改(在 Python 中),然后我将其转换为 R,如下所示:

library(dplyr) # for %>%, arrange, bind_rows

interval_union <- function(input) {
  if (nrow(input) == 1) {
    return(input)
  }
  input <- input %>% arrange(start)
  output = input[1, ]
  for (i in 2:nrow(input)) {
    x <- input[i, ]
    if (output$stop[nrow(output)] < x$start) {
      output <- bind_rows(output, x)
    } else if (output$stop[nrow(output)] == x$start) {
      output$stop[nrow(output)] <- x$stop
    }
    if (x$stop > output$stop[nrow(output)]) {
      output$stop[nrow(output)] <- x$stop
    }
  }
  return(output)
}

以您的示例具有重叠和不连续的间隔:

d <- as.data.frame(list(
  start = c('2005-01-01', '2000-01-01', '2001-01-01'),
  stop = c('2006-01-02', '2001-01-02', '2004-01-02')),
  stringsAsFactors = FALSE)

这会产生:

> d
       start       stop
1 2005-01-01 2006-01-02
2 2000-01-01 2001-01-02
3 2001-01-01 2004-01-02

> interval_union(d)
       start       stop
1 2000-01-01 2004-01-02
2 2005-01-01 2006-01-02

我是 R 编程的相对新手,所以如果有人可以将上面的 interval_union() 函数转换为不仅接受输入数据帧作为参数,而且还接受“开始”和“停止”列的名称以使用该函数可以更容易地重复使用,那就太好了。

于 2016-11-09T14:05:41.087 回答
2

好吧,在您提供的示例中, and 的int1并集int2可以看作是具有两个间隔的向量:

int1 <- new_interval(ymd("2001-01-01"), ymd("2002-01-01"))
int2 <- new_interval(ymd("2003-06-01"), ymd("2004-01-01"))
ints <- c(int1,int2)

%within%适用于向量,因此您可以执行以下操作:

my_int <- new_interval(ymd("2001-01-01"), ymd("2004-01-01"))
my_int %within% ints
# [1]  TRUE FALSE

因此,您可以使用以下命令检查您的时间间隔是否在列表的某个时间间隔内any

any(my_int %within% ints)
# [1] TRUE

您的评论是正确的,给出的结果%within%似乎与文档不一致,文档中说:

如果 a 是一个区间,则它的开始日期和结束日期都必须在 b 范围内才能返回 TRUE。

如果我查看%within% when a 和 b 都是区间的源代码,它似乎如下:

setMethod("%within%", signature(a = "Interval", b = "Interval"), function(a,b){
    as.numeric(a@start) - as.numeric(b@start) <= b@.Data & as.numeric(a@start) - as.numeric(b@start) >= 0
})

因此,似乎只针对 的起点进行了a测试b,并且看起来与结果一致。也许这应该被视为一个错误并应该报告?

于 2013-02-15T08:28:08.007 回答