Pandas中结合时间间隔与组首距离规则拆分序列生成分组ID
问题描述
现有包含Key(键)和Timestamp(时间戳)字段的Pandas DataFrame,样例数据如下:
| Key | Timestamp |
|---|---|
| A | 12.00 |
| A | 12.30 |
| A | 13.00 |
| A | 14.00 |
| B | 12.00 |
| B | 13.30 |
需要针对每个Key下的行按如下规则分组:
- 若当前行时间戳与同Key下上一行时间戳间隔超过30分钟,则当前行归属新分组
- 若当前行时间戳与所属分组首行的时间戳间隔超过1小时,则当前行归属新分组
期望输出新增全局唯一的Group_id列,样例效果如下:
| Key | Timestamp | Group_id |
|---|---|---|
| A | 12.00 | 0 |
| A | 12.30 | 0 |
| A | 13.00 | 0 |
| A | 13.30 | 1 |
| B | 12.00 | 2 |
| B | 13.30 | 3 |
目前已完成DataFrame按时间戳排序,可单独实现单个条件判断:
- 相邻时间间隔判断代码:
df.groupby('Key')['Timestamp'].diff() > thirty_minutes
- 按1小时窗口分组的尝试代码:
df.groupby([pd.Grouper(key='Timestamp', freq='1h')
但无法结合两个条件生成符合要求的全局唯一Group_id列。
实现方案
第二个分组规则依赖动态变化的当前分组首行时间,无法直接用内置向量化groupby方法一步完成,最稳妥的实现方式是按Key分组后逐行遍历判断,动态维护分组首行时间,最终生成全局唯一ID。
前置处理
先确保时间字段为Pandas标准datetime类型,若字段已经是datetime格式可跳过转换步骤:
import pandas as pd # 示例:把数值格式的小时.分钟时间转为datetime,可根据实际时间格式调整转换逻辑 def float_to_time(x): hour = int(x) minute = int(round((x - hour)*60)) return pd.Timestamp(year=2024, month=1, day=1, hour=hour, minute=minute) df['Timestamp'] = df['Timestamp'].apply(float_to_time) thirty_min = pd.Timedelta(minutes=30) one_hour = pd.Timedelta(hours=1)
生成分组ID
group_labels = [] global_group_id = 0 # sort=False保持原有排序,不打乱提前排好的时间顺序 for key, group in df.groupby('Key', sort=False): # 每个Key的第一行默认归属新分组 current_group_start = group.iloc[0]['Timestamp'] group_labels.append(global_group_id) # 从第二行开始逐行判断 for idx in range(1, len(group)): curr_ts = group.iloc[idx]['Timestamp'] prev_ts = group.iloc[idx-1]['Timestamp'] # 触发任意一个新分组规则则新建分组 if (curr_ts - prev_ts > thirty_min) or (curr_ts - current_group_start > one_hour): global_group_id += 1 current_group_start = curr_ts group_labels.append(global_group_id) # 当前Key所有行遍历完成,为下一个Key的首行预留新分组ID global_group_id += 1 df['Group_id'] = group_labels
方案说明
- 逻辑完全对齐给定的两个分组规则,不会出现时间边界判断错误
- 十万行级数据下遍历性能完全够用,百万行以上数据可基于numba优化遍历逻辑提速
- 生成的
Group_id为全局递增唯一值,和样例输出效果完全匹配
内容的提问来源于stack exchange,提问作者emanuele_f
相关产品推荐
相关产品推荐

