Как я могу фильтровать самые последние события во временном окне?

#r #database #filtering

#r #База данных #фильтрация

Вопрос:

У меня есть поток данных со временем, идентификатором, двумя типами событий (A и B) и (в настоящее время) пустыми столбцами совместного появления. Я хочу просмотреть набор данных и для каждого события B проверить, было ли A в течение предыдущих 5 секунд. Если да, то строка события получит идентификатор от события B в столбце совместного появления. В редких случаях, когда их несколько, второе совместное вхождение добавляется ко второму столбцу (или оба могут попасть в один и тот же столбец, который будет рассмотрен позже).

Я могу добиться большей части желаемого результата, используя цикл и некоторую логику, но бывают случаи, когда в течение 5 секунд после A происходит несколько Bs, или несколько, поскольку это происходит за 5 секунд до B, поэтому использование текущей строки -1 не фиксирует их.

Пример потока данных выглядит следующим образом:

 Time     ID  Event Co1 Co2
7:47:28  X1  A
7:47:30  X2  B
7:48:02  X3  A
7:48:04  X4  A
7:48:05  X5  B
7:50:11  X1  A
7:50:12  X2  B
7:50:15  X5  B
7:55:50  X6  A
7:55:52  X2  B
  

И при правильной обработке это должно привести к этому:

 Time     ID  Event Co1 Co2
7:47:28  X1  A     X2
7:47:30  X2  B
7:48:02  X3  A     X5
7:48:04  X4  A     X5
7:48:05  X5  B
7:50:11  X1  A     X2  X5
7:50:12  X2  B
7:50:15  X5  B
7:55:50  X6  A     X2
7:55:52  X2  B
  

Любая помощь или указания в правильном направлении будут высоко оценены!

Комментарии:

1. ваш идентификатор должен быть уникальным? в противном случае неясно, какова цель попадания его в col1 и col2

2. Идентификаторы уникальны, но для этой части обработки не имеет значения, относятся ли идентификаторы к Co1 или Co2 или отправляются вместе в один столбец, например, для «X2X5». Я могу разделить и переместить их на более позднем этапе

Ответ №1:

Учитывая ваш ввод:

 df <- read.table(text = "Time     ID  Event
7:47:28  X1  A
7:47:30  X2  B
7:48:02  X3  A
7:48:04  X4  A
7:48:05  X5  B
7:50:11  X1  A
7:50:12  X2  B
7:50:15  X5  B
7:55:50  X6  A
7:55:52  X2  B", header = TRUE)

# convert to HMS
df$Time <- lubridate::hms(df$Time)
  

Вы можете использовать slide_index_dfr для захвата ID s B на 5 секунд вперед и настройки его в dataframe. Затем вы можете изменить имена и добавить их обратно в свой df .

 xx <- slider::slide_index_dfr(df, df$Time, ~if(.$Event[1] == "A") .$ID[.$Event == "B"] else character(), .after = 5)
colnames(xx) <- paste0("Col", seq_len(ncol(xx)))
cbind(df, xx)
#>          Time ID Event Col1 Col2
#> 1  7H 47M 28S X1     A   X2 <NA>
#> 2  7H 47M 30S X2     B <NA> <NA>
#> 3   7H 48M 2S X3     A   X5 <NA>
#> 4   7H 48M 4S X4     A   X5 <NA>
#> 5   7H 48M 5S X5     B <NA> <NA>
#> 6  7H 50M 11S X1     A   X2   X5
#> 7  7H 50M 12S X2     B <NA> <NA>
#> 8  7H 50M 15S X5     B <NA> <NA>
#> 9  7H 55M 50S X6     A   X2 <NA>
#> 10 7H 55M 52S X2     B <NA> <NA>
  

Ответ №2:

Вот решение с foverlaps функцией из data.table пакета:

 library(data.table)
dt <- read.table(text = "Time ID Event
07:47:28 X1 A
07:47:30 X2 B
07:48:02 X3 A
07:48:04 X4 A
07:48:05 X5 B
07:50:11 X6 A
07:50:12 X7 B
07:50:15 X8 B
07:55:50 X9 A
07:55:52 X10 B", header = TRUE, sep = " ", stringsAsFactors = FALSE)


# Use data.table
setDT(dt)


# Join dataset to self over the 5 second lookback period
dt[, time := as.ITime(Time)]
dt[, time.lookback := time - as.ITime("00:00:05")]
setkey(dt, time.lookback, time)
dt.join <- foverlaps(dt, dt)
dt.join <- dt.join[order(ID)]

# You should be able to simplify this part a lot:
dt.join <- dt.join[(Event == i.Event amp; time == i.time) | (Event == "A" amp; i.Event == "B" amp; time < i.time)]
setorder(dt.join, ID, Event, -i.Event, i.time)
dt.join[i.Event == "A", i.ID := NA]
dt.join[i.Event == "A", i.Event := NA]
dt.join[i.Event == "B" amp; time == i.time, i.ID := NA]
dt.join[i.Event == "B" amp; time == i.time, i.Event := NA]
dt.join[, rn := cumsum(i.Event == "B"), .(ID, Event)]

# Now brining the dataset back to original granularity:
res <- dcast(
  dt.join, 
  formula = ID   Event ~ paste0("col", rn), 
  value.var = "i.ID"
)
res$colNA <- NULL
res
#     ID Event col1 col2
# 1:  X1     A   X2 <NA>
# 2: X10     B <NA> <NA>
# 3:  X2     B <NA> <NA>
# 4:  X3     A   X5 <NA>
# 5:  X4     A   X5 <NA>
# 6:  X5     B <NA> <NA>
# 7:  X6     A   X7   X8
# 8:  X7     B <NA> <NA>
# 9:  X8     B <NA> <NA>
# 10:  X9     A  X10 <NA>