关于np.瓷砖和色情广播

2024-09-28 22:22:15 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有一个2D numpy数组A,形状为(m, n)。我想创建一个形状为(m, n, k)的3D数组B,这样B[:, :, l]是任何片l的{}的副本。我可以想出两种方法:

np.tile(A, (m, n, k))

或者

^{pr2}$

第一种方法似乎更简单,但我在np.tile的文档中提到:

Note: Although tile may be used for broadcasting, it is strongly
recommended to use numpy's broadcasting operations and functions.

为什么会这样,这也是np.repeat的问题吗?在

我的另一个担心是,如果m == n == k,那么{}是否会造成关于哪个轴被扩充的混乱?在

总之,我有两个问题:

  1. 为什么np.tile不是首选,并且在某些情况下m == n == k会导致意外行为?在
  2. 在时间和记忆方面,以上两种方法中哪一种更有效?有没有比这两种方法更干净或更有效的方法?在

Tags: 方法文档numpynp副本数组bemay
2条回答
In [100]: A = np.arange(12).reshape(3,4)

使用“重复”在末尾添加新尺寸:

^{pr2}$

使用“平铺”和“重复”在开始处添加新尺寸:

In [104]: np.tile(A, (2,1,1)).shape
Out[104]: (2, 3, 4)
In [105]: np.repeat(A[None,:,:], 2, axis=0).shape
Out[105]: (2, 3, 4)

如果我们用平铺在最后一个维度上指定2个重复,则会产生不同的形状

In [106]: np.tile(A, (1,1,2)).shape
Out[106]: (1, 3, 8)

注意tile关于在维度前面加上repeats元组的内容比形状大。在

但是,如果在计算中使用了扩展数组(如注释中所述),则不需要进行完全重复的复制。可以使用正确形状的临时视图,利用broadcasting。在

In [107]: A1=np.arange(12).reshape(3,4)
In [108]: A2=np.arange(8).reshape(4,2)
In [109]: A3=A1[:,:,None] + A2[None,:,:]
In [110]: A3.shape
Out[110]: (3, 4, 2)
In [111]: A3
Out[111]: 
array([[[ 0,  1],
        [ 3,  4],
        [ 6,  7],
        [ 9, 10]],

       [[ 4,  5],
        [ 7,  8],
        [10, 11],
        [13, 14]],

       [[ 8,  9],
        [11, 12],
        [14, 15],
        [17, 18]]])

使用Nonenp.newaxis),数组视图是(3,4,1)和(1,4,2)形状的,它们一起广播为(3,4,2)。在第二种情况下,我可以不使用None,因为广播会自动添加。但是后面的None是必需的。在

In [112]: (A1[:,:,None] + A2).shape
Out[112]: (3, 4, 2)

要添加一维数组(最后一个维度):

In [113]: (A1[:,:,None] + np.array([1,2])[None,None,:]).shape
Out[113]: (3, 4, 2)
In [114]: (A1[:,:,None] + np.array([1,2])).shape
Out[114]: (3, 4, 2)

两个基本广播步骤:

  • 根据需要添加大小为1的维度作为开始(自动[None,....]
  • 将所有尺寸为1的尺寸展开为共享尺寸

这组计算说明了这一点:

In [117]: np.ones(2) + np.ones(3)
ValueError: operands could not be broadcast together with shapes (2,) (3,) 

In [118]: np.ones(2) + np.ones((1,3))
ValueError: operands could not be broadcast together with shapes (2,) (1,3) 

In [119]: np.ones(2) + np.ones((3,1))
Out[119]: 
array([[2., 2.],
       [2., 2.],
       [2., 2.]])
In [120]: np.ones((1,2)) + np.ones((3,1))
Out[120]: 
array([[2., 2.],
       [2., 2.],
       [2., 2.]])

缺少中间维度

In [126]: np.repeat(A[:,None,:],2,axis=1)+np.ones(4)
Out[126]: 
array([[[ 1.,  2.,  3.,  4.],
        [ 1.,  2.,  3.,  4.]],

       [[ 5.,  6.,  7.,  8.],
        [ 5.,  6.,  7.,  8.]],

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

有一种更“先进”的替代方案(但不一定更快):

In [127]: np.broadcast_to(A[:,None,:],(3,2,4))+np.ones(4)

假设要将shape-(m, n)数组和shape-(n, k)数组都展开为形状(m, n, k)并将它们相加。在这种情况下,您根本不需要物理扩展阵列;对齐轴和广播可以很好地工作:

A = something of shape (m, n)
B = something of shape (n, k)

C = A[..., np.newaxis] + B

这不需要复制AB中的数据,并且应该比任何涉及物理拷贝的操作都快得多。在

相关问题 更多 >