Pandas中基于分组极值筛选行:峰值保留逻辑在大数据集下存在残留重复峰值的问题求助
Pandas中基于分组极值筛选行:峰值保留逻辑在大数据集下存在残留重复峰值的问题求助
你好!看起来你正在处理价格/图表数据的峰值筛选需求——要把连续标记为HH(高点)的行里只保留High值最大的那一行,连续标记为LL(低点)的行里只保留Low值最小的那一行。你的循环迭代方法在小数据集上能得到预期结果,但放到大数据集里偶尔会出现残留的重复峰值,我来帮你分析问题并给出更稳健的解决方案。
你的现有情况回顾
先再明确下你的数据和预期:
你构造的示例DataFrame如下:
import pandas as pd mydict = [ {'HH': True, 'LL': False, 'High': 10, 'Low': 1}, {'HH': False, 'LL': True, 'High': 100, 'Low': 20}, {'HH': True, 'LL': False, 'High': 32, 'Low': 1}, {'HH': True, 'LL': False, 'High': 30, 'Low': 1}, {'HH': True, 'LL': False, 'High': 31, 'Low': 1}, {'HH': False, 'LL': True, 'High': 100, 'Low': 40}, {'HH': False, 'LL': True, 'High': 100, 'Low': 45}, {'HH': False, 'LL': True, 'High': 100, 'Low': 42}, {'HH': False, 'LL': True, 'High': 100, 'Low': 44}, {'HH': True, 'LL': False, 'High': 50, 'Low': 1}, ] df = pd.DataFrame(mydict)
你期望的结果是每个连续的HH组只保留最高High的行,每个连续的LL组只保留最低Low的行,得到的结果如下:
HH LL High Low 0 True False 10 1 1 False True 100 20 2 True False 32 1 3 False False 30 1 4 False False 31 1 5 False True 100 40 6 False False 100 45 7 False False 100 42 8 False False 100 44 9 True False 50 1
现有方法的问题分析
你的循环迭代逻辑是通过逐次标记那些比前后同类型峰值更低(HH)或更高(LL)的行,然后将它们的HH/LL设为False,直到没有需要处理的行为止。这种方法在小数据集上能工作,但在大数据集容易出问题的原因有两个:
- 迭代逻辑的局限性:依赖相邻行的比较,当连续峰值组内有多个非极值行时,可能需要多次循环才能清除,但如果某次循环后临时的
df3为空,循环会提前终止,导致残留的非极值峰值; - 效率低下:大数据集下循环次数多,不仅性能差,还容易出现边界条件处理不当的情况。
更稳健的解决方案:分组找极值
核心思路是先对连续的HH/LL区块进行分组,然后在每个分组内直接定位极值对应的行,只保留该行的HH/LL标记,一次处理所有区块,避免迭代遗漏。
具体代码实现
# 复制原DataFrame,避免修改原始数据 df_clean = df.copy() # ---------------------- 处理HH峰值 ---------------------- # 生成连续HH的分组标识:当HH状态变化时,分组编号+1 hh_groups = (df_clean['HH'] != df_clean['HH'].shift()).cumsum() # 仅筛选出HH为True的有效分组 hh_valid_groups = hh_groups[df_clean['HH']] # 对每个HH分组,找到High值最大的行索引 hh_peak_indices = df_clean.groupby(hh_valid_groups)['High'].idxmax() # 先把所有HH设为False,再只保留峰值行的HH为True df_clean['HH'] = False df_clean.loc[hh_peak_indices, 'HH'] = True # ---------------------- 处理LL谷值 ---------------------- # 生成连续LL的分组标识:当LL状态变化时,分组编号+1 ll_groups = (df_clean['LL'] != df_clean['LL'].shift()).cumsum() # 仅筛选出LL为True的有效分组 ll_valid_groups = ll_groups[df_clean['LL']] # 对每个LL分组,找到Low值最小的行索引 ll_peak_indices = df_clean.groupby(ll_valid_groups)['Low'].idxmin() # 先把所有LL设为False,再只保留谷值行的LL为True df_clean['LL'] = False df_clean.loc[ll_peak_indices, 'LL'] = True # 查看处理后的结果 print(df_clean)
代码逻辑说明
- 分组标识生成:通过比较当前行和上一行的
HH/LL状态,生成连续区块的分组编号,确保每个连续的HH/LL区块被归为同一组; - 极值定位:使用
groupby结合idxmax/idxmin直接找到每个分组内的极值行索引,这一步是一次性完成所有分组的处理; - 标记重置与保留:先将所有
HH/LL设为False,再把极值行的标记恢复为True,确保每组只保留一个有效峰值。
方案优势
- 无遗漏:一次性处理所有连续峰值区块,不会出现迭代方法的残留问题;
- 高效:避免循环迭代,大数据集下性能提升明显;
- 逻辑清晰:直接针对分组找极值,符合你的业务需求逻辑,便于维护和扩展。
备注:内容来源于stack exchange,提问作者Viktor
相关产品推荐
相关产品推荐

