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?

+3


source to share


2 answers


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

.

+2


source


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')

      

+1


source







All Articles