You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:41:38