Variable width python peak detection
Here is a peak detection routine that works the way I want it. However, I want to make it more flexible.
def peak2(x,y,dp,dv):
# Define two arrays: one for the peaks and one
# for the valleys
peaks=[]
valleys=[]
# Create two arrays, one for x, and one for y, where each
# element of the new array # consists of three adjacent
# elements of the old array.
xt=zip(x,x[1:],x[2:])
yt=zip(y,y[1:],y[2:])
# Walk through these arrays, checking to see if the middle
# value of the three old elements exceeds its neighbors by
# d or more.
idx=1
for i,j in zip(xt,yt):
if(j[1]-j[0]>dp and j[1]-j[2]>dp):
peaks.append((x[idx],y[idx]))
elif (j[0]-j[1]>dv and j[2]-j[1]>dv):
valleys.append((x[idx],y[idx]))
idx+=1
return array(peaks),array(valleys)
As you can see, it determines the peak by comparing the value with its right and left neighbors. And if the value of the center is greater than its immediate neighbors at a certain threshold, then it is considered a peak. Similar logic for finding a valley.
I want to expand it so that it compares the center value with n neighbors on each side. I will pass the parameter to the function (name it w
), and if w=3
, then I will do something like this:
xt=zip(x,x[1:],x[2:])
yt=zip(y,y[1:],y[2:])
which is what is currently in the routine. But if w=5
, then I want this:
xt=zip(x,x[1:],x[2:],x[3:],x[4:])
yt=zip(y,y[1:],y[2:],y[3:],y[4:])
And if w=n
, where n
is odd, then I want:
xt=zip(x,x[1:],x[2:],...,x[n:])
yt=zip(y,y[1:],y[2:],...,y[n:])
So how can I construct these arrays where each element contains elements of n
other arrays?
source to share
You can use range
c slice
to create a list of arguments and then pass them using unboxing (c *
) to zip
:
xt = zip(*[x[slice(i, None)] for i in xrange(n)]) # use range in Python 3
yt = zip(*[y[slice(i, None)] for i in xrange(n)])
In case you may have more than two dimensions, it might be better to create the slice list once, and then use it with map
and list.__getitem__
to create new slices of the list:
slices = [slice(i, None) for i in xrange(n)]
xt = zip(*map(x.__getitem__, slices)
yt = zip(*map(y.__getitem__, slices)
zt = zip(*map(z.__getitem__, slices)
On another note, since the sizes of the arguments of your list are not constant, but zip
stops when the shortest sublist is exhausted (the last snippet in this case), you can use itertools.izip_longest
.
source to share
If you need to perform a switch operation on an iterator instead of a list, you can use itertools.tee()
to create n
offset iterators, for example:
Code:
import itertools as it
def shift(an_iter, n):
iters = it.tee(an_iter, n)
for i in range(n):
for _ in range(i):
# remove the first i elements
next(iters[i])
return zip(*iters)
Test code:
for i in shift('abcdefghij', 5):
print(i)
Results:
('a', 'b', 'c', 'd', 'e')
('b', 'c', 'd', 'e', 'f')
('c', 'd', 'e', 'f', 'g')
('d', 'e', 'f', 'g', 'h')
('e', 'f', 'g', 'h', 'i')
('f', 'g', 'h', 'i', 'j')
source to share