基于MA(5)-MA(20)符号翻转提取Pandas局部高低值(非循环)
高效实现Pandas中基于MA差值符号的局部极值提取(无循环)
刚好之前处理过类似的需求,完全可以用Pandas的矢量化分组操作搞定,绝对不用低效的for循环!我给你拆解成具体步骤,附代码示例:
1. 先构造示例数据
首先我们把你给出的示例数据转换成Pandas DataFrame:
import pandas as pd import numpy as np data = { 'High': [100, 101, 102, 99], 'Low': [90, 91, 92, 88], 'MA(5)-MA(20)': [-1, -2, 1, 2] } df = pd.DataFrame(data)
2. 生成连续符号的分组ID
核心思路是:每次MA差值的符号发生翻转时,就创建一个新的分组。我们用np.sign()获取符号,再通过cumsum()生成分组ID:
# 计算MA差值的符号(正=1,负=-1,这里假设没有0的情况,有0的话可以额外处理) df['sign'] = np.sign(df['MA(5)-MA(20)']) # 生成分组ID:当当前行符号和上一行不同时,分组ID+1 df['group_id'] = (df['sign'] != df['sign'].shift()).cumsum()
3. 计算阶段内的局部极值(两种场景)
根据你需求里的“局部值”,我分两种常见场景实现:
场景1:每个符号阶段内的全局极值(即该阶段内High的最大/Low的最小)
这种场景下,我们用transform直接计算每个分组的极值,再根据符号选择对应值,全程矢量化,效率最高:
# 计算每个分组的High最大值和Low最小值 df['group_high_max'] = df.groupby('group_id')['High'].transform('max') df['group_low_min'] = df.groupby('group_id')['Low'].transform('min') # 根据符号选择对应的极值:正号取High最大值,负号取Low最小值 df['local_extreme'] = np.where(df['sign'] > 0, df['group_high_max'], df['group_low_min']) # 清理中间列(可选) df = df.drop(['group_high_max', 'group_low_min'], axis=1)
执行后得到的结果:
High Low MA(5)-MA(20) sign group_id local_extreme 0 100 90 -1 -1 1 90.0 1 101 91 -2 -1 1 90.0 2 102 92 1 1 2 102.0 3 99 88 2 1 2 102.0
场景2:真正的局部峰值/谷值(即当前值大于前后值的高点,或小于前后值的低点)
如果你的“局部值”是指这种相邻对比的极值,我们可以在分组内用np.where做矢量化判断:
def get_local_peaks_valleys(group): sign = group['sign'].iloc[0] if sign > 0: # 正号阶段:标记High中大于前后值的局部峰值 group['local_extreme'] = np.where( (group['High'] > group['High'].shift()) & (group['High'] > group['High'].shift(-1)), group['High'], np.nan ) else: # 负号阶段:标记Low中小于前后值的局部谷值 group['local_extreme'] = np.where( (group['Low'] < group['Low'].shift()) & (group['Low'] < group['Low'].shift(-1)), group['Low'], np.nan ) return group # 应用分组计算 df = df.groupby('group_id').apply(get_local_peaks_valleys)
执行后得到的结果:
High Low MA(5)-MA(20) sign group_id local_extreme 0 100 90 -1 -1 1 NaN 1 101 91 -2 -1 1 NaN 2 102 92 1 1 2 102.0 3 99 88 2 1 2 NaN
(解释:负号阶段的Low是递增的,没有谷值;正号阶段的102是唯一的局部高点)
为什么这个方案高效?
全程用Pandas/Numpy的底层矢量化操作,没有Python层面的for循环——所有循环逻辑都在C语言实现的底层执行,处理大规模数据时效率会比for循环高几个数量级。
内容的提问来源于stack exchange,提问作者novice
相关产品推荐
相关产品推荐

