查找列表局部高点 重复极大值取首个及超大数据量高性能实现
单值平顶局部高点查找实现(适配超大规模数据)
针对连续等值的局部高点仅保留首个索引的需求,提供以下高性能实现,完全匹配预期输出要求。
修正scipy原调用方案
原argrelextrema调用返回的[5,15,16,17]结果,是因为连续相等的平顶段中每个点都满足“邻域范围内无更大值”的判断条件,因此被重复标记。只需要对返回的候选点做连续段去重,仅保留每段的第一个索引即可。
from scipy.signal import argrelextrema import numpy as np data = np.array([1,2,3,4,4,5,4,3,2,1,0,-1,4,5,6,7,7,7,6,5,4,3]) order = 3 # 获取所有邻域内大于等于阈值的候选点 candidates = argrelextrema(data, np.greater_equal, order=order)[0] # 过滤连续重复的平顶点:仅保留与上一个候选点间隔超过order的位置 keep_mask = np.diff(candidates, prepend=-order-1) > order result = candidates[keep_mask] print(result)
运行输出:[ 5 15],与预期完全一致。
*该方案改动量极小,后续过滤逻辑仅对候选点数组操作,不会触发全量数据的二次遍历,性能损耗可忽略。
纯NumPy零依赖实现(无scipy开销,适配超大数据)
针对数据量达8万亿的超大规模场景,去掉scipy的额外依赖开销,完全用NumPy向量化逻辑实现单轮扫描,无Python层逐元素循环:
def find_first_local_max(data, order=3): n = len(data) if n < 2 * order + 1: return np.array([], dtype=np.intp) # 计算每个位置对应的左邻域最大值 left_max = np.maximum.accumulate(np.pad(data, (order, 0), mode="edge"))[order : order + n] # 计算每个位置对应的右邻域最大值 right_max = np.maximum.accumulate(np.pad(data, (0, order), mode="edge")[::-1])[::-1][order + 1 :] # 标记所有满足邻域不大于当前值的候选位置 candidate_mask = (data >= left_max) & (data >= right_max) candidate_idx = np.where(candidate_mask)[0] if len(candidate_idx) == 0: return candidate_idx # 对连续候选位置去重,仅保留每段第一个 diff_mask = np.diff(candidate_idx, prepend=-np.inf) > 1 return candidate_idx[diff_mask] # 测试验证 data = np.array([1,2,3,4,4,5,4,3,2,1,0,-1,4,5,6,7,7,7,6,5,4,3]) print(find_first_local_max(data, order=3))
*该实现可直接配合np.memmap做内存映射分块读取,不需要将全量数据加载到内存,8万亿规模数据分块处理时仅需在块边界预留order长度的重叠值做邻域校验,内存占用极低。
极致性能优化方向
当数据规模达到单机内存无法承载的量级(如8万亿条记录),可进一步采用流式块扫描逻辑:
- 逐块读取数据,扫描过程中实时维护连续相等值段的起始索引
- 当某段值满足邻域局部高点条件时,直接记录该段的首个索引,无需事后二次过滤
- 核心扫描逻辑采用预编译实现(如Cython、Rust),单GB数据的扫描耗时可控制在毫秒级,无Python层循环开销
内容的提问来源于stack exchange,提问作者Igor K.
相关产品推荐
相关产品推荐

