Как в pandas объединить последовательные события одного типа в один интервал?

Как можно сгруппировать последовательные серии событий одного типа в DataFrame в одну строку?
  • 12 мая 2024 г. 9:40
Ответы на вопрос 2
Для объединения последовательных событий одного типа в один интервал в pandas можно воспользоваться методом groupby() с последующим применением функций агрегации. 

Например, если у нас есть DataFrame df с колонками 'event_type' и 'timestamp', и мы хотим объединить все последовательные события одного типа в один интервал, можно сделать следующим образом:

```python
import pandas as pd

# пример данных
data = {'event_type': ['A', 'A', 'B', 'B', 'A', 'A'],
        'timestamp': ['2022-01-01 01:00:00', '2022-01-01 02:00:00', '2022-01-01 03:00:00', '2022-01-01 04:00:00', '2022-01-01 05:00:00', '2022-01-01 06:00:00']}
df = pd.DataFrame(data)

# преобразуем столбец timestamp в datetime
df['timestamp'] = pd.to_datetime(df['timestamp'])

# группируем данные по event_type и создаем столбец с интервалом времени
df['group'] = (df['event_type'] != df['event_type'].shift()).cumsum()

# сгруппируем данные по event_type и group, найдем минимальное и максимальное значение времени
result = df.groupby(['event_type', 'group']).agg({'timestamp': ['min', 'max']}).reset_index()

print(result)
```

Данный код сгруппирует последовательные события одного типа в один интервал, указывая начальное и конечное время каждого интервала.

Чтобы сгруппировать последовательные серии событий одного типа в DataFrame в одну строку, можно воспользоваться методом groupby() и функцией agg() с передачей словаря с агрегирующими функциями.
Давай по порядку пандас запрос который решает вопрос. 
(
    df
    .assign(
        groups=(df['EventType'] != df['EventType'].shift())
        .cumsum()
    )
    .groupby('groups'
    )
    .agg(
        first= pd.NamedAgg(column='EventTime',aggfunc=lambda x: np.min(x)),
        last= pd.NamedAgg(column='EventTime',aggfunc=lambda x: np.max(x)),
        EventType= pd.NamedAgg(column='EventType',aggfunc=lambda x: set(x).pop()),
        user_id=pd.NamedAgg(column='user_id',aggfunc=lambda x: set(x).pop()),
        )
    .reset_index(drop=True)
    .loc[:,['user_id','EventType','first','last']]
)


Ключевая история это группировка с последовательно повторяющимися значениями. Вот этот запрос по сути решает весь вопрос
(
    df
    .groupby(
        (df["EventType"] != df["EventType"].shift())
        .cumsum()
    )
    .agg({"EventTime" : ["min", "max"]})
)
Остальное это манипуляции для идентичного твоему вывода (писал на скорую руку совместил агрегации с трансформациями) что не есть хорошо, я бы поработал и сделал лучше. В целом сработает и для строк, но лучше привести EventTime к типу данных datetime64[ns]. Сделать это можно
(
    df.assign(
        EventTime=lambda x: pd.to_datetime(x['EventTime'],format='%Y-%m-%d %H:%M:%S')
    )
   ... 
)
Похожие вопросы