numpy如何在1darray

时间:2015-05-14 08:27:11

标签: python numpy scipy

我有一份已分类的样本清单。他们按照他们的采样时间进行分类,其中每个样本在前一个样本之后一秒钟采样。 我想在指定大小的邻域中找到最小值。

例如,假设邻域大小为2且样本大小如下:

samples = [ 5, 12.3, 12.3, 7, 2, 6, 9, 10, 5, 9, 17, 2 ]

我期待以下输出:[5,2,5,2] 在numpy / scipy

中实现这一目标的最佳方法是什么?

编辑:解释最小值背后的原因:

  1. 5 - 旁边的2号窗口是[12.3 12.3]。 5更小
  2. 2 - 向左[12.3,7]向右[6 9]。 2是分钟
  3. 5 - 向左[9 10]向右[9 17]。 5是分钟
  4. 请注意,9分钟是否为左侧和右侧的2个窗口,值较小(2)

4 个答案:

答案 0 :(得分:11)

使用scipy的argrelextrema

>>> import numpy as np
>>> from scipy.signal import argrelextrema
>>> data = np.array([ 5, 12.3, 12.3, 7, 2, 6, 9, 10, 5, 9, 17, 2 ])
>>> radius = 2 # number of elements to the left and right to compare to
>>> argrelextrema(data, np.less, order=radius)
(array([4, 8]),)

这表明位置4和8(25)的数字是2个大小邻域中的最小数字。由于5仅支持2argrelextrema边界条件,因此未检测到边界处的数字(clipwrap)。至于你的问题,我猜你也对他们感兴趣。要检测它们,首先很容易添加反射边界条件:

>>> new_data = np.pad(data, radius, mode='reflect')
>>> new_data
array([ 12.3,  12.3,   5. ,  12.3,  12.3,   7. ,   2. ,   6. ,   9. ,
        10. ,   5. ,   9. ,  17. ,   2. ,  17. ,   9. ])

对于具有相应边界条件的数据,我们现在可以应用previus极值检测器:

>>> arg_minimas = argrelextrema(new_data, np.less, order=radius)[0] - radius
>>> arg_minimas
array([ 0,  4,  8, 11])

返回np.less的滑动窗口中发生局部极值(本例中radius=2以来的最小值)的位置。

请注意-radius+radius边界条件为reflect的数据包裹后修复np.pad索引。

编辑:如果你对价值观感兴趣,而不是在立场,那就是直截了当:

>>>  data[arg_minimas]
array([ 5.,  2.,  5.,  2.])

答案 1 :(得分:2)

看起来,基本上你是在滑动窗口中找到局部最小值,但是滑动窗口以这样一种方式滑动,即前一个窗口的结尾作为新窗口的开始。对于这样一个特定问题,此解决方案中建议使用broadcasting -

的矢量化方法
import numpy as np

# Inputs
N = 2
samples = [ 5, 12.3, 12.3, 7, 2, 6, 9, 10, 5, 9, 17, 2 ]

# Convert input list to a numpy array
S = np.asarray(samples)

# Calculate the number of Infs to be appended at the end
append_endlen = int(2*N*np.ceil((S.size+1)/(2*N))-1 - S.size)

# Append Infs at the start and end of the input array
S1 = np.concatenate((np.repeat(np.Inf,N),S,np.repeat(np.Inf,append_endlen)),0)

# Number of sliding windows
num_windows = int((S1.size-1)/(2*N))

# Get windowed values from input array into rows. 
# Thus, get minimum from each row to get the desired local minimum.
indexed_vals = S1[np.arange(num_windows)[:,None]*2*N + np.arange(2*N+1)]
out = indexed_vals.min(1)

示例运行

运行#1:原始输入数据

In [105]: S     # Input array
Out[105]: 
array([  5. ,  12.3,  12.3,   7. ,   2. ,   6. ,   9. ,  10. ,   5. ,
         9. ,  17. ,   2. ])

In [106]: N   # Window radius
Out[106]: 2

In [107]: out  # Output array
Out[107]: array([ 5.,  2.,  5.,  2.])

运行#2:修改输入数据,窗口半径= 2

In [101]: S     # Input array
Out[101]: 
array([  5. ,  12.3,  12.3,   7. ,   2. ,   6. ,   9. ,  10. ,   5. ,
         9. ,  17. ,   2. ,   0. ,  -3. ,   7. ,  99. ,   1. ,   0. ,
        -4. ,  -2. ])

In [102]: N   # Window radius
Out[102]: 2

In [103]: out  # Output array
Out[103]: array([ 5.,  2.,  5., -3., -4., -4.])

运行#3:修改输入数据,窗口半径= 3

In [97]: S    # Input array
Out[97]: 
array([  5. ,  12.3,  12.3,   7. ,   2. ,   6. ,   9. ,  10. ,   5. ,
         9. ,  17. ,   2. ,   0. ,  -3. ,   7. ,  99. ,   1. ,   0. ,
        -4. ,  -2. ])

In [98]: N   # Window radius
Out[98]: 3

In [99]: out  # Output array
Out[99]: array([ 5.,  2., -3., -4.])

答案 2 :(得分:1)

>>> import numpy as np
>>> a = np.array(samples)
>>> [a[max(i-2,0):i+2].min() for i in xrange(1, a.size)]
[5.0, 2.0, 2.0, 2.0, 2.0, 5.0, 5.0, 5.0, 2.0]

正如Divakar在评论中指出的那样,这就是滑动窗口产生的结果。如果您想删除重复项,可以单独完成

答案 3 :(得分:1)

如果窗口的最小值不等于最近添加的值,则会查看每个窗口,找到最小值,并将其添加到列表中。

samples = [5, 12.3, 12.3, 7, 2, 6, 9, 10, 5, 9, 17, 2]
neighborhood = 2

minima = []
for i in xrange(len(samples)):
  window = samples[max(0, i - neighborhood):i + neighborhood + 1]
  windowMin = min(window)
  if minima == [] or windowMin != minima[-1]:
    minima.append(windowMin)

这给出了你描述的输出:

print minima
> [5, 2, 5, 2]

然而, @ imaluengo的答案更好,因为如果它们在原始列表中有不同的索引,它将包含两个连续的相等最小值!