Generalized method for rolling or sliding window over array axis

穿精又带淫゛_ 提交于 2020-06-27 01:09:54

问题


How can I efficiently make an array of sliding windows across an arbitrary axis of a given array? For example, if I have the following array:

[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]
 [15 16 17 18 19]
 [20 21 22 23 24]
 [25 26 27 28 29]]

And a window size of 4, I would like to be able to make a sliding window across the first dimension, like this:

[[[ 0  1  2  3  4]
  [ 5  6  7  8  9]
  [10 11 12 13 14]
  [15 16 17 18 19]]

 [[ 5  6  7  8  9]
  [10 11 12 13 14]
  [15 16 17 18 19]
  [20 21 22 23 24]]

 [[10 11 12 13 14]
  [15 16 17 18 19]
  [20 21 22 23 24]
  [25 26 27 28 29]]]

But also across the second dimension, like this:

[[[ 0  1  2  3]
  [ 5  6  7  8]
  [10 11 12 13]
  [15 16 17 18]
  [20 21 22 23]
  [25 26 27 28]]

 [[ 1  2  3  4]
  [ 6  7  8  9]
  [11 12 13 14]
  [16 17 18 19]
  [21 22 23 24]
  [26 27 28 29]]]

回答1:


You can build such an array efficiently, in constant time and and without using any additional memory, using numpy.lib.stride_tricks.as_strided. The resulting array will be a view with some limitations, but you can always make a copy if you need a contiguous array.

The following function solves the general problem:

import numpy as np

def as_sliding_window(x, window_size, axis=0, window_axis=None,
                      subok=False, writeable=True):
    """
    Make a sliding window across an axis.

    Uses ``numpy.lib.stride_tricks.as_strided``, similar caveats apply.

    Parameters
    ----------
    x : array_like
        Array from where the sliding window is created.
    window_size: int
        Size of the sliding window.
    axis: int
        Dimension across which the sliding window is created.
    window_axis: int
        New dimension for the sliding window. By default, the new
        dimension is inserted before ``axis``.
    subok: bool
        If True, subclasses are preserved
        (see ``numpy.lib.stride_tricks.as_strided``).
    writeable: bool
        If set to False, the returned array will always be readonly.
        Otherwise it will be writable if the original array was. It
        is advisable to set this to False if possible
        (see ``numpy.lib.stride_tricks.as_strided``).

    Returns
    --------
    sliding_window: ndarray
        View of the given array as a sliding window along ``axis``.
    """
    from numpy.lib.stride_tricks import as_strided
    x = np.asarray(x)
    axis %= x.ndim
    if window_axis is None:
        window_axis = axis
    window_axis %= x.ndim + 1
    # Make shape
    shape = list(x.shape)
    n = shape[axis]
    shape[axis] = window_size
    shape.insert(window_axis, max(n - window_size + 1, 0))
    # Make strides
    strides = list(x.strides)
    strides.insert(window_axis, strides[axis])
    # Make sliding window view
    sliding_window = as_strided(x, shape, strides,
                                subok=subok, writeable=writeable)
    return sliding_window

Examples:

x = np.arange(30).reshape((6, 5))
window_size = 4
print(x)
# [[ 0  1  2  3  4]
#  [ 5  6  7  8  9]
#  [10 11 12 13 14]
#  [15 16 17 18 19]
#  [20 21 22 23 24]
#  [25 26 27 28 29]]

print(as_sliding_window(x, window_size))
# [[[ 0  1  2  3  4]
#   [ 5  6  7  8  9]
#   [10 11 12 13 14]
#   [15 16 17 18 19]]
#
#  [[ 5  6  7  8  9]
#   [10 11 12 13 14]
#   [15 16 17 18 19]
#   [20 21 22 23 24]]
#
#  [[10 11 12 13 14]
#   [15 16 17 18 19]
#   [20 21 22 23 24]
#   [25 26 27 28 29]]]

print(as_sliding_window(x, window_size, axis=1, window_axis=0))
# [[[ 0  1  2  3]
#   [ 5  6  7  8]
#   [10 11 12 13]
#   [15 16 17 18]
#   [20 21 22 23]
#   [25 26 27 28]]
#
#  [[ 1  2  3  4]
#   [ 6  7  8  9]
#   [11 12 13 14]
#   [16 17 18 19]
#   [21 22 23 24]
#   [26 27 28 29]]]

# You can make sliding windows of sliding windows
print(as_sliding_window(as_sliding_window(x, window_size), window_size, axis=2).shape)
# (3, 4, 2, 4)

# New dimension can be put at the end with window_axis=-1
print(as_sliding_window(x, window_size, axis=0, window_axis=-1).shape)
# (4, 5, 3)


来源:https://stackoverflow.com/questions/53263678/generalized-method-for-rolling-or-sliding-window-over-array-axis

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!