Pandas按小时聚合数据时保留实际起止时间的方法咨询
按小时分组聚合时保留实际起止时间的Pandas解决方案
问题描述
我有一个包含timestamp(时间戳)和数值的DataFrame,示例代码如下:
import pandas as pd import numpy as np time_list = ['2020-04-22 13:29:00+00:00','2020-04-22 13:31:00+00:00','2020-04-22 13:32:00+00:00','2020-04-22 13:33:00+00:00','2020-04-22 13:34:00+00:00','2020-04-22 13:35:00+00:00','2020-04-22 13:36:00+00:00','2020-04-22 13:54:00+00:00','2020-04-22 13:55:00+00:00','2020-04-22 13:56:00+00:00','2020-04-22 13:57:00+00:00','2020-04-22 13:58:00+00:00','2020-04-22 13:59:00+00:00','2020-04-22 14:00:00+00:00','2020-04-22 14:01:00+00:00','2020-04-22 14:02:00+00:00','2020-04-22 14:03:00+00:00','2020-04-22 14:04:00+00:00','2020-04-22 14:05:00+00:00','2020-04-22 14:06:00+00:00','2020-04-22 14:49:00+00:00','2020-04-22 14:50:00+00:00','2020-04-22 14:51:00+00:00','2020-04-22 14:52:00+00:00','2020-04-22 14:53:00+00:00','2020-04-22 14:54:00+00:00','2020-04-22 14:55:00+00:00','2020-04-22 14:56:00+00:00','2020-04-22 14:57:00+00:00','2020-04-22 14:58:00+00:00','2020-04-22 14:59:00+00:00','2020-04-22 15:00:00+00:00','2020-04-22 15:01:00+00:00','2020-04-22 15:02:00+00:00','2020-04-22 15:24:00+00:00','2020-04-22 15:25:00+00:00','2020-04-22 15:26:00+00:00','2020-04-22 15:27:00+00:00','2020-04-22 15:28:00+00:00','2020-04-22 15:29:00+00:00','2020-04-22 15:36:00+00:00'] df = pd.DataFrame(time_list) df.columns = ['timestamp'] df['rand']=np.random.randint(0, 100, df.shape[0]) df.timestamp = pd.to_datetime(df.timestamp) df.set_index('timestamp', inplace=True)
使用resample按小时聚合求和:
agg_dict = {'rand': 'sum'} dfr = df.resample('1H').agg(agg_dict)
但这种方式会丢失每个时段的实际起止时间:比如第一个时段实际从13:29开始,聚合结果却标记为13:00(易被误认为覆盖13:00-14:00全时段);最后一个时段实际到15:36结束,结果仅显示15:00,容易让人误以为数据覆盖到15:59。需要一种能保留每个小时分组实际起止时间的方法,且不想自行编写复杂代码。
解决方案
方法1:扩展resample的聚合逻辑
Pandas没有直接的内置函数实现该需求,但可以通过自定义聚合函数,在resample的基础上同时计算每个时段的实际起止时间,代码量极小:
def agg_with_time(group): return pd.Series({ 'rand_sum': group['rand'].sum(), 'actual_start': group.index.min(), 'actual_end': group.index.max() }) # 按小时分组并应用自定义聚合 result = df.resample('1H').apply(agg_with_time).dropna()
说明:
resample('1H')依然负责按自然小时分组,保证分组逻辑正确- 自定义函数
agg_with_time对每个分组计算三个值:数值总和、分组内最早时间(实际开始)、分组内最晚时间(实际结束) dropna()用于过滤没有数据的小时时段
输出示例:
| timestamp | rand_sum | actual_start | actual_end |
|---|---|---|---|
| 2020-04-22 13:00:00 | 642 | 2020-04-22 13:29:00+00:00 | 2020-04-22 13:59:00+00:00 |
| 2020-04-22 14:00:00 | 1025 | 2020-04-22 14:00:00+00:00 | 2020-04-22 14:59:00+00:00 |
| 2020-04-22 15:00:00 | 517 | 2020-04-22 15:00:00+00:00 | 2020-04-22 15:36:00+00:00 |
方法2:使用groupby配合小时提取
如果更习惯常规groupby语法,也可以通过提取日期+小时的分组键来实现:
# 生成日期+小时的分组键 df['hour_group'] = df.index.floor('H') # 分组聚合 result = df.groupby('hour_group').agg( rand_sum=('rand', 'sum'), actual_start=('timestamp', 'min'), actual_end=('timestamp', 'max') ).reset_index().rename(columns={'hour_group': 'hour_start'})
这个方法同样能清晰展示每个时段的实际数据范围,结果结构与方法1一致。
内容的提问来源于stack exchange,提问作者Vincent
相关产品推荐
相关产品推荐

