Python 在numpy数组中查找局部最大值

Python 在numpy数组中查找局部最大值,python,arrays,numpy,distribution,Python,Arrays,Numpy,Distribution,我正在寻找一些高斯平滑数据中的峰值。我已经研究了一些可用的峰值检测方法,但它们需要一个输入范围来搜索,我希望这比那更自动化。这些方法也适用于非平滑数据。由于我的数据已经平滑,我需要一种更简单的方法来检索峰值。我的原始平滑数据如下图所示 从本质上讲,是否有一种pythonic方法可以从平滑数据数组中检索最大值,例如 a = [1,2,3,4,5,4,3,2,1,2,3,2,1,2,3,4,5,6,5,4,3,2,1] 将返回: r = [5,3,6] 如果可以排除阵列边缘的最大

我正在寻找一些高斯平滑数据中的峰值。我已经研究了一些可用的峰值检测方法,但它们需要一个输入范围来搜索,我希望这比那更自动化。这些方法也适用于非平滑数据。由于我的数据已经平滑,我需要一种更简单的方法来检索峰值。我的原始平滑数据如下图所示

从本质上讲,是否有一种pythonic方法可以从平滑数据数组中检索最大值,例如

    a = [1,2,3,4,5,4,3,2,1,2,3,2,1,2,3,4,5,6,5,4,3,2,1]
将返回:

    r = [5,3,6]

如果可以排除阵列边缘的最大值,则始终可以通过检查以下内容来检查一个元素是否大于其每个相邻元素:

import numpy as np
array = np.array([1,2,3,4,5,4,3,2,1,2,3,2,1,2,3,4,5,6,5,4,3,2,1])
# Check that it is bigger than either of it's neighbors exluding edges:
max = (array[1:-1] > array[:-2]) & (array[1:-1] > array[2:])
# Print these values
print(array[1:-1][max])
# Locations of the maxima
print(np.arange(1, array.size-1)[max])

如果原始数据有噪声,则最好使用统计方法,因为并非所有峰值都是显著的。对于a阵列,一种可能的解决方案是使用双微分:

peaks = a[1:-1][np.diff(np.diff(a)) < 0]
# peaks = array([5, 3, 6])

存在完成此任务的bulit in函数:

import numpy as np
from scipy.signal import argrelextrema
    
a = np.array([1,2,3,4,5,4,3,2,1,2,3,2,1,2,3,4,5,6,5,4,3,2,1])

# determine the indices of the local maxima
max_ind = argrelextrema(a, np.greater)

# get the actual values using these indices
r = a[max_ind]  # array([5, 3, 6])
这将为您提供r所需的输出

从SciPy版本1.1开始,您还可以使用。下面是两个取自文档本身的示例

使用height参数,可以选择高于某个阈值的所有最大值(在本例中为所有非负最大值);如果必须处理噪声基线,这可能非常有用;如果要找到极小值,只需将输入值乘以-1:

另一个非常有用的参数是距离,它定义了两个峰值之间的最小距离:

peaks, _ = find_peaks(x, distance=150)
# difference between peaks is >= 150
print(np.diff(peaks))
# prints [186 180 177 171 177 169 167 164 158 162 172]

plt.plot(x)
plt.plot(peaks, x[peaks], "x")
plt.show()

如果您的输入表示有噪声的分布,可以使用NumPy卷积函数进行尝试。

图形中的数据与数组a之间的差异非常明显。对于图形中的数据。我倾向于简单地从数据中减去平滑的版本,然后使用像绝对偏差中位数这样的东西来计算统计显著性峰值的阈值。类似的问题这能回答你的问题吗?我按照这篇文章中的建议做了一个通用的高斯滤波器来去除噪声。这些数据来自光谱仪,所以我试图找到带宽上的峰值响应。我认为高斯滤波器会给出一个很好的近似值,它不需要精确的峰值…你是在上面的图中寻找红线的峰值还是绿线的峰值?我在寻找红线的峰值。我应该说得更清楚些。每一个峰值都是一个带宽,所以我想为这个频带获得最大的价值。我认为这里的代码应该能解决你的问题:@NathanThomas:很高兴它能帮上忙!顺便说一句:如果你对极小值感兴趣,你可以用np.less代替np.greater。
peaks, _ = find_peaks(x, distance=150)
# difference between peaks is >= 150
print(np.diff(peaks))
# prints [186 180 177 171 177 169 167 164 158 162 172]

plt.plot(x)
plt.plot(peaks, x[peaks], "x")
plt.show()
>> import numpy as np
>> from scipy.signal import argrelextrema
>> a = np.array([1,2,3,4,5,4,3,2,1,2,3,2,1,2,3,4,5,6,5,4,3,2,1])
>> argrelextrema(a, np.greater)
array([ 4, 10, 17]),)
>> a[argrelextrema(a, np.greater)]
array([5, 3, 6])