微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 numpy 中设置数组的滑动窗口的值

如何解决在 numpy 中设置数组的滑动窗口的值

假设我有一个形状为 (3,3) 的二维数组,称之为 a,还有一个形状为 (7,7,5,5) 的零数组,称之为 b。我想通过以下方式修改 b

for p in range(5):
    for q in range(5):
        b[p:p + 3,q:q + 3,p,q] = a

给定:

a = np.array([[4,2,2],[9,5],9,4]])
b = np.zeros((7,5),dtype=int)

b 最终会是这样的:

>>> b[:,:,0]
array([[4,0],4,[0,0]])
>>> b[:,1]
array([[0,0]])

解决方法

考虑这种情况的一种方法是制作 b (6D) 的滑动窗口视图,切出您想要的部分(3D 或 4D),并将 a 分配给它们。

但是,有一种更简单的方法可以完全做到这一点。滑动窗口视图的工作方式是创建一个尺寸,该尺寸的步进小于您正在查看的尺寸的全尺寸。例如:

>>> x = np.array([1,2,3,4])
array([1,4])
>>> window = np.lib.stride_tricks.as_strided(
                 x,shape=(x.shape[0] - 2,3),strides=x.strides * 2)
[[1 2 3]
 [2 3 4]]

我在这里故意使用 np.lib.stride_tricks.as_strided 而不是 np.lib.stride_tricks.sliding_window_view,因为它具有您需要的一定灵活性。

只要小心,您的步幅可以大于比您正在查看的轴。在这种情况下,连续数组更宽容,但绝不是必需的。这方面的一个例子是 np.diag。你可以像这样实现它:

>>> x = np.arange(12).reshape(3,4)
array([[ 0,1,3],[ 4,5,6,7],[ 8,9,10,11]])
>>> diag = np.lib.stride_tricks.as_strided(
               x,shape=(min(x.shape),),strides=(sum(x.strides),))
array([ 0,10])

诀窍是仅查看您关心的 b 部分,从而使分配变得容易。由于广播规则,您希望视图的最后两个维度为 a.shape,步幅为 b.strides[:2],因为这是您想要放置 a 的位置。

视图的前两个维度将负责制作 a 的副本。您需要 25 个副本,因此形状将为 (5,5)。步幅是比较棘手的部分。让我们看一个 2D 案例,只是因为它更容易形象化,然后尝试概括:

>>> a0 = np.array([1,2])
>>> b0 = np.zeros((4,dtype=int)
>>> b0[0:2,0] = b0[1:3,1] = b0[2:4,2] = a0

目标是使视图沿第一个轴的 b0 的对角线跨越。所以:

>>> np.lib.stride_tricks.as_strided(
        b0,shape=(b0.shape[0] - a0.shape[0] + 1,a0.shape[0]),strides=(sum(b0.strides),b0.strides[0]))[:] = a0
>>> b0
array([[1,0],[2,[0,1],2]])

这就是您为 b 所做的,但每第二个维度相加:

a = np.array([[4,2],[9,5],4]])
b = np.zeros((7,7,5),dtype=int)
vshape = (*np.subtract(b.shape[:a.ndim],a.shape) + 1,*a.shape)
vstrides = (*np.add(b.strides[:a.ndim],b.strides[a.ndim:]),*b.strides[:a.ndim])
np.lib.stride_tricks.as_strided(b,shape=vshape,strides=vstrides)[:] = a

TL;DR

def emplace_window(a,b):
    vshape = (*np.subtract(b.shape[:a.ndim],*a.shape)
    vstrides = (*np.add(b.strides[:a.ndim],*b.strides[:a.ndim])
    np.lib.stride_tricks.as_strided(b,strides=vstrides)[:] = a

我是这样表述的,因为现在您可以将其应用于任意数量的维度。唯一的期望是 2 * a.ndim == b.ndimb.shape[a.ndim:] == b.shape[:a.ndim] - a.shape + 1

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。