Помощь с подсчётом в датасете pandas

Имеется следующий датасет:

date user event_type parameter
0 2020-04-01_00:01:08 770906 770906 3 unknown
1 2020-04-01_00:00:30 527877 527877 1 text
2 2020-04-01_00:01:12 539948 539948 3 picture
3 2020-04-01_00:01:20 107541 107541 3 picture
4 2020-04-01_00:01:38 374954 374954 4 text

Надо найти день, когда число уникальных пользователей, отправивших текстовое сообщение (event_type=4, parameter=text), было максимальным.

Также нужно определить 20-минутный интервал [time; time + 20 min), в течение которого произошло больше всего событий? Если таких интервалов несколько, нужно найти начало самого позднего.

Описание переменных:

date        object
user        int64
event_type  int64
parameter   object
dtype: object   

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

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

Создадим DataFrame по подобию:

import pandas as pd
import numpy as np
from random import randint as r

day = lambda : "%02d" % r(1,30)
hour = lambda : "%02d" % r(0,23)
min_sec = lambda : "%02d" % r(0,59)
user = lambda : "%06d" % r(100000,999999)

rows_c=100000
df = pd.DataFrame({
    'date': ['2020-04-{}_{}:{}:{}'.format(day(),hour(),min_sec(),min_sec()) for _ in range(0,rows_c)],
    'user': ["%06d" % r(100000,999999) for _ in range(0,rows_c)],
    'event_type': [r(1,4) for _ in range(0,rows_c)],
    'parameter': [['unknown', 'text', 'picture'][r(0,2)] for _ in range(0,rows_c)]
})
df.date = df.date + ' ' + df.user
df
Вывод:

        date                        user    event_type  parameter
0       2020-04-08_16:12:07 395528  395528  2           text
1       2020-04-10_21:10:21 682091  682091  2           unknown
2       2020-04-30_15:06:42 738315  738315  3           picture
3       2020-04-01_20:09:04 723756  723756  2           picture
4       2020-04-20_09:04:02 859750  859750  4           unknown
... ... ... ... ...
99995   2020-04-05_01:45:29 801973  801973  2           picture
99996   2020-04-07_05:48:39 379318  379318  2           text
99997   2020-04-11_04:24:33 581294  581294  2           picture
99998   2020-04-13_13:17:48 807151  807151  4           text
99999   2020-04-24_10:34:03 362205  362205  2           text

100000 rows × 4 columns

Задача 1

Надо найти день, когда число уникальных пользователей, отправивших текстовое сообщение (event_type=4, parameter=text), было максимальным.

В первую очередь приведём колонку date к формату datetime. Затем делаем фильтр по event_type и parameter. Убираем дубликаты из user, чтобы получить уникальных пользователей. Делаем groupby по дням и выводим день в котором было больше всего этих пользователей.

df.date = df.date.str.replace(r'\s.*','', regex=True)
df.date = pd.to_datetime(df.date, format='%Y-%m-%d_%H:%M:%S')

filtered_df = df[(df.event_type == 4) & (df.parameter == 'text')]
filtered_df = filtered_df.drop_duplicates(subset=['user'])
filtered_df.groupby(df.date.dt.day).size().idxmax()
Вывод:
10

Задача 2

Также нужно определить 20-минутный интервал [time; time + 20 min), в течение которого произошло больше всего событий? Если таких интервалов несколько, нужно найти начало самого позднего.

Интервал нужно определить на отфильтрованной таблице? Далее код работает с неотфильтрованной, т.к. из задачи не ясно.

max_c = 0
for x in df.index:
    count = df.date[(df.date >= df.date.loc[x]) & (df.date < df.date.loc[x] + pd.Timedelta(20, "m"))].count()
    if count > max_c:
        ixs = [x]
        max_c = count
    elif count == max_c:
        ixs.append(x)
df.loc[ixs].date.idxmax()
Вывод:
76910

Получили index наиболее позднего события в интервале 20-и минут которого было наибольшее количество событий.

Сами события можно вывести через:

ix = df.loc[ixs].date.idxmax()
df[(df.date >= df.date.loc[ix]) & (df.date < df.date.loc[ix] + pd.Timedelta(20, "m"))]

Делать итератор, конечно, не очень хорошо, можно было бы сделать через:

df.index = df.date
gr = df.groupby([pd.Grouper(freq='20min')])

Но в подходе с итератором я больше уверен.

→ Ссылка