用步幅组成numpy数组

时间:2016-04-22 19:41:05

标签: python arrays numpy

我有一个数组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))

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

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

3 个答案:

答案 0 :(得分:2)

  

我的问题是,如果可以使用步幅来创建我需要使用步幅而无需实际复制数据的形状数组吗?

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

答案 1 :(得分:1)

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

首先是指数

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

更简单的开始;我们一开始不需要2个尺寸,可以通过重塑来改变。我们可能不需要结束维度,但我现在就离开了:

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]]])

答案 2 :(得分:0)

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

但有些事情告诉我,如果你拍摄更大的图片,必须有一个更优雅的问题解决方案。