我想有一个函数,可以检测局部极大值/极小值在数组中的位置(即使存在一组局部极大值/极小值)。示例:
给定数组
test03 = np.array([2,2,10,4,4,4,5,6,7,2,6,5,5,7,7,1,1])
我希望输出如下:
^{pr2}$从这个例子中可以看出,不仅检测到奇异值,而且还检测到局部极大值/极小值集。在
{我只知道一些极小值集的答案,但忽略了它们中的许多极值点。在
在提出这个问题之前,我自己编写了一个函数,它与我前面描述的完全相同(这个函数位于这个问题的末尾:local_min(a)
)。通过我做的测试,它工作正常)。在
问题:然而,我也确信这不是使用Python的最佳方法。是否有我可以使用的内置函数、API、库等?还有其他功能建议吗?一行指令?全矢量解?在
def local_min(a):
candidate_min=0
for i in range(len(a)):
# Controlling the first left element
if i==0 and len(a)>=1:
# If the first element is a singular local minima
if a[0]<a[1]:
print("local minima, i = 0")
# If the element is a candidate to be part of a set of local minima
elif a[0]==a[1]:
candidate_min=1
# Controlling the last right element
if i == (len(a)-1) and len(a)>=1:
if candidate_min > 0:
if a[len(a)-1]==a[len(a)-2]:
print("set of " + str(candidate_min+1)+ " local minima => array["+str(i-candidate_min)+"]:array["+str(i)+"]")
if a[len(a)-1]<a[len(a)-2]:
print("local minima, i = " + str(len(a)-1))
# Controlling the other values in the middle of the array
if i>0 and i<len(a)-1 and len(a)>2:
# If a singular local minima
if (a[i]<a[i-1] and a[i]<a[i+1]):
print("local minima, i = " + str(i))
# print(str(a[i-1])+" > " + str(a[i]) + " < "+str(a[i+1])) #debug
# If it was found a set of candidate local minima
if candidate_min >0:
# The candidate set IS a set of local minima
if a[i] < a[i+1]:
print("set of " + str(candidate_min+1)+ " local minima => array["+str(i-candidate_min)+"]:array["+str(i)+"]")
candidate_min = 0
# The candidate set IS NOT a set of local minima
elif a[i] > a[i+1]:
candidate_min = 0
# The set of local minima is growing
elif a[i] == a[i+1]:
candidate_min = candidate_min + 1
# It never should arrive in the last else
else:
print("Something strange happen")
return -1
# If there is a set of candidate local minima (first value found)
if (a[i]<a[i-1] and a[i]==a[i+1]):
candidate_min = candidate_min + 1
Note: I tried to enrich the code with some comments to let understand what I do. I know that the function that I propose is not clean and just prints the results that can be stored and returned at the end. It was written to give an example. The algorithm I propose should be O(n).
更新:
有人建议导入from scipy.signal import argrelextrema
并使用如下函数:
def local_min_scipy(a):
minima = argrelextrema(a, np.less_equal)[0]
return minima
def local_max_scipy(a):
minima = argrelextrema(a, np.greater_equal)[0]
return minima
拥有这样的东西才是我真正想要的。然而,当局部极小/极大值集合有两个以上的值时,它就不能正常工作。例如:
test03 = np.array([2,2,10,4,4,4,5,6,7,2,6,5,5,7,7,1,1])
print(local_max_scipy(test03))
输出为:
[ 0 2 4 8 10 13 14 16]
当然在test03[4]
我有一个最小值,而不是最大值。我该如何纠正这种行为?(我不知道这是不是另一个问题,或者这是问这个问题的正确地点。)
有多种方法可以解决这个问题。这里列出了一种方法。 您可以创建一个自定义函数,并在查找mimima时使用maximums来处理边缘情况。在
如果这对你有用,请告诉我。这个想法很简单,你需要在列表中迭代一次,并在看到它们时继续存储最小值。通过在每一端填充最大值来处理边。(或填充最后一个结尾,并使用最大值进行初始比较)
全矢量解决方案:
^{pr2}$result
:编辑
不幸的是,这也检测到了最大值,因为它们至少有3个项目大,因为它们被视为平坦的局部极小值。这样的话,裸体补丁会很难看。在
为了解决这个问题,我提出了另外两种解决方案,用numpy,然后用numba。在
使用
np.diff
的数字:与numba加速度兼容的直接解决方案:
下面是一个基于将数组重新划分为iterable窗口的答案:
测试一下:
^{pr2}$输出:
不是最有效的算法,但至少它很短。我很确定它是
O(n^2)
,因为有大约1/2*(n^2 + n)
个窗口需要迭代。这只是部分矢量化,所以可能有一种方法可以改进它。在编辑
为了澄清,输出是包含局部最小值运行的切片的索引。事实上,他们超过了运行的结束是故意的(有人只是试图在编辑中“修复”这个问题)。可以使用输出迭代输入数组中最小值的片段,如下所示:
输出:
相关问题 更多 >
编程相关推荐