如何在Pandas下采样时保留仅完整存在于原数据的时间段?
解决DatetimeIndex Series下采样时保留完整时间段的问题
核心思路
不管是标准日历日还是自定义时间段(如燃气日),核心逻辑都是:先确定每个数据点所属的分组,再验证该分组是否包含了时间段内的所有原始数据点,最后只保留符合条件的分组结果。
分步实现(以燃气日为例)
假设我们需要按当日6点至次日6点的燃气日进行下采样,原始数据是小时级的Series:
1. 构造测试数据
import pandas as pd # 构造包含2个完整燃气日+额外小时的小时级数据 i = pd.date_range('2022-03-04 22:00', '2022-03-07 09:00', freq='H') hourly = pd.Series(range(len(i)), i)
2. 定义自定义分组函数
这个函数将每个时间点映射到所属燃气日的左边界(当日6点,若当前时间早于6点则取前一天的6点):
def gasday(dt): if dt.hour >= 6: # 时间在6点及之后,归属当日6点开始的燃气日 return dt.replace(hour=6, minute=0, second=0, microsecond=0) else: # 时间早于6点,归属前一天6点开始的燃气日 return (dt - pd.Timedelta(days=1)).replace(hour=6, minute=0, second=0, microsecond=0)
3. 标记分组并统计每组数据量
给原始数据添加分组标签,然后统计每个分组包含的原始小时数:
# 给每个数据点标记所属燃气日 hourly['gasday_group'] = hourly.index.map(gasday) # 统计每个燃气日的原始数据点数量 group_counts = hourly.groupby('gasday_group').size()
4. 筛选完整分组
燃气日是24小时跨度,所以完整的分组应该包含24个小时数据点:
# 筛选出包含24个数据点的完整燃气日 complete_groups = group_counts[group_counts == 24].index
5. 下采样并过滤完整分组
先按燃气日聚合数据,再只保留完整的分组结果:
# 按燃气日聚合(这里用sum,可根据需求替换为mean、max等) resampled_gasday = hourly.groupby(gasday).sum() # 过滤出完整的燃气日数据 complete_resampled = resampled_gasday.loc[complete_groups]
执行后,complete_resampled将只包含2022-03-05 06:00:00和2022-03-06 06:00:00这两个完整燃气日的聚合结果。
通用适配方案
对于任意自定义分组规则,只需修改分组函数,然后按以下步骤执行:
- 步骤1:编写分组函数,将每个时间点映射到分组的唯一标识(通常是时间段左边界);
- 步骤2:统计每个分组的原始数据点数量;
- 步骤3:计算完整分组应有的数据点数量(公式:
分组时间段跨度 / 原始数据频率,比如小时级数据+24小时跨度=24个点); - 步骤4:用完整分组的标识过滤聚合后的结果。
时区处理适配
如果你的DatetimeIndex带时区,只需在分组函数中保留时区信息即可,示例:
# 带时区的测试数据 i_tz = pd.date_range('2022-03-04 22:00', '2022-03-07 09:00', freq='H', tz='Europe/Paris') hourly_tz = pd.Series(range(len(i_tz)), i_tz) # 带时区的燃气日分组函数 def gasday_tz(dt): if dt.hour >= 6: res = dt.replace(hour=6, minute=0, second=0, microsecond=0) else: res = (dt - pd.Timedelta(days=1)).replace(hour=6, minute=0, second=0, microsecond=0) return res # 保留时区信息
后续步骤和之前一致,无需额外修改。
内容的提问来源于stack exchange,提问作者ElRudi
相关产品推荐
相关产品推荐

