如何在Pandas中按时间排序DataFrame同时维持配对事件的顺序?
看起来你遇到的核心问题是:既要按时间整体排序,又得保证每个Code对应的事件对(比如Enter-Out、In-Out/Exit)能绑定在一起,对吧?直接用sort_values的常规字段组合确实搞不定——毕竟同一个Code的事件可能在不同时间点触发,得给每个事件对做个专属“标记”,再基于标记来排序。
我给你提供一个高效的向量化解法,不用写循环,步骤如下:
步骤1:给每个事件对生成组ID
每个Enter或In都是一个事件的起点,后面跟着对应的Out或Exit。我们可以用cumsum给每个起点事件分配递增的组号,让同一对事件共享同一个组ID:
# 按ID和Code分组,给每个Enter/In开启的事件对分配组ID df['group_id'] = df.groupby(['ID', 'Code'])['Type'].transform( lambda x: (x.isin(['Enter', 'In'])).cumsum() )
步骤2:计算每个组的最早时间
为了保证整体按事件发生的先后排序,我们需要取每个组的最早时间作为排序依据(比如Code=588的In在11:00,Out在12:30,这个组的最早时间是11:00,会排在12:30开始的Code=322组前面):
# 计算每个组的最早时间,用于整体排序 df['group_time'] = df.groupby(['ID', 'Code', 'group_id'])['Time'].transform('min')
步骤3:定义事件类型的排序优先级
我们要确保组内的事件顺序正确:Enter/In在前,Out/Exit在后,所以给每种类型分配一个排序权重:
# 定义Type的排序优先级,确保开始事件在前,结束事件在后 type_order = {'Enter': 0, 'In': 1, 'Out': 2, 'Exit': 3} df['type_rank'] = df['Type'].map(type_order)
步骤4:执行排序并清理临时列
最后按ID→group_time(整体时间顺序)→group_id(同一组绑定)→type_rank(组内事件顺序)排序,再删掉临时生成的列:
# 执行排序 sorted_df = df.sort_values( by=['ID', 'group_time', 'group_id', 'type_rank'] ).drop(['group_id', 'group_time', 'type_rank'], axis=1)
运行这段代码后,你就能得到和示例中完全一致的排序结果了。而且这个方法对你原始数据中的带日期时间戳也完全适用——只要Time列是datetime类型,min计算和排序逻辑都会正常工作。
如果遇到一个Code有多个连续的In-Out事件,这个方法也能自动处理:每个In都会开启一个新的group_id,对应的Out会被分到同一个组里,不会出现混乱。
备注:内容来源于stack exchange,提问作者user29987781

