#sql #r #oracle #sliding-window
#sql #r #Oracle #скользящее окно
Вопрос:
Представьте, что у меня есть таблица, подобная
ID | Дата |
---|---|
1 | 2021-01-01 |
1 | 2021-01-05 |
1 | 2021-01-17 |
1 | 2021-02-01 |
1 | 2021-02-18 |
1 | 2021-02-28 |
1 | 2021-03-30 |
2 | 2021-01-01 |
2 | 2021-01-14 |
2 | 2021-02-15 |
Я хочу выбрать все данные в этой таблице, но создать новый столбец с новым Event_ID. Событие определяется как все строки с одинаковым идентификатором в течение периода времени в 15 дней. Проблема в том, что я хочу, чтобы временные рамки перемещались — как в первых 3 строках: строка 2 находится в пределах 15 дней строки 1 (поэтому они относятся к одному и тому же событию). Строка 3 находится в пределах 15 дней от строки 2 (но дальше от строки 1), но я хочу, чтобы она была добавлена к тому же событию, что и раньше. (Примечание: таблица не упорядочена, как в примере, это было просто для удобства).
Вывод должен быть
ID | Дата | Event_ID |
---|---|---|
1 | 2021-01-01 | 1 |
1 | 2021-01-05 | 1 |
1 | 2021-01-17 | 1 |
1 | 2021-02-01 | 1 |
1 | 2021-02-18 | 2 |
1 | 2021-02-28 | 2 |
1 | 2021-03-30 | 3 |
2 | 2021-01-01 | 4 |
2 | 2021-01-14 | 4 |
2 | 2021-02-15 | 5 |
Я также могу сделать это в R с помощью data.table (в зависимости от эффективности / производительности)
Комментарии:
1.
Event_ID
должно быть создано в упорядоченном фрейме данных, верно? Итак, если данные не упорядочены, вы хотите сначала упорядочить их перед созданиемEvent_ID
?2. Нет, порядок событий не имеет значения. Я предполагаю, что данные должны быть каким-то образом упорядочены для правильного создания Event_ID, но это не является обязательным условием получения результата
Ответ №1:
Вот один data.table
из подходов в R :
library(data.table)
#Change to data.table
setDT(df)
#Order the dataset
setorder(df, ID, Date)
#Set flag to TRUE/FALSE if difference is greater than 15
df[, greater_than_15 := c(TRUE, diff(Date) > 15), ID]
#Take cumulative sum to create consecutive event id.
df[, Event_ID := cumsum(greater_than_15)]
df
# ID Date greater_than_15 Event_ID
# 1: 1 2021-01-01 TRUE 1
# 2: 1 2021-01-05 FALSE 1
# 3: 1 2021-01-17 FALSE 1
# 4: 1 2021-02-01 FALSE 1
# 5: 1 2021-02-18 TRUE 2
# 6: 1 2021-02-28 FALSE 2
# 7: 1 2021-03-30 TRUE 3
# 8: 2 2021-01-01 TRUE 4
# 9: 2 2021-01-14 FALSE 4
#10: 2 2021-02-15 TRUE 5
данные
df <- structure(list(ID = c(1, 1, 1, 1, 1, 1, 1, 2, 2, 2),
Date = structure(c(18628, 18632, 18644, 18659, 18676, 18686, 18716,
18628, 18641, 18673), class = "Date")),
row.names = c(NA, -10L), class = "data.frame")
Ответ №2:
r
Решением может быть использование dplyr
подхода и rleid
функции из data.table
library(dplyr)
library(data.table)
df %>% group_by(ID) %>%
mutate(Date = as.Date(Date)) %>% #mutating Date column as Date
arrange(ID, Date) %>% #arranging the rows in order
mutate(Event = if_else(is.na(Date - lag(Date)), Date - Date, Date - lag(Date)),
Event = paste(ID, cumsum(if_else(Event > 15, 1, 0)), sep = "_")) %>%
ungroup() %>% #since the event numbers are not to be created group-wise
mutate(Event = rleid(Event))
# A tibble: 9 x 3
ID Date Event
<int> <date> <int>
1 1 2021-01-01 1
2 1 2021-01-05 1
3 1 2021-01-17 1
4 1 2021-02-15 2
5 1 2021-02-28 2
6 1 2021-03-30 3
7 2 2021-01-01 4
8 2 2021-01-14 4
9 2 2021-02-15 5
Комментарии:
1. Не могли бы вы обновить свой ответ дополнительной строкой, которую я добавил к вопросу (для согласованности)?
2. Предполагает ли ваш ответ, что данные поступают упорядоченно? Если да, я бы добавил шаг упорядочивания в ваш канал (а для других людей я бы сохранил вызов библиотеки) 😉
3. Спасибо, что указали на это! @DiogoSantos, редактирую его сейчас