Python / SciPy的峰值查找算法
我可以通过查找一阶导数或其他东西的零交叉来自己编写一些东西,但它似乎是一个通用的函数,可以包含在标准库中。 谁知道一个?
我的特定应用是2D阵列,但通常它将用于在FFT等中查找峰值。
具体来说,在这些类型的问题中,有多个强峰,然后是许多较小的峰#34; 这只是应该被忽略的噪音引起的。 这只是例子; 不是我的实际数据:
一维峰值:
二维峰值:
峰值寻找算法将找到这些峰值的位置(不仅仅是它们的值),理想情况下会找到真正的样本间峰值,而不仅仅是具有最大值的索引,可能使用二次插值等。
通常,您只关心几个强峰,因此它们要么被选中,要么是因为它们高于某个阈值,要么是因为它们是按幅度排序的有序列表的前n个峰。
正如我所说,我知道如何自己写这样的东西。 我只是想知道是否有一个已知的功能或包可以很好地运作。
更新:
我翻译了一个MATLAB脚本,它适用于1-D案例,但可能更好。
更新更新:
sixtenbe为1-D案例创造了更好的版本。
8个解决方案
43 votes
我正在研究类似的问题,并且我发现一些最好的参考资料来自化学(来自质谱数据中的峰值)。 有关峰值查找算法的详细审查,请阅读此内容。 这是我发现的最佳峰值发现技术最清晰的评论之一。 (小波最适合在噪声数据中找到此类峰值。)。
看起来您的峰值已明确定义,并且不会隐藏在噪音中。 在这种情况下,我建议使用平滑的savtizky-golay衍生物来找到峰值(如果你只是区分上面的数据,那么就会有一堆误报。)。 这是一种非常有效的技术,并且很容易实现(你需要一个矩阵类w /基本操作)。 如果您只是找到第一个S-G衍生物的过零点,我认为您会感到高兴。
Paul answered 2019-07-03T21:04:15Z
19 votes
scipy中有一个名为scipy.signal.find_peaks_cwt的功能,听起来很适合您的需要,但我没有经验,所以我不推荐..
[http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.find_peaks_cwt.html]
Hanan Shteingart answered 2019-07-03T21:04:46Z
17 votes
顾名思义,函数width对此很有用。 但是,理解其参数width,width,width以及最重要的width以获得良好的峰提取是重要的。
根据我的测试和文档,突出的概念是"有用的概念" 保持良好的峰值,并丢弃嘈杂的山峰。
什么是(地形)突出? 这是从山顶下降到任何更高地形所需的最小高度",如下所示:
这个想法是:
突出程度越高,越重要" 高峰是。
测试:
我故意使用(嘈杂的)变频正弦波,因为它显示出许多困难。 我们可以看到width参数在这里不是很有用,因为如果你将最小值设置得太高,那么它就无法跟踪高频部分中非常接近的峰值。 如果将width设置得太低,则信号的左侧会有许多不需要的峰值。 与distance相同的问题.threshold仅与直接邻居进行比较,这在此处没有用。 prominence是提供最佳解决方案的人。 请注意,您可以组合使用其中的许多参数!
码:
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import find_peaks
x = np.sin(2*np.pi*(2**np.linspace(2,10,1000))*np.arange(1000)/48000) + np.random.normal(0, 1, 1000) * 0.15
peaks, _ = find_peaks(x, distance=20)
peaks2, _ = find_peaks(x, prominence=1) # BEST!
peaks3, _ = find_peaks(x, width=20)
peaks4, _ = find_peaks(x, threshold=0.4) # Required vertical distance to its direct neighbouring samples, pretty useless
plt.subplot(2, 2, 1)
plt.plot(peaks, x[peaks], "xr"); plt.plot(x); plt.legend(['distance'])
plt.subplot(2, 2, 2)
plt.plot(peaks2, x[peaks2], "ob"); plt.plot(x); plt.legend(['prominence'])
plt.subplot(2, 2, 3)
plt.plot(peaks3, x[peaks3], "vg"); plt.plot(x); plt.legend(['width'])
plt.subplot(2, 2, 4)
plt.plot(peaks4, x[peaks4], "xk"); plt.plot(x); plt.legend(['threshold'])
plt.show()
Basj answered 2019-07-03T21:05:45Z
14 votes
对于那些不确定在Python中使用哪种峰值查找算法的人,可以快速浏览一下备选方案:[https://github.com/MonsieurV/py-findpeaks]
想要自己相当于MatLab findpeaks功能,我发现Marcos Duarte的detect_peaks功能很好。
非常好用:
import numpy as np
from vector import vector, plot_peaks
from libs import detect_peaks
print('Detect peaks with minimum height and distance filters.')
indexes = detect_peaks.detect_peaks(vector, mph=7, mpd=2)
print('Peaks are: %s' % (indexes))
哪个会给你:
Yoan Tournade answered 2019-07-03T21:06:25Z
6 votes
已经对可靠地检测频谱中的峰值进行了相当多的研究,例如80年代对音乐/音频信号的正弦建模的所有工作。 寻找"正弦模型" 在文献中。
如果你的信号和示例一样干净,那就简单地给我一些振幅高于N个邻居的东西。 应该运作得相当好。 如果您有嘈杂的信号,一种简单但有效的方法是查看您的峰值,跟踪它们:然后检测谱线而不是谱峰。 IOW,您在信号的滑动窗口上计算FFT,以获得一组时间光谱(也称为频谱图)。 然后,您可以观察光谱峰值的演变(即在连续的窗口中)。
David Cournapeau answered 2019-07-03T21:06:59Z
5 votes
我不认为您所寻找的是由SciPy提供的。 在这种情况下,我会自己编写代码。
scipy.interpolate的样条插值和平滑非常好,可能非常有助于拟合峰值,然后找到它们的最大位置。
Eric O Lebigot answered 2019-07-03T21:03:44Z
1 votes
有标准的统计函数和方法可以找到数据的异常值,这可能是你在第一种情况下所需要的。 使用衍生物可以解决你的问题。 但是,我不确定一种解决连续函数和采样数据的方法。
nullpointer answered 2019-07-03T21:07:25Z
0 votes
首先,"峰值"的定义 如果没有进一步的规范,则含糊不清 例如,对于以下系列,您会将5-4-5称为一个或两个峰值吗?
1-2-1-2-1-1-5-4-5-1-1-5-1
在这种情况下,您需要至少两个阈值:1)高阈值,高于此阈值可以将极值注册为峰值; 2)低阈值,以便由低于它的小值分隔的极值将变为两个峰值。
峰值检测是极值理论文献中一个经过深入研究的主题,也称为“极端值的去模式”。 其典型应用包括基于环境变量的连续读数识别危险事件,例如 分析风速以检测风暴事件。
Ian Liu answered 2019-07-03T21:08:11Z