按连续日期范围与多标识字段分组Pandas DataFrame
按连续日期范围与多标识字段分组Pandas DataFrame
我来帮你搞定这个分组需求,咱们可以分步骤实现你要的「同标识且连续日期间隔不超6小时」的分组效果,最终得到每个连续块的日期范围。
首先先回顾下你的原始数据结构,先把数据初始化的代码放出来方便后续操作:
import pandas as pd data = { 'date': ['2023-01-01 00:00:00', '2023-01-01 06:00:00', '2023-01-01 12:00:00', '2023-01-02 00:00:00', '2023-01-02 06:00:00', '2023-01-03 00:00:00'], 'x': [1, 1, 1, 2, 2, 1], 'y': ['A', 'A', 'A', 'B', 'B', 'A'], 'z': [10, 10, 10, 20, 20, 10] } df = pd.DataFrame(data) df['date'] = pd.to_datetime(df['date'])
接下来咱们一步步处理:
步骤1:计算分组内的日期间隔
首先按x、y、z这三个标识字段分组,计算每个分组内连续行的日期差值:
# 计算每个x/y/z分组内,当前行与上一行的日期差 df['date_diff'] = df.groupby(['x', 'y', 'z'])['date'].diff()
步骤2:标记新分组的起始行
如果日期差超过6小时,说明这一行是一个新连续块的开始;对于每个分组的第一行(date_diff为NaN),我们也标记为新组起始:
# 判断是否需要开启新分组:日期差>6小时 或者是分组的第一行 df['new_group'] = (df['date_diff'] > pd.Timedelta('6H')).fillna(True)
步骤3:生成连续块的唯一ID
在每个x/y/z分组内,对new_group做累积求和,这样就能给每个连续的日期块分配一个唯一的block_id:
# 每个x/y/z分组内,按new_group的累积和生成块ID df['block_id'] = df.groupby(['x', 'y', 'z'])['new_group'].cumsum()
步骤4:聚合得到日期范围
现在我们可以用x、y、z、block_id这四个字段一起分组,提取每个组的最小和最大日期,就是我们要的连续日期范围了:
# 分组聚合得到每个连续块的日期范围 result = df.groupby(['x', 'y', 'z', 'block_id']).agg( start_date=('date', 'min'), end_date=('date', 'max') ).reset_index().drop(columns='block_id') print(result)
最终输出结果
运行上面的代码后,你会得到如下结果,完全符合你要的效果:
x y z start_date end_date 0 1 A 10 2023-01-01 00:00:00 2023-01-01 12:00:00 1 1 A 10 2023-01-03 00:00:00 2023-01-03 00:00:00 2 2 B 20 2023-01-02 00:00:00 2023-01-02 06:00:00
简单解释下这个结果:
- 第一行:
x=1,y=A,z=10的前三条记录,日期间隔都是6小时,属于同一个连续块,日期范围是从1号0点到1号12点 - 第二行:
x=1,y=A,z=10的最后一条记录,和上一个块的日期差超过6小时(1号12点到3号0点差36小时),所以单独成一个块 - 第三行:
x=2,y=B,z=20的两条记录间隔6小时,属于同一个块,日期范围是2号0点到2号6点
这样就完美实现了你要的「同标识+连续日期间隔不超6小时」的分组,同时得到每个组的日期范围啦!
备注:内容来源于stack exchange,提问作者Samuel Reyes
相关产品推荐
相关产品推荐

