#!/usr/bin/env python # coding: utf-8 # # Делаем сессии из лога событий # Загружаем библиотеки pandas и numpy, а также display для отображения dataframe'ов # In[1]: import pandas as pd import numpy as np from IPython.display import display # Загружаем лог # # Структура данных: # - id - порядковый номер события в логе # - user_id - уникальный идентификатор пользователя, совершившего событие (при решении реальной задачи анализа лога в качестве user_id может выступать IP-адрес пользователя или, например, уникальный идентификатор cookie-файла) # - date_time - время совершения события # - page - страница, на которую перешел пользователь (для решения задачи эта колонка не несет никакой пользы, я привожу её для наглядности) # In[2]: event_df = pd.read_excel('event_log.xlsx') display(event_df) # События сгенерированные разными пользователями идут в хронологическом порядке. Для удобства отсортируем их по user_id, тогда события каждого пользователя будут идти последовательно # In[3]: event_df = event_df.sort_values('user_id') display(event_df) # В колонке 'diff' для каждого события отдельного пользователя посчитаем разницу между временем посещения страницы и времененем посещения предыдущей страницы. Если страница была первой для пользователя, то значение в колонке 'diff' будет NaT, т.к. нет предыдущего значения # In[4]: event_df['diff'] = event_df.groupby('user_id')['date_time'].diff(1) display(event_df) # Из основного dataframe 'event_df' создадим вспомогательный dataframe 'session_start_df'. Этот dataframe будет содержать события, которые будут считаться первыми событиями сессий. К таким событиям относятся все события, которые произошли спустя более чем 30 минут после предудыщего, либо события, которые были первыми для пользователя (NaT в колонке 'diff') # # Также создадим во вспомогательном dataframe колонку 'session_id', которая будет содержать в себе id первого события сессии. Она пригодится, чтобы корректно отобразить идентификатор сессии, когда будем соединять данные из основного и вспомогательного dataframe # In[5]: sessions_start_df = event_df[(event_df['diff'].isnull()) | (event_df['diff'] > '1800 seconds')] sessions_start_df['session_id'] = sessions_start_df['id'] display(sessions_start_df) # С помощью функции merge_asof объединим между собой данные основного и вспомогательного dataframe'ов. Эта функция позволяет объединить данные двух dataframe'ов схожим образом с левым join'ом, но не по точному соответствию ключей, а по ближайшему. Примеры и подробности в документации: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.merge_asof.html # # Для корректной работы этой функции оба dataframe должны быть отсортированы по ключу, на основе которого будет происходить merge_asof # In[6]: event_df = event_df.sort_values('id') sessions_start_df = sessions_start_df.sort_values('id') event_df = pd.merge_asof(event_df,sessions_start_df[['id','user_id','session_id']],on='id',by='user_id') # После объединения отсортируем основной dataframe по user_id. И убедимся, что сессии корректно сопоставлены с событиями # In[7]: event_df = event_df.sort_values(['user_id','date_time']) display(event_df) # ## Что еще можно сделать? # /1. Можно найти события, которые были первыми в сессиях. Это будет полезно, если мы захотим определить страницы входа # # Найти эти события предельно просто: их идентификаторы будут равны идентификаторам сессии # In[8]: event_df['is_first_event_in_session'] = event_df['id'] == event_df['session_id'] display(event_df) # /2. Можно вычислить время, проведенное на странице, руководствуясь временем посещения следующей страницы # # Для этого сначала считаем разницу между предыдущей и следующей страницей внутри сессии # In[9]: event_df['time_on_page'] = event_df.groupby(['session_id'])['date_time'].diff(1) display(event_df) # Затем смещаем посчитанную разницу на строку выше внутри сессии # In[10]: event_df['time_on_page'] = event_df.groupby(['session_id'])['time_on_page'].shift(-1) display(event_df) # Для удобства дальнейших вычислений переведем 'time_on_page' в секунды # In[11]: event_df['time_on_page'] = event_df['time_on_page'] / np.timedelta64(1, 's') display(event_df) # На основе полученных данных мы можем посчитать простейшие показатели. А можно придумать что-нибудь по-сложнее :) # In[12]: print u'Количество пользователей: {0}'.format(event_df['user_id'].nunique()) print u'Количество сессий: {0}'.format(event_df['session_id'].nunique()) print u'Количество просмотров страниц: {0}'.format(event_df['id'].count()) print u'Среднее время просмотра страницы: {0}'.format(event_df['time_on_page'].mean()) # In[ ]: