Pandas DataFrame查找满足分组约束的连续数值下降序列方法
解决方案
全程用Pandas向量化操作实现,无显式for循环,完全符合你的需求规则:
前置数据处理
import pandas as pd # 加载数据(提前复制你提供的DataFrame到剪贴板) df = pd.read_clipboard(sep='\s\s+', engine='python') # 清除空值行 df = df.dropna(subset=['Group1', 'Group2', 'Value']).reset_index(drop=True)
核心实现代码
# 1. 生成分组ID:Group1或Group2变化时触发序列中断 df['group_id'] = ( (df['Group1'] != df['Group1'].shift()) | (df['Group2'] != df['Group2'].shift()) ).cumsum() # 2. 标记下降步长和中断点 df['value_diff'] = df['Value'].diff() df['is_drop'] = df['value_diff'] < 0 # 有效下降步长标记 df['is_break'] = ( (df['group_id'] != df['group_id'].shift()) | (df['value_diff'] > 0) # Value上升时也触发中断 ) # 3. 生成连续下降段ID df['drop_segment_id'] = df['is_break'].cumsum() # 4. 按下降段聚合统计,筛选符合条件的序列 N = 4 DELTA = 0.1 result = df.groupby('drop_segment_id').agg( 起始时间=('Time', 'first'), 结束时间=('Time', 'last'), 起始Value=('Value', 'first'), 结束Value=('Value', 'last'), 下降步长=('is_drop', 'sum'), 总降幅=('Value', lambda x: x.iloc[0] - x.iloc[-1]) ).reset_index(drop=True) # 筛选符合条件的结果 result = result[(result['下降步长'] >= N) & (result['总降幅'] >= DELTA)].reset_index(drop=True)
输出结果示例(N=4、DELTA=0.1)
| 起始时间 | 结束时间 | 起始Value | 结束Value | 下降步长 | 总降幅 |
|---|---|---|---|---|---|
| 05 | 08 | 0.91 | 0.74 | 4 | 0.17 |
| 19 | 22 | 1.04 | 0.89 | 4 | 0.15 |
和你给出的示例完全一致。
规则适配说明
- 完全符合中断规则:Group1/Group2变化、Value上升都会触发新的下降段,原有序列中断
- 完全符合持平规则:Value持平的时候
is_drop为False,不计入下降步长,同时不会触发is_break,不会中断序列 - 筛选条件直接在聚合后用布尔索引实现,可灵活调整N和DELTA的取值
内容的提问来源于stack exchange,提问作者tim
相关产品推荐
相关产品推荐

