当给定x和y值作为numpy数组时,找到所有的局部极大值和极小值

15

我有两个数组xy

x = np.array([6, 3, 5, 2, 1, 4, 9, 7, 8])
y = np.array([2, 1, 3, 5, 3, 9, 8, 10, 7])

我正在按照以下方式查找局部极小值和极大值的索引:

sortId = np.argsort(x)
x = x[sortId]
y = y[sortId]
minm = np.array([])
maxm = np.array([])
while i < y.size-1:
   while(y[i+1] >= y[i]):
      i = i + 1

   maxm = np.insert(maxm, 0, i)
   i++
   while(y[i+1] <= y[i]):
      i = i + 1

   minm = np.insert(minm, 0, i)
   i++

这段代码有什么问题? 答案应该是minima = [2, 5, 7]maxima = [1, 3, 6]的索引。


1
你在做什么与 sortId=np.argsort(x); x=x[sortId] - fferri
@mescalinum:我正在对x值进行排序,相应的索引将存储在sortId中,以便我可以按照那个顺序排列y值。 - prtkp
@Cleb:我想要峰值和谷底。 - prtkp
@rth:实际上,在我的数据集中,点非常相邻,所以您链接中提到的方法也会在极值周围给出一些额外的点。 - prtkp
@Cleb:完全正确,这就是我说最大值的索引为1、3、6,对应的点为(2,5)、(4,9)和(7,10)的原因。同样地,最小值的索引为2、5、7,对应的点为(3,1)、(6,2)和(8,7)。 - prtkp
显示剩余4条评论
3个回答

27

你根本不需要这个while循环。下面的代码将会给你想要的输出结果;它能够找到所有局部最小值和局部最大值,分别存储在minmmaxm中。请注意:当你将其应用于大型数据集时,一定要先平滑信号,否则你将得到大量的极值。

import numpy as np
from scipy.signal import argrelextrema
import matplotlib.pyplot as plt

x = np.array([6, 3, 5, 2, 1, 4, 9, 7, 8])
y = np.array([2, 1, 3 ,5 ,3 ,9 ,8, 10, 7])

# sort the data in x and rearrange y accordingly
sortId = np.argsort(x)
x = x[sortId]
y = y[sortId]

# this way the x-axis corresponds to the index of x
plt.plot(x-1, y)
plt.show()
maxm = argrelextrema(y, np.greater)  # (array([1, 3, 6]),)
minm = argrelextrema(y, np.less)  # (array([2, 5, 7]),)

这比上面的while循环效率要高得多。

图像如下所示;我将x值移动,以使其对应于minmmaxm中返回的索引:

enter image description here

自SciPy版本1.1起,您还可以使用find_peaks

from scipy.signal import find_peaks

peaks, _ = find_peaks(y)

# this way the x-axis corresponds to the index of x
plt.plot(x-1, y)
plt.plot(peaks, y[peaks], "x")
plt.show()

这将产生

enter image description here

好的一点是,现在你还可以轻松地设置最小峰值高度(例如8):

peaks, _ = find_peaks(y, height=8)

# this way the x-axis corresponds to the index of x
plt.plot(x-1, y)
plt.plot(peaks, y[peaks], "x")
plt.show() 

输入图像描述

请注意,由于第一个峰的高度低于8,现在已经被去除。

此外,您还可以设置峰之间的最小距离(例如5):

peaks, _ = find_peaks(y, distance=5)

# this way the x-axis corresponds to the index of x
plt.plot(x-1, y)
plt.plot(peaks, y[peaks], "x")
plt.show()

图片描述

现在中间的峰被排除了,因为其到其他两个峰的距离小于5。


嗯...这个运行得很好...我下面提供的解决方案也给出了相同的答案...但问题是由于数据集太大,它会产生很多极值,就像你在我的第二个问题中所说的,并建议在查找极值之前平滑信号...顺便说一句,谢谢。 - prtkp
1
抱歉以评论的形式添加此内容,但不确定如何在搜索时表达问题。您所说的“平滑信号”是什么意思?您会使用什么来实现?谢谢。 - datahappy
1
@datahappy:你可以搜索“smooth signal scipy”和“running average”,这应该会让你走上正确的轨道。平滑处理可以消除很多局部极值,有助于找到实际的峰值。 - Cleb
6
嗨,使用 peaks,_ = find_peaks(-y) 可以获得最小值。 - Echan

1
x=np.array([6,3,5,2,1,4,9,7,8])
y=np.array([2,1,3,5,7,9,8,10,7])

sort_idx = np.argsort(x)
y=y[sort_idx]
x=x[sort_idx]
minm=np.array([],dtype=int)
maxm=np.array([],dtype=int)
length = y.size
i=0

while i < length-1:
    if i < length - 1:
        while i < length-1 and y[i+1] >= y[i]:
            i+=1

        if i != 0 and i < length-1:
            maxm = np.append(maxm,i)

        i+=1

    if i < length - 1:
        while i < length-1 and y[i+1] <= y[i]:
            i+=1

        if i < length-1:
            minm = np.append(minm,i)
        i+=1


print minm
print maxm

minmmaxm 分别包含最小值和最大值的索引。


0

这个会很好用。

Python使用+=代替++

在while循环中使用i之前,你必须先赋值 - 在这种情况下是0 - 这样初始化它以避免错误。

import numpy as np

x=np.array([6,3,5,2,1,4,9,7,8])
y=np.array([2,1,3,5,3,9,8,10,7])


sortId=np.argsort(x)
x=x[sortId]
y=y[sortId]
minm = np.array([])
maxm = np.array([])
i = 0
while i < y.size-1:
   while(y[i+1] >= y[i]):
      i+=1

   maxm=np.insert(maxm,0,i)
   i+=1
   while(y[i+1] <= y[i]):
      i+=1

   minm=np.insert(minm,0,i)
   i+=1

print minm, maxm

导致 [ 7. 5. 2.] [ 6. 3. 1.] 的结果。 - Geeocode
你尝试运行它了吗?忽略原始技术问题,例如while循环和重新分配内存,有人可以运行我的解决方案以检查它是否会出现“索引超出范围”的错误吗? - Geeocode
当我执行时,出现了错误。当您执行第三个 while 循环时,您没有检查索引边界。拿另一个例子然后再尝试执行。 - prtkp
脚本当然已经到达了第三个while循环,如果没有到达,Python解析器会给我一个错误信息,但它没有。请发送您运行的完整代码以进行检查。你这边出了问题。 - Geeocode

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接