Python,查找数组的所有局部最大值,调整测量中的缺陷

时间:2017-10-17 21:25:06

标签: python arrays numpy scipy

我试图获得一维数组中的最大点,在那里它产生几条曲线。为此,我使用scipy.signal.argrelextremanp.greater。在这里给出数组y

的位置
argrelextrema(y, np.greater)

问题是,由于y的数据收集方式,这个一维数据存在不准确性。因此,有很多"误报"在曲线的底部,技术上底部的最大值是因为一个值大于周围值。

作为参考,这里是y,x,它只是每个y值的索引,用于演示我正在使用的数组。底部的不准确性是不可见的。忽略轴,使用我在代码中的内容。

y

此外,这里是我使用找到的最大值计算一个值的结果,因为这是不需要的,因为预期的结果应该是平滑的下降曲线。对于每个最大值,以递增的顺序对一个点进行图表。从实际图表中可以看出,这显然是错误的。

results

那么,避免这种情况的最佳解决方案是什么?我找不到能够以足够好的方式近似图形的东西,能够使用它。我看起来很平滑,但我发现的方法,如savgol_filter中的scipy.signal,是我无法理解的。

当前的解决方案是忽略低于5的y值,这大约略高于曲线的底部,但根本不是理想的解决方案。

更新

find_peaks_cwt发现scipy.signal也适用于此。它有点复杂,因为我完全不知道它的大部分工作原理,即使在读了一下之后也是如此。但是,我设法使用:find_peaks_cwt(y, [3], noise_perc=2)制作了稍微好一点的图表但是,下面看到的结果只是我将噪音从10降到2的结果,而不知道这会对结果产生怎样的影响。

enter image description here

编辑: 这是我正在处理的1D阵列:https://pastebin.com/GZrBBRce 对不起表示不好,但每行都是列表中的下一个值。它有点大。

编辑:最小工作示例,y来自pastebin,有点大,包含在最小工作示例中:

energy = []
for i in find_peaks_cwt(y, [3],noise_perc=2):
    energy.append(y[i])
plt.plot([i for i in range(len(energy))], energy)
plt.show()

这是通过一些猜测得出的,结果可以在这个问题的最后一张图片中看到。

更新2:进一步的进展,我使用numpy.polyfit以近似15度的方式平滑y函数。它非常准确。由于这是顺利的,我可以恢复到第一个函数argrelextrema(y, np.greater),它给了我一个相当不错的答案,并且不包括误报,如上图所示。 (当我的图表只有20个以上时,我得到了30-40个最大值。)

在标记解决之前,我会让它站立一点,以防有人想要更好的解决方案并使用numpy.polyfit逼近图表。然而,这解决了我的用例问题。

2 个答案:

答案 0 :(得分:1)

我会使用:scipy.signal.find_peaks_cwt()

从其文档:

  

尝试在1-D阵列中找到峰值。

     

一般方法是通过将宽度与每个宽度的小波(宽度)进行卷积来平滑矢量。可以接受以足够的长度尺度出现并具有足够高的SNR的相对最大值。

更新(包含实际数据)

import numpy as np
import scipy as sp

import matplotlib.pyplot as plt

import scipy.signal

y_arr = np.loadtxt('/home/raid1/metere/Downloads/1d_array.txt')
print('array size: ', y_arr.shape)

arr_size = len(y_arr)
expected_num = 30

expected_width = arr_size // expected_num // 2
print('expected width of peaks: ', expected_width)

peaks = sp.signal.find_peaks_cwt(y_arr, np.linspace(2, expected_width, 10))

print('num peaks: ', len(peaks))
print('peaks: ', peaks)

plt.plot(y_arr)
for peak in peaks:
    plt.axvline(peak)
plt.show()

这可能会进一步调整,例如提高准确度。

答案 1 :(得分:1)

如果它不是太大的数组,我现在能想到的最简单的方法就是在数组的值上进行一次循环。 Somethong喜欢:

如果ar [i-1]< ar [i]& ar [i]> AR [I + 1]

将一个[i]添加到maxArray。

你只需要检查ar [i]!= ar [i + 1]。如果它相等,你应该取第一个或那个值或eqauls值。

编辑:

SECURE_SSL_REDIRECT = False

你的数据有点吵。所以我得到了一些“附加”值。

编辑2:

所以你可以添加一个过滤器,我相信你可以找到一个更好的方法去做,但对我来说最简单的是:

count=1
leng=len(list1)-1
while count < leng:
    count=count+1
    if ((list1[count-1] < list1[count]) & (list1[count] > list1[count+1])):
        print list1[count]


21.55854026
4.205178829
16.6062412
16.60490417
13.14358751
11.76675489
10.71131948
10.34922208
9.703966466
4.440605216
9.557176225
9.163999162
4.530660664
9.067259599
4.482917884
8.628552441
4.443787789
8.340760319
7.9779415
4.411471328
4.415029139
7.840661767
7.858075487
4.413923668
7.555398794
7.533918443
4.445146914
7.58446368
7.56834833
7.264249919
7.34901701
7.349173404
7.315796894
7.235120197
4.577840109
7.24188544
7.243943576
7.205527364
4.480817125
4.483523464
4.526264151
6.90592723
6.903067763
6.905932124
4.513352307
4.464000858
6.848673936
6.831810008
6.819620162
4.485243384
6.606738091