#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>