Вы можете объединить эту идиому с неэквивалентным соединением:
library(data.table)
library(lubridate)
df <- read.table(header=T, text="
process_id date event
00001 00/01/20 1
00002 00/01/20 1
00003 00/01/20 0
00001 01/01/19 1
00002 01/01/19 0
00003 01/01/19 1")
dt <- as.data.table(df)
dt[, date := as.POSIXct(date, format = "%y/%m/%d")]
dt[, prev_year := date - lubridate::dyears(1L)]
positives <- dt[.(1), .(process_id, date, event), on = "event"]
dt[, prev_event := positives[.SD,
.(x.event),
on = .(process_id, date < date, date >= prev_year),
mult = "last"]]
print(dt)
process_id date event prev_year prev_event
1: 1 2000-01-20 1 1999-01-20 NA
2: 2 2000-01-20 1 1999-01-20 NA
3: 3 2000-01-20 0 1999-01-20 NA
4: 1 2001-01-19 1 2000-01-20 1
5: 2 2001-01-19 0 2000-01-20 1
6: 3 2001-01-19 1 2000-01-20 NA
При необходимости настройте формат даты,
и удалите prev_year
впоследствии, если вам это не нужно.
И если вы хотите добавить также дату, когда произошло предыдущее событие,
изменить строку перед print
на:
dt[, `:=`(
c("prev_event", "prev_date"),
positives[.SD, .(x.event, x.date), on = .(process_id, date < date, date >= prev_year), mult = "last"]
)]
Немного бесстыдного штекера:
с новой версией table.express
,
Вы также можете написать выше как:
library(table.express)
library(data.table)
library(lubridate)
dt <- as.data.table(df) %>%
start_expr %>%
mutate(date = as.POSIXct(date, format = "%y/%m/%d")) %>%
mutate(prev_year = date - lubridate::dyears(1L)) %>%
end_expr
positives <- dt %>%
start_expr %>%
filter_on(event = 1) %>%
select(process_id, date, event) %>%
end_expr
dt %>%
start_expr %>%
mutate_join(positives,
process_id, date > date, prev_year <= date,
mult = "last",
.SDcols = c(prev_event = "event", prev_date = "date")) %>%
end_expr
print(dt)
process_id date event prev_year prev_event prev_date
1: 1 2000-01-20 1 1999-01-20 NA <NA>
2: 2 2000-01-20 1 1999-01-20 NA <NA>
3: 3 2000-01-20 0 1999-01-20 NA <NA>
4: 1 2001-01-19 1 2000-01-20 1 2000-01-20
5: 2 2001-01-19 0 2000-01-20 1 2000-01-20
6: 3 2001-01-19 1 2000-01-20 NA <NA>