检测数字列表中的峰值并记录它们的位置
Detect peaks in list of numbers and record their positions
我正在尝试创建一些代码 returns 数值数组 "peaks"(或局部最大值)的位置和值。
例如,列表 arr = [0, 1, 2, 5, 1, 0]
在位置 3
处有一个峰值,值为 5
(因为 arr[3]
等于 5
)。
数组的第一个和最后一个元素不会被视为峰值(在数学函数的上下文中,您不知道之前和之后是什么,因此,您不知道它是否是一个峰值与否)。
def pick_peaks(arr):
print(arr)
posPeaks = {
"pos": [],
"peaks": [],
}
startFound = False
n = 0
while startFound == False:
if arr[n] == arr[n+1]:
n += 1
else:
startFound = True
endFound = False
m = len(arr) - 1
while endFound == False:
if arr[m] == arr[m-1]:
m -= 1
else:
endFound = True
for i in range(n+1, m):
if arr[i] == arr[i-1]:
None
elif arr[i] >= arr[i-1] and arr[i] >= arr[i+1]:
posPeaks["pos"].append(i)
posPeaks["peaks"].append(arr[i])
return posPeaks
我的问题是高原。 [1, 2, 2, 2, 1]
有峰值而 [1, 2, 2, 2, 3]
没有。当一个平台为峰时,记录平台的第一个位置。
感谢任何帮助。
如果您可以对数据进行预处理以删除重复数字并仅保留 1 个唯一数字,则您也可以对高原使用相同的算法。因此,您可以将示例 [1, 2, 2, 2, 1]
转换为 [1, 2, 1]
并应用相同的算法。
编辑:
代码:
from itertools import groupby
def process_data(data):
return [list(val for num in group) for val, group in groupby(data)]
def peaks(arr):
#print(arr)
posPeaks = {
"pos": [],
"peaks": [],
}
startFound = False
n = 0
while startFound == False:
if arr[n][0] == arr[n+1][0]:
n += 1
else:
startFound = True
endFound = False
m = len(arr) - 1
while endFound == False:
if arr[m][0] == arr[m-1][0]:
m -= 1
else:
endFound = True
for i in range(n+1, m):
if arr[i][0] == arr[i-1][0]:
None
elif arr[i][0] >= arr[i-1][0] and arr[i][0] >= arr[i+1][0]:
pos = sum([len(arr[idx]) for idx in range(i)])
posPeaks["pos"].append(pos) #.append(i)
posPeaks["peaks"].append(arr[i][0])
return posPeaks
print(peaks(process_data([0, 1, 2, 5, 1, 0])))
print(peaks(process_data([1, 2, 2, 2, 1])))
print(peaks(process_data([1, 2, 2, 2, 3])))
输出:
{'pos': [3], 'peaks': [5]}
{'pos': [1], 'peaks': [2]}
{'pos': [], 'peaks': []}
我建议您使用 groupby 对连续的相等值进行分组,然后为每个组存储第一个位置,例如 [1, 2, 2, 2, 1]
它在元组列表 [(1, 0), (2, 1), (1, 4)]
之后创建以下列表, 放在一起:
from itertools import groupby
def peaks(data):
start = 0
sequence = []
for key, group in groupby(data):
sequence.append((key, start))
start += sum(1 for _ in group)
for (b, bi), (m, mi), (a, ai) in zip(sequence, sequence[1:], sequence[2:]):
if b < m and a < m:
yield m, mi
print(list(peaks([0, 1, 2, 5, 1, 0])))
print(list(peaks([1, 2, 2, 2, 1])))
print(list(peaks([1, 2, 2, 2, 3])))
输出
[(5, 3)]
[(2, 1)]
[]
这是一个相当简单的生成器函数。只需循环并维护必要的状态:i
("growth" 的最后一个索引),up
(如果最后一个值更改为 "growth",则为真)
def peaks(ar):
i, up = 0, False
for j in range(1, len(ar)):
prev, val = ar[j-1], ar[j]
if up and val < prev:
yield prev, i
up = False
if val > prev:
i, up = j, True
>>> list(peaks([0,1,2,5,1,0]))
[(5, 3)]
>>> list(peaks([0,1,2,5,1,2,0]))
[(5, 3), (2, 5)]
>>> list(peaks([0,1,2,5,1,2,0,3]))
[(5, 3), (2, 5)]
>>> list(peaks([1,2,2,2,1]))
[(2, 1)]
>>> list(peaks([1,2,2,2,3]))
[]
一个较短的脚本可以是:
data_array = [1, 2, 5, 4, 6, 9]
# Delete the first and the last element of the data array.
reduced_array = [ data_array[i] for i in range(1, len(data_array)-1) ]
# Find the maximum value of the modified array
peak_value = max(reduced_array)
# Print out the maximum value and its index in the data array.
print 'The peak value is: ' + str(peak_value)
print 'And its position is: ' + str(data_array.index(peak_value))
输出:
The peak value is: 6
And its position is: 4
我知道我可能会迟到一点,但我想分享我使用 NumPy 数组的解决方案:
def get_level_peaks(v):
peaks = []
i = 1
while i < v.size-1:
pos_left = i
pos_right = i
while v[pos_left] == v[i] and pos_left > 0:
pos_left -= 1
while v[pos_right] == v[i] and pos_right < v.size-1:
pos_right += 1
is_lower_peak = v[pos_left] > v[i] and v[i] < v[pos_right]
is_upper_peak = v[pos_left] < v[i] and v[i] > v[pos_right]
if is_upper_peak or is_lower_peak:
peaks.append(i)
i = pos_right
peaks = np.array(peaks)
"""
# uncomment this part of the code
# to include first and last positions
first_pos, last_pos = 0, v.size-1
peaks = np.append([first_pos], peaks)
peaks = np.append(peaks, [last_pos])
"""
return peaks
- 示例 1 (see graph):
v = np.array([7, 2, 0, 4, 4, 6, 6, 9, 5, 5])
p = get_peaks(v)
print(v) # [7 2 0 4 4 6 6 9 5 5]
print(p) # [0 2 7 9] (peak indexes)
print(v[p]) # [7 0 9 5] (peak elements)
- 示例 2 (see graph):
v = np.array([8, 2, 1, 0, 1, 2, 2, 5, 9, 3])
p = get_peaks(v)
print(v) # [8 2 1 0 1 2 2 5 9 3]
print(p) # [0 3 8 9] (peak indexes)
print(v[p]) # [8 0 9 3] (peak elements)
- 示例 3 (see graph):
v = np.array([9, 8, 8, 8, 0, 8, 9, 9, 9, 6])
p = get_peaks(v)
print(v) # [9 8 8 8 0 8 9 9 9 6]
print(p) # [0 4 6 9] (peak indexes)
print(v[p]) # [9 0 9 6] (peak elements)
在示例 3 中,我们有一个从索引 6 到索引 8 的平坦上峰。在这种情况下,索引将始终指示平台的最左侧位置。如果要表示中间位置或者最右边的位置,只需更改这部分代码:
...
if is_upper_peak or is_lower_peak:
peaks.append(i)
...
对此:
...
# middle position
if is_upper_peak or is_lower_peak:
peaks.append((pos_left + pos_right) // 2)
...
...
# rightmost position
if is_upper_peak or is_lower_peak:
peaks.append(pos_right)
...
此代码采用 window 数字并给出该 window 大小内的峰值
l=[1,2,3,4,5,4,3,2,1,2,3,4,3,2,4,2,1,2]
n=int(input("The size of window on either side "))
for i in range(n,len(l)-n):
if max(l[i-n:i]+l[i+1:i+n+1])<l[i]:
print(l[i],' at index = ',i)
我正在尝试创建一些代码 returns 数值数组 "peaks"(或局部最大值)的位置和值。
例如,列表 arr = [0, 1, 2, 5, 1, 0]
在位置 3
处有一个峰值,值为 5
(因为 arr[3]
等于 5
)。
数组的第一个和最后一个元素不会被视为峰值(在数学函数的上下文中,您不知道之前和之后是什么,因此,您不知道它是否是一个峰值与否)。
def pick_peaks(arr):
print(arr)
posPeaks = {
"pos": [],
"peaks": [],
}
startFound = False
n = 0
while startFound == False:
if arr[n] == arr[n+1]:
n += 1
else:
startFound = True
endFound = False
m = len(arr) - 1
while endFound == False:
if arr[m] == arr[m-1]:
m -= 1
else:
endFound = True
for i in range(n+1, m):
if arr[i] == arr[i-1]:
None
elif arr[i] >= arr[i-1] and arr[i] >= arr[i+1]:
posPeaks["pos"].append(i)
posPeaks["peaks"].append(arr[i])
return posPeaks
我的问题是高原。 [1, 2, 2, 2, 1]
有峰值而 [1, 2, 2, 2, 3]
没有。当一个平台为峰时,记录平台的第一个位置。
感谢任何帮助。
如果您可以对数据进行预处理以删除重复数字并仅保留 1 个唯一数字,则您也可以对高原使用相同的算法。因此,您可以将示例 [1, 2, 2, 2, 1]
转换为 [1, 2, 1]
并应用相同的算法。
编辑: 代码:
from itertools import groupby
def process_data(data):
return [list(val for num in group) for val, group in groupby(data)]
def peaks(arr):
#print(arr)
posPeaks = {
"pos": [],
"peaks": [],
}
startFound = False
n = 0
while startFound == False:
if arr[n][0] == arr[n+1][0]:
n += 1
else:
startFound = True
endFound = False
m = len(arr) - 1
while endFound == False:
if arr[m][0] == arr[m-1][0]:
m -= 1
else:
endFound = True
for i in range(n+1, m):
if arr[i][0] == arr[i-1][0]:
None
elif arr[i][0] >= arr[i-1][0] and arr[i][0] >= arr[i+1][0]:
pos = sum([len(arr[idx]) for idx in range(i)])
posPeaks["pos"].append(pos) #.append(i)
posPeaks["peaks"].append(arr[i][0])
return posPeaks
print(peaks(process_data([0, 1, 2, 5, 1, 0])))
print(peaks(process_data([1, 2, 2, 2, 1])))
print(peaks(process_data([1, 2, 2, 2, 3])))
输出:
{'pos': [3], 'peaks': [5]}
{'pos': [1], 'peaks': [2]}
{'pos': [], 'peaks': []}
我建议您使用 groupby 对连续的相等值进行分组,然后为每个组存储第一个位置,例如 [1, 2, 2, 2, 1]
它在元组列表 [(1, 0), (2, 1), (1, 4)]
之后创建以下列表, 放在一起:
from itertools import groupby
def peaks(data):
start = 0
sequence = []
for key, group in groupby(data):
sequence.append((key, start))
start += sum(1 for _ in group)
for (b, bi), (m, mi), (a, ai) in zip(sequence, sequence[1:], sequence[2:]):
if b < m and a < m:
yield m, mi
print(list(peaks([0, 1, 2, 5, 1, 0])))
print(list(peaks([1, 2, 2, 2, 1])))
print(list(peaks([1, 2, 2, 2, 3])))
输出
[(5, 3)]
[(2, 1)]
[]
这是一个相当简单的生成器函数。只需循环并维护必要的状态:i
("growth" 的最后一个索引),up
(如果最后一个值更改为 "growth",则为真)
def peaks(ar):
i, up = 0, False
for j in range(1, len(ar)):
prev, val = ar[j-1], ar[j]
if up and val < prev:
yield prev, i
up = False
if val > prev:
i, up = j, True
>>> list(peaks([0,1,2,5,1,0]))
[(5, 3)]
>>> list(peaks([0,1,2,5,1,2,0]))
[(5, 3), (2, 5)]
>>> list(peaks([0,1,2,5,1,2,0,3]))
[(5, 3), (2, 5)]
>>> list(peaks([1,2,2,2,1]))
[(2, 1)]
>>> list(peaks([1,2,2,2,3]))
[]
一个较短的脚本可以是:
data_array = [1, 2, 5, 4, 6, 9]
# Delete the first and the last element of the data array.
reduced_array = [ data_array[i] for i in range(1, len(data_array)-1) ]
# Find the maximum value of the modified array
peak_value = max(reduced_array)
# Print out the maximum value and its index in the data array.
print 'The peak value is: ' + str(peak_value)
print 'And its position is: ' + str(data_array.index(peak_value))
输出:
The peak value is: 6
And its position is: 4
我知道我可能会迟到一点,但我想分享我使用 NumPy 数组的解决方案:
def get_level_peaks(v):
peaks = []
i = 1
while i < v.size-1:
pos_left = i
pos_right = i
while v[pos_left] == v[i] and pos_left > 0:
pos_left -= 1
while v[pos_right] == v[i] and pos_right < v.size-1:
pos_right += 1
is_lower_peak = v[pos_left] > v[i] and v[i] < v[pos_right]
is_upper_peak = v[pos_left] < v[i] and v[i] > v[pos_right]
if is_upper_peak or is_lower_peak:
peaks.append(i)
i = pos_right
peaks = np.array(peaks)
"""
# uncomment this part of the code
# to include first and last positions
first_pos, last_pos = 0, v.size-1
peaks = np.append([first_pos], peaks)
peaks = np.append(peaks, [last_pos])
"""
return peaks
- 示例 1 (see graph):
v = np.array([7, 2, 0, 4, 4, 6, 6, 9, 5, 5])
p = get_peaks(v)
print(v) # [7 2 0 4 4 6 6 9 5 5]
print(p) # [0 2 7 9] (peak indexes)
print(v[p]) # [7 0 9 5] (peak elements)
- 示例 2 (see graph):
v = np.array([8, 2, 1, 0, 1, 2, 2, 5, 9, 3])
p = get_peaks(v)
print(v) # [8 2 1 0 1 2 2 5 9 3]
print(p) # [0 3 8 9] (peak indexes)
print(v[p]) # [8 0 9 3] (peak elements)
- 示例 3 (see graph):
v = np.array([9, 8, 8, 8, 0, 8, 9, 9, 9, 6])
p = get_peaks(v)
print(v) # [9 8 8 8 0 8 9 9 9 6]
print(p) # [0 4 6 9] (peak indexes)
print(v[p]) # [9 0 9 6] (peak elements)
在示例 3 中,我们有一个从索引 6 到索引 8 的平坦上峰。在这种情况下,索引将始终指示平台的最左侧位置。如果要表示中间位置或者最右边的位置,只需更改这部分代码:
...
if is_upper_peak or is_lower_peak:
peaks.append(i)
...
对此:
...
# middle position
if is_upper_peak or is_lower_peak:
peaks.append((pos_left + pos_right) // 2)
...
...
# rightmost position
if is_upper_peak or is_lower_peak:
peaks.append(pos_right)
...
此代码采用 window 数字并给出该 window 大小内的峰值
l=[1,2,3,4,5,4,3,2,1,2,3,4,3,2,4,2,1,2]
n=int(input("The size of window on either side "))
for i in range(n,len(l)-n):
if max(l[i-n:i]+l[i+1:i+n+1])<l[i]:
print(l[i],' at index = ',i)