如何用Pandas将含起止事件的时间序列DataFrame重塑为起止列格式?
解决方案
可以通过生成配对分组ID,结合分组聚合的方式处理这种包含异常情况的事件配对需求,具体步骤如下:
步骤1:生成配对分组ID
首先创建一个触发列,标记每个新配对组的起始位置,然后通过累计求和得到唯一的配对ID:
import pandas as pd # 初始化原始DataFrame df1 = pd.DataFrame({'Time': ['1:42 AM','2:30 AM','3:29 AM','4:19 AM','4:37 AM','4:59 AM','5:25 AM','5:33 AM','6:48 AM'], 'Event': ['End','Start','End','Start','End','Start','Start','End','Start']}) # 创建触发列,标记新配对组的开始 trigger = pd.Series(False, index=df1.index) # 第一行是End,单独作为一个配对组 trigger.iloc[0] = df1.iloc[0]['Event'] == 'End' # 所有Start事件都作为新配对组的开始 trigger[1:] = df1['Event'].iloc[1:] == 'Start' # 连续的End事件(前一行不是Start)也作为新配对组的开始 trigger[1:] |= (df1['Event'].iloc[1:] == 'End') & (df1['Event'].iloc[:-1] != 'Start') # 生成配对ID df1['pair_id'] = trigger.cumsum()
步骤2:分组聚合生成目标DataFrame
通过分组聚合,提取每个配对组中的Start和End时间,没有对应事件的位置填充空字符串:
# 分组聚合,处理每个配对组的Start和End df2 = df1.groupby('pair_id').agg( Start=('Time', lambda x: x[df1.loc[x.index, 'Event'] == 'Start'].iloc[0] if any(df1.loc[x.index, 'Event'] == 'Start') else ''), End=('Time', lambda x: x[df1.loc[x.index, 'Event'] == 'End'].iloc[0] if any(df1.loc[x.index, 'Event'] == 'End') else '') ).reset_index(drop=True) print(df2)
运行后输出结果与预期完全一致:
Start End 0 1:42 AM 1 2:30 AM 3:29 AM 2 4:19 AM 4:37 AM 3 4:59 AM 4 5:25 AM 5:33 AM 5 6:48 AM
逻辑说明
- 针对开头无前置Start的End事件:单独生成一个配对组,对应结果中Start为空、End为该时间的行
- 针对连续的Start事件:每个Start都生成独立配对组,后续的End会匹配最近的未配对Start
- 针对无对应End的Start事件:配对组中只有Start,End位置自动填充空字符串
内容的提问来源于stack exchange,提问作者MBlankfield
相关产品推荐
相关产品推荐

