如何编写带容差的函数查找连续函数/数组的第一、第二峰值
峰值查找函数实现方案
核心实现思路
- 首先提取所有局部极大值作为候选峰值
- 支持双维度容差过滤:
- 数值容差:与更高峰值的差值小于该值的峰判定为噪声
- 间距容差:与更高峰值的索引距离小于该值的峰判定为噪声
- 过滤后按峰值从高到低排序,取前两位即为所需的第一、第二峰值
完整代码实现
import numpy as np # 可选依赖scipy,如果不想引入可以用下方注释的原生实现替换候选点提取逻辑 from scipy.signal import argrelextrema def peak(arr, tolerance): """ 查找数组的第一、第二峰值 参数: arr: 输入一维numpy数组 tolerance: 容差参数,可传入两种格式: 1. 单个数值:仅作为数值容差,间距容差默认取数组长度的1/10 2. 二元组(数值容差, 间距容差):分别设置数值和索引间距的过滤阈值 返回: 列表,每个元素为(峰值索引, 峰值数值),按峰值从高到低排序 """ # 解析容差参数 if isinstance(tolerance, (int, float)): val_tol = tolerance dist_tol = len(arr) // 10 else: val_tol, dist_tol = tolerance # 提取所有局部极大值点(比左右邻居都大的点) candidate_idx = argrelextrema(arr, np.greater)[0] # ---------------- 无scipy依赖的候选点提取替换逻辑 ---------------- # candidate_idx = [] # for i in range(1, len(arr)-1): # if arr[i] > arr[i-1] and arr[i] > arr[i+1]: # candidate_idx.append(i) # candidate_idx = np.array(candidate_idx) # ------------------------------------------------------------- # 补充边界点判定:数组首尾如果是峰值的情况 if len(arr) >=2 and arr[0] > arr[1]: candidate_idx = np.insert(candidate_idx, 0, 0) if len(arr) >=2 and arr[-1] > arr[-2]: candidate_idx = np.append(candidate_idx, len(arr)-1) # 按峰值从高到低排序候选点 candidates = sorted([(idx, arr[idx]) for idx in candidate_idx], key=lambda x: -x[1]) if not candidates: return [] # 过滤噪声峰 kept = [candidates[0]] for cur in candidates[1:]: cur_idx, cur_val = cur is_noise = False for k in kept: k_idx, k_val = k # 数值差小于容差 或者 距离小于容差,判定为噪声 if (k_val - cur_val < val_tol) or (abs(cur_idx - k_idx) < dist_tol): is_noise = True break if not is_noise: kept.append(cur) # 已经找到前两个峰值可提前退出,提高性能 if len(kept) >=2: break return kept
测试验证
测试用例1:无噪声的数组ar
ar = np.array([1,2,3,4,4.5,4.1,4.05,4,3,2,1,2,3,3.5,3.2,2,1,0]) print(peak(ar, tolerance=0.5))
输出结果:
[(4, 4.5), (13, 3.5)]
测试用例2:带小幅噪声的数组ar2
ar2 = np.array([1,2,3,4,4.5,4.1,4.2,4,3,2,1,2,3,3.5,3.2,2,1,0]) print(peak(ar2, tolerance=0.5))
输出结果和ar完全一致,索引6处的4.2因为和最高峰值4.5的差值仅0.3,小于设置的0.5数值容差,会被判定为噪声过滤:
[(4, 4.5), (13, 3.5)]
峰值效果示意图

二维数组扩展思路
如果需要支持二维数组,可以将上述逻辑适配:
- 使用
scipy.signal.argrelmax提取二维局部极大值点 - 容差逻辑增加二维坐标的欧氏距离作为间距容差判定标准
- 过滤后取前两位峰值即可
内容的提问来源于stack exchange,提问作者user7867665
相关产品推荐
相关产品推荐

