Как найти среднее время между определенными событиями, которые входят в одну пользовательскую сессию?

Пожалуйста, помогите найти среднее время между определенными событиями входящих в одну сессию.

Например, есть датафрейм:

data = {
'id': [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5],
'event': ['login', 'news', 'comment', 'login', 'news', 'advt', 'login', 'like', 'comment', 'login', 'news', 'comment', 'login'],
'data': ['2023-03-15 10:00:00', '2023-03-15 10:05:00', '2023-03-15 10:10:00', '2023-03-15 10:15:00', 
         '2023-03-16 11:00:01', '2023-03-16 11:05:06', '2023-03-16 11:10:10',
         '2023-03-17 12:00:02', '2023-03-17 12:05:00', '2023-03-17 12:10:30',
         '2023-03-18 13:00:05', '2023-03-18 13:05:11', '2023-03-18 13:10:00', '2023-03-18 13:10:00']}

id - это id сессии. Как можно у каждой id сессии найти среднее время между login и между событием news или advt? Последовательность шагов строгая, первый шаг login второй выбранные события. Иногда в сессиях проскакивает что login был позже. Так же как можно код оптимизировать, чтобы он по возможности более оперативно обрабатывал большие датафреймы?


Ответы (2 шт):

Автор решения: CrazyElf

Ну я вам покажу примерный ход действий, дальше сами приспособите к своим задачам:

import pandas as pd

data = {
'id': [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5],
'event': ['login', 'news', 'comment', 'login', 'news', 'advt', 'login', 'like', 'comment', 'login', 'news', 'comment', 'login'],
'data': ['2023-03-15 10:00:00', '2023-03-15 10:05:00', '2023-03-15 10:10:00', '2023-03-15 10:15:00', 
         '2023-03-16 11:00:01', '2023-03-16 11:05:06', '2023-03-16 11:10:10',
         '2023-03-17 12:00:02', '2023-03-17 12:05:00', '2023-03-17 12:10:30',
         '2023-03-18 13:00:05', '2023-03-18 13:05:11', '2023-03-18 13:10:00']} #, '2023-03-18 13:10:00']}

df = pd.DataFrame(data)
# на всякий случай сортируем
df = df.sort_values(['id', 'data'])
df['data'] = pd.to_datetime(df['data'])
# отбираем только интересующие нас события
df1 = df[df.event.isin(['login','news'])].copy()
# формируем парные события и разницу между ними
df2 = df1.shift()
df1['evev'] = df2.event + '-' + df1.event
df1['diff'] = df1.data - df2.data
# выводим среднюю разницу по интересующей нас паре событий
print(df1[df1['evev'] == 'login-news']['diff'].mean())

Вывод:

0 days 16:33:12
→ Ссылка
Автор решения: Алексей Р

Примечания в коде

data = {
    'id': [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5],
    'event': ['login', 'news', 'comment', 'login', 'news', 'advt', 'login', 'like', 'comment', 'login', 'news', 'comment', 'login'],
    'data': ['2023-03-15 10:00:00', '2023-03-15 10:05:00', '2023-03-15 10:10:00', '2023-03-15 10:15:00',
             '2023-03-16 11:00:01', '2023-03-16 11:05:06', '2023-03-16 11:10:10',
             '2023-03-17 12:00:02', '2023-03-17 12:05:00', '2023-03-17 12:10:30',
             '2023-03-18 13:00:05', '2023-03-18 13:05:11', '2023-03-18 13:10:00']}

df = pd.DataFrame(data).astype({'data': 'datetime64[ns]'}) # создаем фрейм и преобразуем столбец `data` в тип даты/времени

logint = df[df['event'].eq('login')].groupby('id').last()['data']  # находим дату последнего (если их несколько) логинов для каждого ид
df = df.merge(logint, left_on='id', right_index=True, suffixes=('_event', '_login'))  # проставляем во все строки фрейма моменты ранее найденных логинов для каждого ид
df = df[df['event'].isin(['news', 'advt'])]  # фильтруем фрейм, оставляя только нужные события
df['delta'] = df['data_event'].sub(df['data_login'])  # вычитаем из моментов событий моменты логинов
avg = df.groupby('id')['delta'].mean()  # группируем фрейм по ид, находя по каждой группе среднее время. Если нужно в секундах, дописываем в конце .dt.total_seconds(), если в часах - еще .div(3600)
print(avg)
id
1          0 days 00:05:00
2   1 days 00:47:33.500000
4          1 days 00:49:35
Name: delta, dtype: timedelta64[ns]
→ Ссылка