【问题标题】:R Find overlap among time periodsR查找时间段之间的重叠
【发布时间】:2016-04-29 07:52:03
【问题描述】:

经过大量思考和谷歌搜索,我找不到解决问题的方法,希望您能帮助我。

我有一个大型数据框,其中包含一个可以重复超过 2 次的 ID 列,一个构成时间段的开始和结束日期列。我想按 ID 分组找出该 ID 的任何时间段是否与另一个时间段重叠,如果是,则通过创建一个新列来标记它,例如,说明该 ID 是否重叠。

这是一个已经包含所需新列的示例数据框:

structure(list(ID= c(34L, 34L, 80L, 80L, 81L, 81L, 81L, 94L, 
94L), Start = structure(c(1072911600, 1262300400, 1157061600, 
1277935200, 1157061600, 1277935200, 1157061600, 1075590000, 1285891200
), class = c("POSIXct", "POSIXt"), tzone = ""), End = structure(c(1262214000, 
1409436000, 1251669600, 1404079200, 1251669600, 1404079200, 1251669600, 
1264892400, 1475193600), class = c("POSIXct", "POSIXt"), tzone = ""), 
    Overlap = c(FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, 
    FALSE, FALSE)), .Names = c("ID", "Start", "End", "Overlap"
), row.names = c(NA, -9L), class = "data.frame")


 ID               Start                 End Overlap
 34 2004-01-01 00:00:00 2009-12-31 00:00:00   FALSE
 34 2010-01-01 00:00:00 2014-08-31 00:00:00   FALSE
 80 2006-09-01 00:00:00 2009-08-31 00:00:00   FALSE
 80 2010-07-01 00:00:00 2014-06-30 00:00:00   FALSE
 81 2006-09-01 00:00:00 2009-08-31 00:00:00    TRUE
 81 2010-07-01 00:00:00 2014-06-30 00:00:00    TRUE
 81 2006-09-01 00:00:00 2009-08-31 00:00:00    TRUE
 94 2004-02-01 00:00:00 2010-01-31 00:00:00   FALSE
 94 2010-10-01 02:00:00 2016-09-30 02:00:00   FALSE

在这种情况下,对于 ID“81”,两个时间段之间存在重叠,因此我想将 ID = 81 的所有行标记为 TRUE,这意味着在该 ID 的至少两行中发现了重叠.这只是一个理想的解决方案,但总的来说,我要做的就是在按 ID 分组时找出重叠,因此标记它的方式可以灵活,以防简化事情。

提前感谢您的帮助。

【问题讨论】:

标签: r overlap


【解决方案1】:

另一种选择 - 假设 df 包含您的数据框,那么:

library(data.table)
dt <- data.table(df, key=c("Start", "End"))[, `:=`(Overlap=NULL, row=1:nrow(df))]
overlapping <- unique(foverlaps(dt, dt)[ID==i.ID & row!=i.row, ID])
dt[, `:=`(Overlap=FALSE, row=NULL)][ID %in% overlapping, Overlap:=TRUE][order(ID, Start)]
#    ID               Start                 End Overlap
# 1: 34 2004-01-01 00:00:00 2009-12-31 00:00:00   FALSE
# 2: 34 2010-01-01 00:00:00 2014-08-31 00:00:00   FALSE
# 3: 80 2006-09-01 00:00:00 2009-08-31 00:00:00   FALSE
# 4: 80 2010-07-01 00:00:00 2014-06-30 00:00:00   FALSE
# 5: 81 2006-09-01 00:00:00 2009-08-31 00:00:00    TRUE
# 6: 81 2006-09-01 00:00:00 2009-08-31 00:00:00    TRUE
# 7: 81 2010-07-01 00:00:00 2014-06-30 00:00:00    TRUE
# 8: 94 2004-02-01 00:00:00 2010-01-31 00:00:00   FALSE
# 9: 94 2010-10-01 02:00:00 2016-09-30 02:00:00   FALSE

【讨论】:

  • 你有使用dplyr等效包的类似解决方案吗?
  • 不抱歉,dplyr 中没有 foverlaps 吊坠。
  • 我正在尝试将您的解决方案用于非常相似的情况,只是我不需要标记给定ID 的所有行,而只需标记重叠的行。对于这个特定的示例,重叠将是 TRUE 仅适用于行:5,6 但不是 7。是否有任何快速修改您的答案以获得这个?在这个 post 这是一个很好的讨论关于日期重叠,他们提出这个公式的条件是:max(startA, startB) &lt;= min(endA, endB)。我不知道它是否会比foverlaps 更好。任何想法
  • @DavidLeal 您是否按照您的评论设法做到了这一点?我正在努力克服这个问题
  • @SalmoSalar,不是真的。最后,我找到了一种按照@LujeA 提出的方式使用它的方法。 TRUE 表示该行至少与具有相同ID 的任何其他行有重叠,它表示双向关系。我只想有一个单向关系,但这在数学上更难以表示,并且可以克服操纵数据集。
【解决方案2】:

我认为这是您正在寻找的代码?告诉我。

data<- structure(list(ID= c(34L, 34L, 80L, 80L, 81L, 81L, 81L, 94L, 
                            94L), Start = structure(c(1072911600, 1262300400, 1157061600, 
                                                      1277935200, 1157061600, 1277935200, 1157061600, 1075590000, 1285891200
                            ), class = c("POSIXct", "POSIXt"), tzone = ""), End = structure(c(1262214000, 
                                                                                              1409436000, 1251669600, 1404079200, 1251669600, 1404079200, 1251669600, 
                                                                                              1264892400, 1475193600), class = c("POSIXct", "POSIXt"), tzone = ""), 
                      Overlap = c(FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, 
                                  FALSE, FALSE)), .Names = c("ID", "Start", "End", "Overlap"
                                  ), row.names = c(NA, -9L), class = "data.frame")

library("dplyr")
library("lubridate")

overlaps<- function(intervals){
        for(i in 1:(length(intervals)-1)){
                for(j in (i+1):length(intervals)){
                        if(int_overlaps(intervals[i],intervals[j])){
                                return(TRUE)
                        }
                }
        }
        return(FALSE)
}

data %>%
        mutate(Interval=interval(Start,End))%>%
        group_by(ID) %>% 
       do({
               df<-.
               ovl<- overlaps(df$Interval)
               return(data.frame(ID=df$ID[1], ovl))
       })

另外,我希望有人对我的overlaps 函数提出更优雅的解决方案..

【讨论】:

  • 谢谢,这很好用。由于某种原因,lukeA 的解决方案不起作用,尽管它看起来像一个更简单的解决方案
猜你喜欢
  • 1970-01-01
  • 2020-02-19
  • 2020-02-28
  • 2020-02-24
  • 1970-01-01
  • 2020-07-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多