今天早上花了一段时间寻找一个泛化的问题来指出关于 as_strided 和/或 how to make generalized window functions 的问题的重复项。似乎有很多 questions 关于如何(安全地)为机器学习、卷积、图像处理和/或数值积分创建补丁、滑动窗口、滚动窗口、瓦片或 View 到阵列上。

我正在寻找一个通用函数,它可以接受 windowstepaxis 参数并返回 as_strided 任意维度的 View 。我将在下面给出我的答案,但我很感兴趣是否有人可以提出更有效的方法,因为我不确定使用 np.squeeze() 是最好的方法,我不确定我的 assert 语句是否使函数足够安全,可以写入结果 View ,我不知道如何处理 axis 不是升序的边缘情况。

尽职调查

我能找到的最通用的函数是@eickenberg 编写的 sklearn.feature_extraction.image.extract_patches (以及明显等效的 skimage.util.view_as_windows ),但这些在网上没有得到很好的记录,并且不能在比原始数组中更少的轴上做窗口(例如,this question 要求在一个轴上有一个特定大小的窗口)。也经常问题需要一个 numpy 唯一的答案。

@Divakar 为一维输入 here 创建了一个通用的 numpy 函数,但更高维的输入需要多加注意。我做了一个裸骨 2D window over 3d input method ,但它不是很可扩展。

最佳答案

EDIT JAN 2020 :将可迭代返回从列表更改为生成器以节省内存。
EDIT OCT 2020 :将生成器放在一个单独的函数中,因为混合生成器和 return 语句不能直观地工作。
这是我到目前为止的食谱:

def window_nd(a, window, steps = None, axis = None, gen_data = False):
        """
        Create a windowed view over `n`-dimensional input that uses an
        `m`-dimensional window, with `m <= n`

        Parameters
        -------------
        a : Array-like
            The array to create the view on

        window : tuple or int
            If int, the size of the window in `axis`, or in all dimensions if
            `axis == None`

            If tuple, the shape of the desired window.  `window.size` must be:
                equal to `len(axis)` if `axis != None`, else
                equal to `len(a.shape)`, or
                1

        steps : tuple, int or None
            The offset between consecutive windows in desired dimension
            If None, offset is one in all dimensions
            If int, the offset for all windows over `axis`
            If tuple, the steps along each `axis`.
                `len(steps)` must me equal to `len(axis)`

        axis : tuple, int or None
            The axes over which to apply the window
            If None, apply over all dimensions
            if tuple or int, the dimensions over which to apply the window

        gen_data : boolean
            returns data needed for a generator

        Returns
        -------

        a_view : ndarray
            A windowed view on the input array `a`, or `a, wshp`, where `whsp` is the window shape needed for creating the generator

        """
        ashp = np.array(a.shape)

        if axis != None:
            axs = np.array(axis, ndmin = 1)
            assert np.all(np.in1d(axs, np.arange(ashp.size))), "Axes out of range"
        else:
            axs = np.arange(ashp.size)

        window = np.array(window, ndmin = 1)
        assert (window.size == axs.size) | (window.size == 1), "Window dims and axes don't match"
        wshp = ashp.copy()
        wshp[axs] = window
        assert np.all(wshp <= ashp), "Window is bigger than input array in axes"

        stp = np.ones_like(ashp)
        if steps:
            steps = np.array(steps, ndmin = 1)
            assert np.all(steps > 0), "Only positive steps allowed"
            assert (steps.size == axs.size) | (steps.size == 1), "Steps and axes don't match"
            stp[axs] = steps

        astr = np.array(a.strides)

        shape = tuple((ashp - wshp) // stp + 1) + tuple(wshp)
        strides = tuple(astr * stp) + tuple(astr)

        as_strided = np.lib.stride_tricks.as_strided
        a_view = np.squeeze(as_strided(a,
                                     shape = shape,
                                     strides = strides))
        if gen_data :
            return a_view, shape[:-wshp.size]
        else:
            return a_view

def window_gen(a, window, **kwargs):
    #Same docstring as above, returns a generator
    _ = kwargs.pop(gen_data, False)
    a_view, shp = window_nd(a, window, gen_data  = True, **kwargs)
    for idx in np.ndindex(shp):
        yield a_view[idx]
一些测试用例:
a = np.arange(1000).reshape(10,10,10)

window_nd(a, 4).shape # sliding (4x4x4) window
Out: (7, 7, 7, 4, 4, 4)

window_nd(a, 2, 2).shape # (2x2x2) blocks
Out: (5, 5, 5, 2, 2, 2)

window_nd(a, 2, 1, 0).shape # sliding window of width 2 over axis 0
Out: (9, 2, 10, 10)

window_nd(a, 2, 2, (0,1)).shape # tiled (2x2) windows over first and second axes
Out: (5, 5, 2, 2, 10)

window_nd(a,(4,3,2)).shape  # arbitrary sliding window
Out: (7, 8, 9, 4, 3, 2)

window_nd(a,(4,3,2),(1,5,2),(0,2,1)).shape #arbitrary windows, steps and axis
Out: (7, 5, 2, 4, 2, 3) # note shape[-3:] != window as axes are out of order

关于arrays - 使用 numpy `as_strided` 函数创建任意尺寸的补丁、瓷砖、滚动或滑动窗口,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45960192/

10-15 06:01
查看更多