Найти интервалы соответствия в кадре данных в диапазоне от двух значений столбца

У меня есть кадр данных связанных с временем событий.

Вот пример:

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 разных имен. Каждый из этих людей появляется в трех разных последовательностях, A-C. Затем они имеют активные периоды времени во время этих последовательностей, и я отмечаю события начала/конца и вычисляют продолжительность.

Я хотел бы изолировать каждого человека и найти, когда у них есть соответствующие временные интервалы с людьми как в противоположном, так и в одинаковом идентификаторе группы.

Используя приведенные выше данные примера, я хочу найти, когда Джон и Адам появляются в одной и той же последовательности, в то же время. Затем я хочу сравнить Джона с остальными 17 именами в ID1/ID2.

Я не должен соответствовать точной сумме общего "активного" времени, я просто надеюсь изолировать ряды, которые являются общими.

Мои удобства в использовании dplyr, но я пока не могу взломать. Я осмотрелся и увидел похожие примеры с матрицами смежности, но они с точными точными точками данных. Я не могу понять стратегию с диапазоном/интервалом.

Спасибо!

UPDATE: Вот пример желаемого результата

  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  

Я думаю, что вы выделили каждую строку событий для Джона, отметьте начальный и конечный временные рамки, а затем перейдете к каждому имени и событию для остальной части фрейма данных, чтобы найти точки времени, которые соответствуют первым в той же последовательности, а затем во второй раз по сравнению с обозначенным временем начала/окончания времени Джона.

Ответ 1

Как я понимаю, вы хотите вернуть любую строку, где событие для Джона с определенным порядковым номером перекрывает событие для кого-то другого с тем же значением последовательности. Чтобы достичь этого, вы можете использовать split-apply-comb для разделения по последовательности, идентифицировать перекрывающиеся строки и затем повторно объединить:

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], который перекрывает последовательность А для Адама с временным интервалом [19, 75].

Это может быть легко сопоставлено с языком 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") для получения предыдущего вывода. Создание перекрытий для каждой пары пользователей теперь можно выполнить с помощью combn и apply:

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