【问题标题】:composing numpy array with strides用 strides 组成 numpy 数组
【发布时间】:2016-04-22 19:41:05
【问题描述】:

我有一个数组A1_ijk 并想将它广播到A2_ijmnk,但仅适用于m=n 的情况。否则A2 应该用零填充。当然,我可以创建新的空数组并用A1 填充它,如下所示:

import numpy as np
A1 = np.random.rand(100, 5, 3)
A2 = np.zeros((100, 5, 2, 2, 3))
A2[..., 0, 0, :] = A1
A2[..., 1, 1, :] = A1

但是,我觉得这可以以更有效的方式完成。我试过as_strided

as_strided = np.lib.stride_tricks.as_strided
sz = A1.itemsize
A2 = as_strided(A1, shape=(100,5,2,2,3), strides=(5*3*sz, 3*sz, 0, 0, sz))

还有broadcast_to:

broadcast_to = np.lib.stride_tricks.broadcast_to
A2=broadcast_to(A1[...,None,None,:], (100,5,2,2,3))

不幸的是,这两种方法都用A1 值填充所有m, n 对。

我的问题是,是否可以使用跨步创建我需要的形状的数组,而无需实际复制数据?

【问题讨论】:

  • 在您的实际情况中A2.shape[2],A2.shape[3] 也将是(2,2) 吗?如果是这样,对于这么小的尺寸,您的代码在可读性和性能方面对我来说看起来还不错。
  • 这可以是(2,2)(3,3),但也可以是更多维度,例如m,n,o,p(2,2,2,2)(3,3,3,3)。但是我必须经常撰写A2。我希望大步前进,我只能更新 A1 并立即看到 A2 的变化。
  • 不是连续构造A1 并试图使A2 成为A1 的视图,你可以让A1 成为A2 的视图吗?
  • 理论上是的,但在这种情况下更新A1 只会更新A2 的查看部分,不是吗?
  • 是的。如果您要使A1 成为A2 的视图,则必须更改代码进行修改的方式。更新 A1 还不够。

标签: python arrays numpy


【解决方案1】:

我的问题是,是否可以使用 strides 来创建我需要的形状的数组,而无需实际复制数据?

不是。作为查看这一点的一种简单方法,请考虑如果您的数组中没有零,那么该数组的任何可能视图都不会为您提供所需的非对角零。

【讨论】:

  • 好吧,也许零也可以跨步?
  • @mrkwjc:您需要以某种方式将视图组成的数组放入多个单独的缓冲区中。 NumPy 不这样做。
【解决方案2】:

我可以使用np.diag_indices 简化编码。我不关心相对于跨步解决方案的效率(如果可能的话)。让我们看看我是否可以足够简化我的开发历史

首先是索引

In [2]: np.diag_indices(2)
Out[2]: (array([0, 1]), array([0, 1]))

更简单的开始;我们一开始不需要二维,可以通过重塑来改变。我们可能不需要结束维度,但我暂时先保留它:

In [3]: A1=np.arange(12).reshape(4,3)

现在构建参考解决方案:

In [4]: A2=np.zeros((4,2,2,3),int)    
In [5]: A2[:,0,0,:]=A1
In [6]: A2[:,1,1,:]=A1

In [7]: A2
Out[7]: 
array([[[[ 0,  1,  2],
         [ 0,  0,  0]],

        [[ 0,  0,  0],    
       [[[ 3,  4,  5],
         [ 0,  0,  0]],

        [[ 0,  0,  0],
         [ 3,  4,  5]]],


       ...

       [[[ 9, 10, 11],
         [ 0,  0,  0]],

         [ 0,  1,  2]]],

          ...
        [[ 0,  0,  0],
         [ 9, 10, 11]]]])

替代方案:

In [8]: A3=np.zeros((4,2,2,3),int)

In [9]: i,j=np.diag_indices(2)

In [10]: A3[:,i,j,:]=A1
...
ValueError: shape mismatch: value array of shape (4,3) could not be broadcast to indexing result of shape (2,4,3)

第一次尝试形状不匹配

In [12]: A2[:,i,j,:]
Out[12]: 
array([[[ 0,  1,  2],
        [ 0,  1,  2]],

       [[ 3,  4,  5],
        [ 3,  4,  5]],

       [[ 6,  7,  8],
        [ 6,  7,  8]],

       [[ 9, 10, 11],
        [ 9, 10, 11]]])

In [13]: A2[:,i,j,:].shape
Out[13]: (4, 2, 3)

我们需要修改A1,让它可以广播到目标槽。

In [14]: A1.shape
Out[14]: (4, 3)

In [15]: A3[:,i,j,:] = A1[:,None,:]

In [16]: np.allclose(A2,A3)
Out[16]: True

A2[...,i,j,:] = A1[...,None,:] 应该处理您的示例。

一个更简单的版本,从 1d 数组开始,扩展到 3d

In [21]: a1=np.arange(3)

In [22]: a3=np.zeros((2,2,3),int)

In [23]: a3[...,i,j,:]=a1[...,None,:]

In [24]: a3[i,j,:]=a1   # equivalent since a1[None,:] is automatic

In [25]: a3
Out[25]: 
array([[[0, 1, 2],
        [0, 0, 0]],

       [[0, 0, 0],
        [0, 1, 2]]])

a3 没有a1 值的重复模式;是吗?

In [36]: a3.flatten()
Out[36]: array([0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 1, 2])

正如您所发现的,用as_strides 填充所有插槽很容易,但仅填充对角线很难:

In [46]: ast(a1,shape=a3.shape, strides=(0,0,4))
Out[46]: 
array([[[0, 1, 2],
        [0, 1, 2]],

       [[0, 1, 2],
        [0, 1, 2]]])

【讨论】:

    【解决方案3】:

    你需要用至少 n 个零来填充你的数据;那么你可以设置 stride[n]==-stride[m] 来达到预期的效果,并避免分配顺序 n*m 零。

    但有件事告诉我,如果您放眼全局,必须有更优雅的解决方案来解决您的问题。

    【讨论】:

    猜你喜欢
    • 2022-01-18
    • 1970-01-01
    • 2019-11-29
    • 1970-01-01
    • 2021-12-28
    • 2021-02-13
    • 2016-08-23
    • 2019-04-05
    • 2019-03-02
    相关资源
    最近更新 更多