Numpy发现元素大于前n个元素

时间:2017-03-14 14:06:44

标签: python loops numpy iteration vectorization

我想识别numpy数组中的元素,它比从索引5开始的前5个元素更大。我用'for'循环写下了这个问题的解决方案。我的问题是如何在没有迭代的情况下解决这个问题呢?这个问题是否存在某些功能?

import numpy as np
values = np.array([160, 140, 152, 142, 143, 186, 152, 145, 165, 152, 143, 148, 196, 152, 145, 157, 152])
indices = []
for i in range(5, len(values)):
    if np.all(values[(i-5):i]<values[i]):
        indices.append(i)

3 个答案:

答案 0 :(得分:2)

一个技巧是计算跨越数组长度的滑动窗口中的最大值,不包括当前元素并与当前元素进行比较。如果当前元素更大,那么我们就有赢家,否则我们不会。

要获得滑动最大值,我们可以使用Scipy's 1D max过滤器的服务,因此可以实现这样的实现 -

from scipy.ndimage.filters import maximum_filter1d as maxf

def greater_than_all_prev(values, W=5):
    hW = (W-1)//2
    maxv = maxf(values,W, origin=hW)
    mask = values[1:] > maxv[:-1]
    mask[:W-1] = 0
    return np.flatnonzero(mask)+1

示例运行 -

In [336]: values
Out[336]: 
array([160, 140, 152, 142, 143, 186, 152, 145, 165, 152, 143, 148, 196,
       152, 145, 157, 152])

In [337]: greater_than_all_prev(values, W=5)
Out[337]: array([ 5, 12])

答案 1 :(得分:1)

Erik Rigtorp为Efficient rolling statistics with NumPy发布了一个很好的技巧:

  

与C代码中的循环相比,Python中的循环非常慢。   幸运的是,有一个技巧可以让NumPy执行这种循环   在C代码内部。这是通过添加额外的维度来实现的   与窗口大小相同,并有适当的步幅:

def rolling_window(a, window):
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    strides = a.strides + (a.strides[-1],)
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

使用此功能可以:

winlen = 5

values = np.array([160, 140, 152, 142, 143, 186, 152, 145, 165, 152, 143, 148, 196, 152, 145, 157, 152])

rolling_values = rolling_window(values, winlen + 1)
rolling_indices = np.arange(winlen, values.shape[0])

mask = np.all(rolling_values[:, [-1]] >  rolling_values[:, :-1], axis=1)
indices = rolling_indices[mask]
print(indices)

说明:

rolling_window将值转换为以下格式的数组:

print(rolling_values)
array([[160, 140, 152, 142, 143, 186],
       [140, 152, 142, 143, 186, 152],
       [152, 142, 143, 186, 152, 145],
       [142, 143, 186, 152, 145, 165],
       [143, 186, 152, 145, 165, 152],
       [186, 152, 145, 165, 152, 143],
       [152, 145, 165, 152, 143, 148],
       [145, 165, 152, 143, 148, 196],
       [165, 152, 143, 148, 196, 152],
       [152, 143, 148, 196, 152, 145],
       [143, 148, 196, 152, 145, 157],
       [148, 196, 152, 145, 157, 152]])

每行包含一个元素(从第六个开始)和前五个元素。由于步幅技巧,这种表示不需要比原始数组更多的内存。

现在,我们可以比较每行中的最后一个元素是否大于previos元素,并查找相应的索引。

答案 2 :(得分:0)

一个简单的方法是:

@Value

如果您在某个索引处的import numpy as np values = np.array([160, 140, 152, 142, 143, 186, 152, 145, 165, 152, 143, 148, 196, 152, 145, 157, 152]) prod = np.ones_like(values) for n in range(1,6): prod *= values > np.roll(values, n) print(prod) 中找到1,那么在prod的此索引处,您的条件将大于前五个元素。您可以使用values找到这些索引。您应该注意np.where(prod == 1)包围数组的边界。