【问题标题】:Find matching intervals in data frame by range of two column values通过两列值的范围查找数据框中的匹配区间
【发布时间】:2015-10-17 22:39:32
【问题描述】:

我有一个时间相关事件的数据框。

这是一个例子:

Name     Event Order     Sequence     start_event     end_event     duration     Group 
JOHN     1               A               0               19          19           ID1
JOHN     2               A               60              112         52           ID1  
JOHN     3               A               392             429         37           ID1  
JOHN     4               B               282             329         47           ID1
JOHN     5               C               147             226         79           ID1  
JOHN     6               C               566             611         45           ID1  
ADAM     1               A               19              75          56           ID2
ADAM     2               A               384             407         23           ID2  
ADAM     3               B               0               79          79           ID2  
ADAM     4               B               505             586         81           ID2
ADAM     5               C               140             205         65           ID2  
ADAM     6               C               522             599         77           ID2  

基本上有两个不同的组,ID 1 和 2。对于每个组,有 18 个不同的名称。这些人中的每一个都以 3 个不同的顺序出现,A-C。然后它们在这些序列中有活动时间段,我标记开始/结束事件并计算持续时间。

我想隔离每个人,并找出他们何时与同一组 ID 中的人具有匹配的时间间隔。

使用上面的示例数据,我想找出 John 和 Adam 在同一序列中同时出现的时间。然后,我想将 John 与 ID1/ID2 中的其他 17 个名字进行比较。

不需要匹配共享“活动”时间的确切数量,我只是希望隔离常见的行。

我的安慰是使用 dplyr,但我还不能破解它。我环顾四周,看到了一些具有邻接矩阵的类似示例,但这些示例具有精确且精确的数据点。我无法弄清楚范围/间隔的策略。

谢谢!

更新: 这是所需结果的示例

  Name     Event Order     Sequence     start_event     end_event     duration     Group 
    JOHN     3               A               392             429         37           ID1        
    JOHN     5               C               147             226         79           ID1  
    JOHN     6               C               566             611         45           ID1  
    ADAM     2               A               384             407         23           ID2  
    ADAM     5               C               140             205         65           ID2  
    ADAM     6               C               522             599         77           ID2  

我认为您应该为 John 隔离每个事件行,标记开始/结束时间框架,然后遍历数据框架其余部分的每个名称和事件,以找到最适合同一序列的时间点,其次是针对约翰的基准开始/结束时间框架。

【问题讨论】:

标签: r dplyr


【解决方案1】:

据我了解,您希望返回具有特定序列号的 John 的事件与具有相同序列值的其他任何人的事件重叠的任何行。为此,您可以使用 split-apply-combine 按顺序拆分,识别重叠行,然后重新组合:

overlap <- function(start1, end1, start2, end2) pmin(end1, end2) > pmax(start2, start1)
do.call(rbind, lapply(split(dat, dat$Sequence), function(x) {
  jpos <- which(x$Name == "JOHN")
  njpos <- which(x$Name != "JOHN")
  over <- outer(jpos, njpos, function(a, b) {
    overlap(x$start_event[a], x$end_event[a], x$start_event[b], x$end_event[b])
  })
  x[c(jpos[rowSums(over) > 0], njpos[colSums(over) > 0]),]
}))
#      Name EventOrder Sequence start_event end_event duration Group
# A.2  JOHN          2        A          60       112       52   ID1
# A.3  JOHN          3        A         392       429       37   ID1
# A.7  ADAM          1        A          19        75       56   ID2
# A.8  ADAM          2        A         384       407       23   ID2
# C.5  JOHN          5        C         147       226       79   ID1
# C.6  JOHN          6        C         566       611       45   ID1
# C.11 ADAM          5        C         140       205       65   ID2
# C.12 ADAM          6        C         522       599       77   ID2

请注意,我的输出包括问题中未显示的另外两行 - 来自时间范围 [60, 112] 的 John 的序列 A,它与时间范围 [19, 75] 的 Adam 的序列 A 重叠。

这可以很容易地映射到dplyr 语言:

library(dplyr)
overlap <- function(start1, end1, start2, end2) pmin(end1, end2) > pmax(start2, start1)
sliceRows <- function(name, start, end) {
  jpos <- which(name == "JOHN")
  njpos <- which(name != "JOHN")
  over <- outer(jpos, njpos, function(a, b) overlap(start[a], end[a], start[b], end[b]))
  c(jpos[rowSums(over) > 0], njpos[colSums(over) > 0])
}
dat %>%
  group_by(Sequence) %>%
  slice(sliceRows(Name, start_event, end_event))
# Source: local data frame [8 x 7]
# Groups: Sequence [3]
# 
#     Name EventOrder Sequence start_event end_event duration  Group
#   (fctr)      (int)   (fctr)       (int)     (int)    (int) (fctr)
# 1   JOHN          2        A          60       112       52    ID1
# 2   JOHN          3        A         392       429       37    ID1
# 3   ADAM          1        A          19        75       56    ID2
# 4   ADAM          2        A         384       407       23    ID2
# 5   JOHN          5        C         147       226       79    ID1
# 6   JOHN          6        C         566       611       45    ID1
# 7   ADAM          5        C         140       205       65    ID2
# 8   ADAM          6        C         522       599       77    ID2

如果您希望能够计算指定用户对的重叠,这可以通过将操作包装到指定要处理的用户对的函数中来完成:

overlap <- function(start1, end1, start2, end2) pmin(end1, end2) > pmax(start2, start1)
pair.overlap <- function(dat, user1, user2) {
  dat <- dat[dat$Name %in% c(user1, user2),]
  do.call(rbind, lapply(split(dat, dat$Sequence), function(x) {
    jpos <- which(x$Name == user1)
    njpos <- which(x$Name == user2)
    over <- outer(jpos, njpos, function(a, b) {
      overlap(x$start_event[a], x$end_event[a], x$start_event[b], x$end_event[b])
    })
    x[c(jpos[rowSums(over) > 0], njpos[colSums(over) > 0]),]
  }))
}

您可以使用pair.overlap(dat, "JOHN", "ADAM") 来获取之前的输出。现在可以使用combnapply 为每对用户生成重叠:

apply(combn(unique(as.character(dat$Name)), 2), 2, function(x) pair.overlap(dat, x[1], x[2]))

【讨论】:

  • A,John 的 [0, 19] 和 A,Adam 的 [19. 75] 怎么样?
  • @Arun 我没有在overlap 函数中使用&gt; 包含重叠为0 的情况。如果 OP 想要包含端点接触但间隔之间没有重叠的情况,他们可以将其更改为 &gt;= in overlap
  • 这里的重叠是 1,而不是 0。那么您使用闭区间 [] 会产生误导。
  • 有 17 个名字,OP 想要比较 all 的名字
  • @wetcoaster 前两个代码块处理一个名称(在这种情况下为 John)与所有其他名称的所有重叠。您可以简单地将“JOHN”更改为其他名称,以检查不同名称的所有重叠。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-27
  • 1970-01-01
  • 2020-01-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多