如何在Pandas中获取含重复值的连续值组的DateTimeIndex起止索引
为DateTime索引的DataFrame标记连续值组的起止位置
我需要给带DateTimeIndex的DataFrame中,连续出现n≥2次的重复值组标记起始和结束位置,排除单个值的情况,且重复出现的组也要单独标记。网上找到的基于数值索引的方案没法适配我的场景,求助可行的实现方式。
示例数据
import pandas as pd index = pd.date_range( start=pd.Timestamp("2023-03-20 12:00:00+0000", tz="UTC"), end=pd.Timestamp("2023-03-20 15:00:00+0000", tz="UTC"), freq="15Min", ) data = { "values_including_constant_groups": [ 2.0, 1.0, 1.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 2.0, 3.0, 3.0, 1.0, ], } df = pd.DataFrame( index=index, data=data, ) print(df)
示例数据输出
values_including_constant_groups 2023-03-20 12:00:00+00:00 2.0 2023-03-20 12:15:00+00:00 1.0 2023-03-20 12:30:00+00:00 1.0 2023-03-20 12:45:00+00:00 3.0 2023-03-20 13:00:00+00:00 3.0 2023-03-20 13:15:00+00:00 3.0 2023-03-20 13:30:00+00:00 4.0 2023-03-20 13:45:00+00:00 4.0 2023-03-20 14:00:00+00:00 4.0 2023-03-20 14:15:00+00:00 2.0 2023-03-20 14:30:00+00:00 3.0 2023-03-20 14:45:00+00:00 3.0 2023-03-20 15:00:00+00:00 1.0
期望输出(格式可灵活调整)
values_including_constant_groups group_start group_end 2023-03-20 12:00:00+00:00 2.0 NaN NaN 2023-03-20 12:15:00+00:00 1.0 True False 2023-03-20 12:30:00+00:00 1.0 False True 2023-03-20 12:45:00+00:00 3.0 True False 2023-03-20 13:00:00+00:00 3.0 False False 2023-03-20 13:15:00+00:00 3.0 False True 2023-03-20 13:30:00+00:00 4.0 True False 2023-03-20 13:45:00+00:00 4.0 False False 2023-03-20 14:00:00+00:00 4.0 False True 2023-03-20 14:15:00+00:00 2.0 NaN NaN 2023-03-20 14:30:00+00:00 3.0 True False 2023-03-20 14:45:00+00:00 3.0 False True 2023-03-20 15:00:00+00:00 1.0 NaN NaN
解决方案
可以利用pandas的分组和移位功能实现,完全适配DateTimeIndex,无需依赖数值索引:
# 1. 生成连续值的分组ID:当前值与前一个不同时,分组ID递增 df['group_id'] = (df['values_including_constant_groups'] != df['values_including_constant_groups'].shift()).cumsum() # 2. 计算每个分组的长度 group_lengths = df.groupby('group_id')['values_including_constant_groups'].transform('count') # 3. 标记组的起始位置:仅保留长度≥2的组的第一个元素 df['group_start'] = (df['group_id'] != df['group_id'].shift()) & (group_lengths >= 2) # 4. 标记组的结束位置:仅保留长度≥2的组的最后一个元素 df['group_end'] = (df['group_id'] != df['group_id'].shift(-1)) & (group_lengths >= 2) # 5. 将单个值的组的标记转为NaN df.loc[group_lengths < 2, ['group_start', 'group_end']] = pd.NA # 可选:删除临时的group_id列 df = df.drop(columns='group_id') print(df)
代码说明
- 分组标记:通过比较当前值与前一个值的差异生成分组ID,完全基于列值变化,和索引类型无关。
- 过滤短分组:计算每个分组的长度,只对长度≥2的组标记起止。
- 起止判断:
group_start:当前行是分组第一行且分组长度≥2时为True,否则为NaN。group_end:当前行是分组最后一行且分组长度≥2时为True,否则为NaN。
运行上述代码后,输出结果将与期望输出一致。
内容的提问来源于stack exchange,提问作者Cord Kaldemeyer
相关产品推荐
相关产品推荐

