使用scipy find_peaks时如何设置峰间信号阈值筛选单峰?
解决scipy find_peaks中宽峰被拆分为多峰的问题
核心方案:使用prominence参数
scipy的find_peaks没有直接的“峰间必须低于阈值才检测下一个峰”的参数,但**prominence(峰突出度)**刚好匹配你的需求:它要求峰的顶点到其左右最近谷底的最小高度差必须达到设定值。如果宽峰内的小凸起周围没有低于阈值的谷底,它们的突出度就不达标,不会被判定为独立峰,同时不会影响真正的窄小峰值。
调整后的代码示例
# 设定突出度阈值,可根据数据特征调整比例 prominence_threshold = 0.1 * bg_G2.values scp_peaks, properties = find_peaks( plotdf['G2'].values, height=1.1*bg_G2.values, width=9, prominence=prominence_threshold )
- 原理:
prominence会自动过滤无足够“落差”的小凸起——宽峰内的三个子峰之间未降至阈值以下,突出度远小于主峰,会被合并为一个峰;而真正独立的小峰因和相邻峰间有足够谷底落差,会被保留。
备选方案:自定义后处理过滤
如果prominence的效果不够精准,可先检测所有候选峰,再手动过滤峰间信号未降至阈值的相邻峰:
import numpy as np # 先检测所有候选峰 scp_peaks, properties = find_peaks( plotdf['G2'].values, height=1.1*bg_G2.values, width=9 ) # 设定峰间必须低于的阈值,比如背景值 valley_threshold = bg_G2.values filtered_peaks = [] if len(scp_peaks) > 0: filtered_peaks.append(scp_peaks[0]) for i in range(1, len(scp_peaks)): # 取相邻两峰之间的信号最小值 valley_min = np.min(plotdf['G2'].values[scp_peaks[i-1]:scp_peaks[i]]) # 谷底低于阈值则保留当前峰,否则合并到前一个峰 if valley_min < valley_threshold: filtered_peaks.append(scp_peaks[i]) # 最终保留的有效峰 scp_peaks = np.array(filtered_peaks)
- 优势:完全自定义峰间阈值,还可灵活调整合并逻辑(比如保留相邻峰中高度更高的那个)。
为什么不推荐调大width?
width参数基于峰的半高宽筛选,调大后会过滤掉所有窄峰;而prominence或后处理只针对“无足够谷底落差”的假峰,不会影响真正的独立窄峰,更贴合你的需求。
内容的提问来源于stack exchange,提问作者Daan64
相关产品推荐
相关产品推荐

