find_peaks#
- scipy.signal.find_peaks(x, height=None, threshold=None, distance=None, prominence=None, width=None, wlen=None, rel_height=0.5, plateau_size=None)[源代码]#
根据峰值属性查找信号内的峰值。
此函数接受一个一维数组,并通过简单比较相邻值来查找所有局部最大值。 可选地,可以通过指定峰值属性的条件来选择这些峰值的子集。
- 参数:
- x序列
带有峰值的信号。
- height数字或 ndarray 或序列,可选
峰值的所需高度。可以是数字、
None
、与 x 匹配的数组或前者的双元素序列。第一个元素始终被解释为最小高度,第二个元素(如果提供)被解释为最大所需高度。- threshold数字或 ndarray 或序列,可选
峰值的所需阈值,即与其相邻样本的垂直距离。可以是数字、
None
、与 x 匹配的数组或前者的双元素序列。第一个元素始终被解释为最小阈值,第二个元素(如果提供)被解释为最大所需阈值。- distance数字,可选
相邻峰值之间所需的最小水平距离(>= 1,以样本为单位)。首先删除较小的峰值,直到所有剩余的峰值都满足条件。
- prominence数字或 ndarray 或序列,可选
峰值的所需突出度。可以是数字、
None
、与 x 匹配的数组或前者的双元素序列。第一个元素始终被解释为最小突出度,第二个元素(如果提供)被解释为最大所需突出度。- width数字或 ndarray 或序列,可选
峰值的所需宽度,以样本为单位。可以是数字、
None
、与 x 匹配的数组或前者的双元素序列。第一个元素始终被解释为最小宽度,第二个元素(如果提供)被解释为最大所需宽度。- wlen整数,可选
用于计算峰值的突出度,因此只有在给出了 prominence 或 width 参数之一时才会使用。 有关其影响的完整描述,请参见
peak_prominences
中的 wlen 参数。- rel_height浮点数,可选
用于计算峰值的宽度,因此只有在给出了 width 时才会使用。 有关其影响的完整描述,请参见
peak_widths
中的 rel_height 参数。- plateau_size数字或 ndarray 或序列,可选
峰值的平坦顶部的所需大小,以样本为单位。可以是数字、
None
、与 x 匹配的数组或前者的双元素序列。第一个元素始终被解释为最小平顶大小,第二个元素(如果提供)被解释为最大所需平顶大小。1.2.0 版本新增。
- 返回:
- peaksndarray
满足所有给定条件的 x 中峰值的索引。
- properties字典
一个字典,其中包含返回的峰值的属性,这些属性是在评估指定条件期间作为中间结果计算的。
- ‘peak_heights’
如果给出了 height,则为 x 中每个峰值的高度。
- ‘left_thresholds’, ‘right_thresholds’
如果给出了 threshold,则这些键包含峰值与其相邻样本的垂直距离。
- ‘prominences’, ‘right_bases’, ‘left_bases’
如果给出了 prominence,则可以访问这些键。 有关其内容的描述,请参见
peak_prominences
。
- ‘widths’, ‘width_heights’, ‘left_ips’, ‘right_ips’
如果给出了 width,则可以访问这些键。 有关其内容的描述,请参见
peak_widths
。
- ‘plateau_sizes’, ‘left_edges’, ‘right_edges’
如果给出了 plateau_size,则可以访问这些键,其中包含峰值边缘的索引(边缘仍然是平顶的一部分)和计算出的平顶大小。
1.2.0 版本新增。
要计算并返回属性而不排除峰值,请为相应的参数提供开区间
(None, None)
(不包括 distance)。
- 警告:
- PeakPropertyWarning
如果峰值的属性具有意外的值,则引发(请参见
peak_prominences
和peak_widths
)。
警告
此函数可能会返回包含 NaN 的数据的意外结果。为避免这种情况,应删除或替换 NaN。
参见
find_peaks_cwt
使用小波变换查找峰值。
peak_prominences
直接计算峰值的突出度。
peak_widths
直接计算峰值的宽度。
备注
在此函数的上下文中,峰值或局部最大值定义为任何两个直接邻居的幅度较小的样本。 对于平坦的峰值(多个幅度相等的样本宽度),返回中间样本的索引(如果样本数是偶数,则向下舍入)。对于噪声信号,峰值位置可能会偏差,因为噪声可能会改变局部最大值的位置。 在这些情况下,请考虑在搜索峰值之前对信号进行平滑处理,或使用其他峰值查找和拟合方法(例如
find_peaks_cwt
)。关于指定条件的一些其他说明
几乎所有条件(不包括 distance)都可以作为半开或闭区间给出,例如,
1
或(1, None)
定义半开区间 \([1, \infty]\),而(None, 1)
定义区间 \([-\infty, 1]\)。也可以指定开区间(None, None)
,这将返回匹配的属性,而不排除峰值。边界始终包含在用于选择有效峰值的区间中。
对于多个条件,可以使用与 x 形状匹配的数组来指定区间边界,从而实现基于样本位置的动态约束。
条件按照以下顺序评估:plateau_size、height、threshold、distance、prominence、width。在大多数情况下,这个顺序是最快的,因为会先应用较快的操作,以减少后续需要评估的峰值数量。
虽然 peaks 中的索引保证至少相隔 distance 个样本,但平坦峰值的边缘可能比允许的 distance 更接近。
如果 x 很大或有许多局部最大值,则可以使用 wlen 来减少评估 prominence 或 width 条件所花费的时间(请参阅
peak_prominences
)。
在 1.1.0 版本中新增。
示例
为了演示此函数的使用,我们使用 SciPy 提供的信号 x (请参阅
scipy.datasets.electrocardiogram
)。让我们找到 x 中所有幅度高于 0 的峰值(局部最大值)。>>> import numpy as np >>> import matplotlib.pyplot as plt >>> from scipy.datasets import electrocardiogram >>> from scipy.signal import find_peaks >>> x = electrocardiogram()[2000:4000] >>> peaks, _ = find_peaks(x, height=0) >>> plt.plot(x) >>> plt.plot(peaks, x[peaks], "x") >>> plt.plot(np.zeros_like(x), "--", color="gray") >>> plt.show()
我们可以使用
height=(None, 0)
选择低于 0 的峰值,或者使用大小与 x 匹配的数组来反映信号不同部分的动态条件。>>> border = np.sin(np.linspace(0, 3 * np.pi, x.size)) >>> peaks, _ = find_peaks(x, height=(-border, border)) >>> plt.plot(x) >>> plt.plot(-border, "--", color="gray") >>> plt.plot(border, ":", color="gray") >>> plt.plot(peaks, x[peaks], "x") >>> plt.show()
对于周期性信号,可以使用 distance 参数给出另一个有用的条件。在这种情况下,我们可以通过要求至少间隔 150 个样本的距离,轻松地选择心电图(ECG)中 QRS 波群的位置。
>>> peaks, _ = find_peaks(x, distance=150) >>> np.diff(peaks) array([186, 180, 177, 171, 177, 169, 167, 164, 158, 162, 172]) >>> plt.plot(x) >>> plt.plot(peaks, x[peaks], "x") >>> plt.show()
特别是对于噪声信号,峰值可以很容易地根据其突出程度进行分组(请参阅
peak_prominences
)。例如,我们可以通过将允许的突出程度限制为 0.6 来选择除上述 QRS 波群之外的所有峰值。>>> peaks, properties = find_peaks(x, prominence=(None, 0.6)) >>> properties["prominences"].max() 0.5049999999999999 >>> plt.plot(x) >>> plt.plot(peaks, x[peaks], "x") >>> plt.show()
最后,让我们检查心电图的不同部分,其中包含不同形状的搏动波形。为了仅选择非典型心跳,我们结合了两个条件:最小突出程度为 1 且宽度至少为 20 个样本。
>>> x = electrocardiogram()[17000:18000] >>> peaks, properties = find_peaks(x, prominence=1, width=20) >>> properties["prominences"], properties["widths"] (array([1.495, 2.3 ]), array([36.93773946, 39.32723577])) >>> plt.plot(x) >>> plt.plot(peaks, x[peaks], "x") >>> plt.vlines(x=peaks, ymin=x[peaks] - properties["prominences"], ... ymax = x[peaks], color = "C1") >>> plt.hlines(y=properties["width_heights"], xmin=properties["left_ips"], ... xmax=properties["right_ips"], color = "C1") >>> plt.show()