4

这是我想使用 numpy 实现的算法:

对于给定的一维数组,计算滑动窗口上的最大值和最小值。创建一个新数组,第一个值等于给定数组中的第一个值。对于每个后续值,从滑动窗口的最小值和最大值之间剪切插入新数组中的前一个值。

作为示例,让我们以数组a=[3, 4, 5, 4, 3, 2, 3, 3]和大小为 3 的滑动窗口为例。我们找到最小值和最大值:

min = [3, 4, 3, 2, 2, 2]
max = [5, 5, 5, 4, 3, 3]

现在我们的输出数组将从 的第一个元素开始a,所以它是3。对于下一个值,我将 3(插入的最后一个值)剪辑在 4 和 5 之间(在索引 1 处找到的最小值和最大值)。结果是 4。对于下一个值,我将 4 剪辑在 3 和 5 之间。它仍然是 4。依此类推。所以我们终于有了:

output = [3, 4, 4, 4, 3, 3]

我找不到避免在我的代码中使用 python for 循环的方法。这是我目前所拥有的:

def second_window(array, samples):
    sample_idx = samples - 1
    output = np.zeros_like(array[0:-sample_idx])
    start, stop = 0, len(array)
    last_value = array[0]
    # Sliding window is a deque of length 'samples'.
    sliding_window = deque(array[start : start+sample_idx], samples)
    for i in xrange( stop - start - sample_idx):
        # Get the next value in sliding window. After the first loop,
        # the left value gets discarded automatically.
        sliding_window.append(array[start + i + sample_idx])
        min_value, max_value = min(sliding_window), max(sliding_window)
        # Clip the last value between sliding window min and max
        last_value = min( max(last_value, min_value), max_value)
        output[start + i] = last_value
    return output

是否有可能仅使用 numpy 来实现此结果?

4

2 回答 2

2

我不认为你可以。您有时可以使用无缓冲的 ufunc 进行这种迭代计算,但事实并非如此。但让我详细说明...

好的,首先窗口最小/最大计算可以更快地完成:

>>> a = np.array([3, 4, 5, 4, 3, 2, 3, 3])
>>> len_a = len(a)
>>> win = 3
>>> win_a = as_strided(a, shape=(len_a-win+1, win), strides=a.strides*2)
>>> win_a
array([[3, 4, 5],
       [4, 5, 4],
       [5, 4, 3],
       [4, 3, 2],
       [3, 2, 3],
       [2, 3, 3]])
>>> min_ = np.min(win_a, axis=-1)
>>> max_ = np.max(win_a, axis=-1)

现在,让我们创建并填充您的输出数组:

>>> out = np.empty((len_a-win+1,), dtype=a.dtype)
>>> out[0] = a[0]

如果np.clip哪里有一个ufunc,我们可以尝试这样做:

>>> np.clip(out[:-1], min_[1:], max_[1:], out=out[1:])
array([4, 3, 3, 3, 3])
>>> out
array([3, 4, 3, 3, 3, 3])

但这不起作用,因为np.clip它不是 ufunc,并且似乎涉及一些缓冲。

如果你单独申请np.minimumnp.maximum那么它并不总是有效:

>>> np.minimum(out[:-1], max_[1:], out=out[1:])
array([3, 3, 3, 3, 3])
>>> np.maximum(out[1:], min_[1:], out=out[1:])
array([4, 3, 3, 3, 3])
>>> out
array([3, 4, 3, 3, 3, 3])

尽管对于您的特定情况,颠倒另一个确实有效:

>>> np.maximum(out[:-1], min_[1:], out=out[1:])
array([4, 4, 4, 4, 4])
>>> np.minimum(out[1:], max_[1:], out=out[1:])
array([4, 4, 4, 3, 3])
>>> out
array([3, 4, 4, 4, 3, 3])
于 2013-11-09T15:30:19.837 回答
0

您可以使用numpy.clip以矢量化方式执行裁剪操作,但在移动窗口上计算最小值和最大值将需要一些 Python 循环和双端队列或堆栈结构,就像您已经实现的那样。

有关该方法的更多示例,请参阅这些问题:

于 2013-11-09T14:19:29.517 回答