Usuarios activos en los últimos 30 días I

Escribe una solución para encontrar el total de usuarios activos durante un periodo de 30 días terminando el 2019-07-27 (incluyendo esta fecha). Un usuario estuvo activo si hizo al menos una actividad en ese día. Regresa el resultado en cualquier orden.

#pandas#sorting-and-grouping

Tabla: Activity

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| user_id       | int     |
| session_id    | int     |
| activity_date | date    |
| activity_type | enum    |
+---------------+---------+

- Esta tabla puede contener filas duplicadas.
- La columna activity_type es un ENUM (categoría) de tipo ('open_session', 'end_session', 'scroll_down', 'send_message').
- La tabla muestra la actividad de cada usuario en una red social.
- Nota que cada sesión pertenece a exactamente un usuario.

El formato del resultado se muestra en el siguiente ejemplo.

Ejemplo 1:

Entrada:

Tabla Activity:
+---------+------------+---------------+---------------+
| user_id | session_id | activity_date | activity_type |
+---------+------------+---------------+---------------+
| 1       | 1          | 2019-07-20    | open_session  |
| 1       | 1          | 2019-07-20    | scroll_down   |
| 1       | 1          | 2019-07-20    | end_session   |
| 2       | 4          | 2019-07-20    | open_session  |
| 2       | 4          | 2019-07-21    | send_message  |
| 2       | 4          | 2019-07-21    | end_session   |
| 3       | 2          | 2019-07-21    | open_session  |
| 3       | 2          | 2019-07-21    | send_message  |
| 3       | 2          | 2019-07-21    | end_session   |
| 4       | 3          | 2019-06-25    | open_session  |
| 4       | 3          | 2019-06-25    | end_session   |
+---------+------------+---------------+---------------+

Salida:

+------------+--------------+
| day        | active_users |
+------------+--------------+
| 2019-07-20 | 2            |
| 2019-07-21 | 2            |
+------------+--------------+

Explicación: Nota que los días sin usuarios activos no son relevantes para esta consulta.

Solución:

import datetime
import pandas as pd


def user_activity(activity: pd.DataFrame) -> pd.DataFrame:
    # `between` end date is not inclusive 27+1
    period_end = datetime.datetime(2019, 7, 28)
    period_start = period_end - pd.Timedelta('30D')

    df = activity[activity.activity_date.between(period_start, period_end)]
    no_duplicates = (
        ~df.duplicated(['user_id', 'activity_date']),
    )
    result = df.loc[no_duplicates].groupby(
        'activity_date'
    ).size().reset_index(name='active_users')

    return pd.DataFrame({
        'day': result['activity_date'],
        'active_users': result['active_users']
    })


def test_user_activity():
    data = [
        [1, 1, '2019-07-20', 'open_session'],
        [1, 1, '2019-07-20', 'scroll_down'],
        [1, 1, '2019-07-20', 'end_session'],
        [2, 4, '2019-07-20', 'open_session'],
        [2, 4, '2019-07-21', 'send_message'],
        [2, 4, '2019-07-21', 'end_session'],
        [3, 2, '2019-07-21', 'open_session'],
        [3, 2, '2019-07-21', 'send_message'],
        [3, 2, '2019-07-21', 'end_session'],
        [4, 3, '2019-06-25', 'open_session'],
        [4, 3, '2019-06-25', 'end_session']
    ]
    activity = pd.DataFrame(
        data,
        columns=['user_id', 'session_id', 'activity_date', 'activity_type']
    ).astype({
        'user_id': 'Int64',
        'session_id': 'Int64',
        'activity_date': 'datetime64[ns]',
        'activity_type': 'object'
    })

    expected = pd.DataFrame(
        [['2019-07-20', 2], ['2019-07-21', 2]],
        columns=['day', 'active_users']
    ).astype({
        'day': 'datetime64[ns]',
        'active_users': 'int'
    })

    got = user_activity(activity)
    pd.testing.assert_frame_equal(expected, got)

slackmart blog © 2024