Давай по порядку пандас запрос который решает вопрос.
(
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')
)
...
)