【问题标题】:Confusion regarding np.tile and numpy broadcasting关于 np.tile 和 numpy 广播的困惑
【发布时间】:2018-01-23 18:13:15
【问题描述】:

假设我有一个形状为(m, n) 的二维numpy 数组A。我想创建一个形状为(m, n, k) 的3D 数组B,这样B[:, :, l] 是任何切片lA 的副本。我可以想到两种方法来做到这一点:

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

np.repeat(A[:, :, np.newaxis], k, axis=-1)

第一种方法似乎更简单,但我在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,那么np.tile() 是否会在增强哪个轴方面造成混淆?

总的来说,我有两个问题:

  1. 为什么np.tile 不是首选,m == n == k 在某些情况下会导致意外行为?
  2. 上述两种方式中哪一种在时间和内存方面效率更高?有没有比这两种方法更清洁或更有效的方法?

【问题讨论】:

  • 您的np.tile 呼叫没有执行您想要执行的操作。 np.tile 不能那样做;它需要重复计数,而不是新形状,并且不会从 mnk 的值中猜测如何将旧形状与新形状对齐。
  • Look at the code for tile. It uses a reshape plus repeat. repeat`是编译后的函数。
  • 收到B 后会做什么? (该问题的答案首先有助于告知构建B 的选项。)
  • @MarkDickinson 就我而言,我实际上有一个形状为 (m, n) 的数组 A1 和一个形状为 A2 的数组 (n, k),我想将每个数组扩展为一个 3D 数组塑造(m, n, k) 并计算总和数组。
  • @Hilbert:如果此扩展的目的是计算总和数组,那么您不需要存储物理扩展的数组。广播就足够了。

标签: python arrays numpy broadcasting


【解决方案1】:

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

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

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

这不需要复制AB 中的数据,并且运行速度应该比任何涉及物理副本的操作都要快。

【讨论】:

    【解决方案2】:
    In [100]: A = np.arange(12).reshape(3,4)
    

    使用repeat在末尾添加一个新维度:

    In [101]: B = np.repeat(A[:,:,np.newaxis], 2, axis=-1)
    In [102]: B.shape
    Out[102]: (3, 4, 2)
    

    使用平铺和重复在开头添加新维度:

    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 所说的关于在维度前面加上重复元组大于形状。

    但是,如果您在计算中使用了扩展数组,如 cmets 中所述,则不需要制作完整的重复副本。可以使用正确形状的临时视图,利用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]]])
    

    使用None (np.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)
    

    【讨论】:

    • 谢谢!对于您的最后一条评论,自动广播究竟是如何工作的? numpy 默认会沿哪个维度广播?
    • 抱歉,再问一个问题:在某些情况下,我还有一个形状为 (k,) 的一维数组 c,我想再次将 c 扩展为 (m, n, k) 并将其相加在扩展为 (m, n, k) 后,具有形状为 (m, k) 的二维数组 A 。在这种情况下我可以做广播吗?我刚试过c[None, None, :] + A[:, None, :],但当然这给了我一个形状数组(m,1,k)...
    • 我添加了一个k 示例。
    • 谢谢!虽然在我的情况下,n 维度不会以Ac 的形状出现,所以我假设我必须在其中一个上做np.repeat
    • 好的,是的,如果两者都没有n 维度,那么需要某种repeat
    猜你喜欢
    • 2019-11-29
    • 1970-01-01
    • 1970-01-01
    • 2014-10-30
    • 2011-12-13
    • 2017-12-04
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多