How to detect up and down trend in a list?
Question:
A lot of python list with some data, how to detect the data in the list is meet downward then upward.
For example:
a1 = [8,6,4,1,-2,-6,5,8,9,87]
a2 = [8,6,4,1,-2,-6,5,-8,9,10]
where data in a1 is downard then upward,expect print ‘OK’
but data in a2 is downard then upward then downard last upward, expect print ‘NG’
how to do it by python?
Answers:
You can iterate through the list three items at a time and count the types of peaks that you see, either downward or upwards. At the end, return True
if there is only one downward peak, False
otherwise.
def one_downward_peak(data):
upward_peaks = 0
downward_peaks = 0
for i in range(len(data) - 2):
a, b, c = data[i:i+3]
if a > b < c:
downward_peaks += 1
elif a < b > c:
upward_peaks += 1
return upward_peaks == 0 and downward_peaks == 1
>>> one_downward_peak([8,6,4,1,-2,-6,5,8,9,87])
True
>>> one_downward_peak([8,6,4,1,-2,-6,5,-8,9,10])
False
If you want to optimize this, you could exit early as soon as you see an upward peak.
You can compute the sign of the successive differences, then only keep the different ones. If this yields [-1, 1]
this is a OK
, else a NG
:
import numpy as np
def check(lst):
# sign of successive difference
s = np.sign(np.diff(lst))
# mask to deduplicate successive values
m1 = np.r_[True, s[:-1]!=s[1:]]
# mask to remove flat lines
m2 = s != 0
# OK if both masks are True else NG
return 'OK' if s[m1&m2].tolist() == [-1, 1] else 'NG'
check(a1)
# 'OK'
check(a2)
# 'NG'
check([2,1,1,2])
# 'OK'
Intermediates:
### first example
lst
# [8, 6, 4, 1, -2, -6, 5, 8, 9, 87]
s = np.sign(np.diff(lst))
# array([-1, -1, -1, -1, -1, 1, 1, 1, 1])
s[np.r_[True, s[:-1]!=s[1:]]].tolist()
# [-1, 1]
### second example
lst
# [8, 6, 4, 1, -2, -6, 5, -8, 9, 10]
s = np.sign(np.diff(lst))
# array([-1, -1, -1, -1, -1, 1, -1, 1, 1])
s[np.r_[True, s[:-1]!=s[1:]]].tolist()
# [-1, 1, -1, 1]
A lot of python list with some data, how to detect the data in the list is meet downward then upward.
For example:
a1 = [8,6,4,1,-2,-6,5,8,9,87]
a2 = [8,6,4,1,-2,-6,5,-8,9,10]
where data in a1 is downard then upward,expect print ‘OK’
but data in a2 is downard then upward then downard last upward, expect print ‘NG’
how to do it by python?
You can iterate through the list three items at a time and count the types of peaks that you see, either downward or upwards. At the end, return True
if there is only one downward peak, False
otherwise.
def one_downward_peak(data):
upward_peaks = 0
downward_peaks = 0
for i in range(len(data) - 2):
a, b, c = data[i:i+3]
if a > b < c:
downward_peaks += 1
elif a < b > c:
upward_peaks += 1
return upward_peaks == 0 and downward_peaks == 1
>>> one_downward_peak([8,6,4,1,-2,-6,5,8,9,87])
True
>>> one_downward_peak([8,6,4,1,-2,-6,5,-8,9,10])
False
If you want to optimize this, you could exit early as soon as you see an upward peak.
You can compute the sign of the successive differences, then only keep the different ones. If this yields [-1, 1]
this is a OK
, else a NG
:
import numpy as np
def check(lst):
# sign of successive difference
s = np.sign(np.diff(lst))
# mask to deduplicate successive values
m1 = np.r_[True, s[:-1]!=s[1:]]
# mask to remove flat lines
m2 = s != 0
# OK if both masks are True else NG
return 'OK' if s[m1&m2].tolist() == [-1, 1] else 'NG'
check(a1)
# 'OK'
check(a2)
# 'NG'
check([2,1,1,2])
# 'OK'
Intermediates:
### first example
lst
# [8, 6, 4, 1, -2, -6, 5, 8, 9, 87]
s = np.sign(np.diff(lst))
# array([-1, -1, -1, -1, -1, 1, 1, 1, 1])
s[np.r_[True, s[:-1]!=s[1:]]].tolist()
# [-1, 1]
### second example
lst
# [8, 6, 4, 1, -2, -6, 5, -8, 9, 10]
s = np.sign(np.diff(lst))
# array([-1, -1, -1, -1, -1, 1, -1, 1, 1])
s[np.r_[True, s[:-1]!=s[1:]]].tolist()
# [-1, 1, -1, 1]