按段数 (R) 分隔相交时间间隔

Separate intersecting time intervals by number of segments (R)

提问人:user2602640 提问时间:10/13/2023 最后编辑:user2602640 更新时间:10/14/2023 访问量:71

问:

我正在研究一个时间间隔数据集。某些间隔重叠。我想获取原始区间数据,并按重叠次数将其分解为连续区间。在下面的玩具数据中,有 3 个区间。我想要的输出是一个数据框,其中包含只有一个 ID 的开始和停止,然后在 ID 1 和 ID 2 相交的地方开始和停止,然后在 ID 1-3 相交的地方开始和停止,然后开始和停止 ID 1 和 3 相交的地方,最后是 ID 1 其余部分的开始和停止。

library(lubridate)
library(ggplot2)

df <- structure(list(ID = 1:3, Start = structure(c(1690740180, 1690740480, 
1690741380), class = c("POSIXct", "POSIXt"), tzone = "America/Iqaluit"), 
    End = structure(c(1690751520, 1690742140, 1690742280), class = c("POSIXct", 
    "POSIXt"), tzone = "America/Iqaluit")), row.names = 3:5, class = "data.frame")

ggplot(df) + geom_segment(aes(x = Start, xend = End, y = as.factor(ID), yend = as.factor(ID)))

所需的输出应如下所示:

  Intervals               Start                 End
         1 2023-07-30 14:03:00 2023-07-30 14:07:59
         2 2023-07-30 14:08:00 2023-07-30 14:22:59
         3 2023-07-30 14:23:00 2023-07-30 14:35:40
         2 2023-07-30 14:35:40 2023-07-30 14:38:00
         1 2023-07-30 14:38:00 2023-07-30 15:06:40

我可以通过将数据插值到 1 秒并检查交叉点来做到这一点,但我希望有一个更清晰的解决方案。

R 间隔 润滑剂

评论


答:

2赞 r2evans 10/13/2023 #1

下面是一个基本的 R 解决方案:

alltimes <- unique(sort(c(df$Start, df$End)))
intervals <- sapply(alltimes[-length(alltimes)],
                    function(tm) df$Start <= tm & tm < df$End)
intervals
#       [,1]  [,2] [,3]  [,4]  [,5]
# [1,]  TRUE  TRUE TRUE  TRUE  TRUE
# [2,] FALSE  TRUE TRUE FALSE FALSE
# [3,] FALSE FALSE TRUE  TRUE FALSE

在 中,每一行都是原始行,每列都是一个时间段,该值指示是否在该时间段中找到原始行。我们可以取每列的总和来创建列,然后 和 列只是我们向量的对。intervalsdfdfIntervalsStartEndalltimes

data.frame(
  Intervals = colSums(intervals),
  Start = alltimes[-length(alltimes)],
  End = alltimes[-1]
)
#   Intervals               Start                 End
# 1         1 2023-07-30 14:03:00 2023-07-30 14:08:00
# 2         2 2023-07-30 14:08:00 2023-07-30 14:23:00
# 3         3 2023-07-30 14:23:00 2023-07-30 14:35:40
# 4         2 2023-07-30 14:35:40 2023-07-30 14:38:00
# 5         1 2023-07-30 14:38:00 2023-07-30 17:12:00

我不确定新的是否应该与下一个相同或偏移一秒,您的预期输出同时使用两者。另外,我不知道你的最后一行是怎么回事(不在你的原始数据中),我怀疑它是你真实数据的产物,而不是样本。EndStart15:06:40

评论

2赞 user2602640 10/13/2023
了不起。时至今日,鬼鬼祟祟的基本 R 解决方案仍然让我感到惊讶。是的,为玩具示例中的几件文物道歉。
0赞 user2602640 10/13/2023
对不起 - 答案是什么?intervals
1赞 r2evans 10/13/2023
错别字,已修复,对此感到震惊
1赞 user2602640 10/13/2023
嘎,没关系。我在应该使用的时候使用了.一切都很好:)不好意思~geom_ribbongeom_rect
1赞 r2evans 10/13/2023
我犯了同样的错误,一旦我意识到这是一个绘图问题而不是间隔问题,我就几乎犯了这个错误。很高兴你弄清楚了!
1赞 Davis Vaughan 10/14/2023 #2

使用 ivs,一个用于处理间隔的包:

library(ivs)
library(dplyr, warn.conflicts = FALSE)

start <- structure(
  c(1690740180, 1690740480, 1690741380),
  class = c("POSIXct", "POSIXt"),
  tzone = "America/Iqaluit"
)
end <- structure(
  c(1690751520, 1690742140, 1690742280),
  class = c("POSIXct", "POSIXt"),
  tzone = "America/Iqaluit"
)

x <- iv(start, end)
x
#> <iv<datetime<America/Iqaluit>>[3]>
#> [1] [2023-07-30 14:03:00, 2023-07-30 17:12:00)
#> [2] [2023-07-30 14:08:00, 2023-07-30 14:35:40)
#> [3] [2023-07-30 14:23:00, 2023-07-30 14:38:00)

iv_locate_splits(x) |>
  as_tibble() |>
  mutate(count = lengths(loc))
#> # A tibble: 5 × 3
#>                                          key loc       count
#>                                   <iv<dttm>> <list>    <int>
#> 1 [2023-07-30 14:03:00, 2023-07-30 14:08:00) <int [1]>     1
#> 2 [2023-07-30 14:08:00, 2023-07-30 14:23:00) <int [2]>     2
#> 3 [2023-07-30 14:23:00, 2023-07-30 14:35:40) <int [3]>     3
#> 4 [2023-07-30 14:35:40, 2023-07-30 14:38:00) <int [2]>     2
#> 5 [2023-07-30 14:38:00, 2023-07-30 17:12:00) <int [1]>     1

如果需要从列中获取开始/结束,请使用 和 。keyiv_start()iv_end()