в датафрейме.
Есть таблица с пользователями, там есть время регистрации и время покупок. Мне нужно определить время, прошедшее со времени регистрации до первой покупки. Регистрация одна на пользователя, это легко, а как найти первую покупку из всех, сделанных конкретным пользователем?
можно так: 1. отфильтровать и оставить только покупки 2. сгрупировать по user 3. отсортировать по дате 4. выбрать первую запись 5. сделать джойн с фильтром по регистрации 6. посчитать разницу во времени
? data.table( user_id = c(1, 1, 1, 2, 2, 2, 3, 3), date = as.Date(c( '2022-01-01', '2022-02-01', '2022-01-03', '2022-04-01', '2022-05-01', '2022-06-01', '2022-08-01', '2022-07-01')), bablo = c(3, 3, 7, 5, 6, 1, 9, 3) ) %>% setorder(user_id, -date) %>% .[, head(.SD, 1), by = "user_id"] %>% view()
Эх, говорила мне мама - учи дата тейбл! :) Спасибо
а я бы отсортировал по дате, сгруппировал по пользователю и event_type, сделал бы slice(1), pivot_wider по event_type и дате, а дальше бы просто вычел purchase-registration
.[, head(.SD, 1), by = "user_id"] Этот кусок оставляет ноль столбцов
1. Все работает верно (только View, а не view надо писать). Типовой подход. 2. Типовой вопрос. Я немного писал о подобных задачках в ряде публикаций, при желании можно ознакомиться: - https://habr.com/ru/post/558250/ - https://habr.com/ru/post/526194/ - https://habr.com/ru/post/461463/ - https://habr.com/ru/company/ruvds/blog/562906/ - https://habr.com/ru/post/555476/
Увидел в формулировке задачи термин "датафрейм", использовал дт близкий к нему
У меня всё норм Мб надо вместо view использовать View. Но view съедается если подключен tidyverse. В то же время, я просто психанул и в свой пакет-фреймворк подгрузил View как view по определению, потому что 100500 раз лишний tab-жать - очень плохая задумка авторов дататейбла
Так ещё можно в data.table # Придумаем данные, вытянем таблицу patients из eventdataR и преобразуем к нужному виду library("eventdataR") dates <- patients %>% setDT %>% .[,.(patient,time,handling)] %>% .[handling=="Registration",handling:="registration"] %>% .[handling!="registration",handling:="purchase"] %>% setnames(old=c("patient","time","handling"),new=c("user_id","event_date","event_type")) %>% # дальше собственно код решающий задачу .[,.(event_date=min(event_date)),by=.(event_type,user_id)] %>% dcast(user_id~event_type,value.var="event_date") %>% .[,dift:=difftime(purchase,registration,units = "hours")]
Если честно, то не сильно круто. По различным причинам, много внутренних циклов, множественные сортировки, доп. преобразования, менджемент памяти. Так будет веселее (f3()): # Придумаем данные, вытянем таблицу patients из eventdataR и преобразуем к нужному виду library(eventdataR) library(data.table) library(magrittr) raw_dt <- patients %>% setDT %>% .[,.(patient,time,handling)] %>% .[handling=="Registration",handling:="registration"] %>% .[handling!="registration",handling:="purchase"] %>% setnames(old=c("patient","time","handling"),new=c("user_id","timestamp","event_type")) %>% setorder(user_id, timestamp) %>% .[, ts := as.numeric(timestamp)] evt_dt <- rep(list(raw_dt), 1000) %>% rbindlist() # дальше собственно код решающий задачу f1 <- function(){ evt_dt %>% .[,.(timestamp = min(timestamp)),by=.(event_type,user_id)] %>% dcast(user_id ~ event_type, value.var="timestamp") %>% .[,dift:=difftime(purchase,registration, units = "hours")] } f3 <- function(){ evt_dt[, delta_t := ts - ts[1], by = user_id] %>% .[event_type == "purchase", head(.SD, 1), by = user_id] }
Обсуждают сегодня