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)[source]#
根据峰属性在信号内找出峰。
此函数采用 1-D 数组并通过简单的相邻值比较找出所有局部最大值。也可以通过指定峰的属性条件,有选择地找出这些峰中的子集。
- 参数:
- x序列
具有峰值的信号。
- height数字或 ndarray 或序列,可选
峰的必需高度。可以使用一个数字,
None
,与x 匹配的数组或前者的 2 元组。第一个元素始终被解释为最小值,第二个元素(如果提供)被解释为最大必需高度。- 阈值数字或 ndarray 或序列,可选
峰的必需阈值,与相邻样本的垂直距离。可以使用一个数字,
None
,与x 匹配的数组或前者的 2 元组。第一个元素始终被解释为最小值,第二个元素(如果提供)被解释为最大必需阈值。- 距离数字,可选
相邻峰之间的样本当中(>= 1)必需的最小水平距离。较小的峰将先被移除,直至所有剩余峰满足条件。
- 显著性数字或 ndarray 或序列,可选
峰的必需显著性。可以使用一个数字,
None
,与x 匹配的数组或前者的 2 元组。第一个元素始终被解释为最小值,第二个元素(如果提供)被解释为最大必需显著性。- 宽度数字或 ndarray 或序列,可选
样本当中的峰的必需宽度。可以使用一个数字,
None
,与x 匹配的数组或前者的 2 元组。第一个元素始终被解释为最小值,第二个元素(如果提供)被解释为最大必需宽度。- wlen整数,可选
用于计算峰的显著性,因此仅在给出参数prominence 或width 之一时使用。有关其效果的完整说明,请参见
peak_prominences
中的参数 wlen。- 相对高度浮点数,可选
用于计算峰的宽度,因此仅在给出width 时使用。有关其效果的完整说明,请参见
peak_widths
中的参数 rel_height。- 平稳期大小数字或 ndarray 或序列,可选
样品中峰值平顶部分所需大小。数字、
None
、与x相匹配的阵列或前者的双元素序列。**第一个元素总是解释为最小值,如果提供则第二个元素为所需最大平台大小**。在版本 1.2.0 中添加。
- 返回值:
- peaksndarray
x 中满足所有给定条件的峰值索引。
- propertiesdict
字典,包含在评估指定条件过程中作为中间结果计算出的已返回值的峰值属性
- ‘peak_heights’
如果给定height,则为x中每个峰值的高度。
- ‘left_thresholds’,‘right_thresholds’
如果给定threshold,这些键包含峰值与其相邻样本的垂直距离。
- ‘prominences’,‘right_bases’,‘left_bases’
如果给定prominence,则可访问这些键。请参阅
peak_prominences
,了解其内容说明。
- ‘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
直接计算峰值的突出度。
峰宽
直接计算峰宽。
注释
在本函数的上下文中,峰值或局部最大值被定义为任何两个直接邻居都有较小振幅的样本。对于平坦峰值(多个样本具有相等的振幅宽度),则返回中间样本的索引(如果样本数量为偶数,则向下舍入)。对于噪声信号,峰值位置可能会偏离,因为噪声可能会改变局部最大值的位置。在这些情况下,请考虑在搜索峰值之前平滑信号,或使用其他峰值查找和拟合方法(例如
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
)。让我们找出振幅高于 0 的 x 中的所有峰值(局部极大值)。>>> 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()