第一维的numpy广播

时间:2014-03-24 07:30:24

标签: python numpy

在NumPy中,是否有 easy 方式广播两个维度数组,例如(x,y)(x,y,z)? NumPy广播通常匹配最后一个维度的维度,因此通常的广播不起作用(它需要第一个数组具有维度(y,z))。

背景:我正在使用图像,其中一些是RGB(形状(h,w,3)),其中一些是灰度(形状(h,w))。我生成了形状为(h,w)的alpha蒙版,我想通过mask * im将蒙版应用于图像。由于上述问题,这不起作用,所以我最终不得不做

mask = mask.reshape(mask.shape + (1,) * (len(im.shape) - len(mask.shape)))

这很难看。代码的其他部分使用向量和矩阵进行操作,这也会遇到同样的问题:它无法尝试执行m + v m具有(x,y)形状v(x,)形状atleast_3d。可以使用例如{{1}},但我必须记住我真正想要的维度。

6 个答案:

答案 0 :(得分:7)

如何使用转置:

(a.T + c.T).T

答案 1 :(得分:4)

numpy函数通常具有检查维度的代码块,将数组重新整形为兼容的形状,所有这些都在进入添加或乘法的核心业务之前。它们可能会重塑输出以匹配输入。所以滚动自己做类似的操作并没有错。

不要随意忽略将变量3维度旋转到维度开头的想法。这样做利用了numpy在开始时自动添加维度的事实。

对于逐元素乘法,einsum非常强大。

np.einsum('ij...,ij...->ij...',im,mask)

将处理immask是2维或3维混合的情况(假设前2个始终是兼容的。不幸的是,这不会推广到添加或其他操作。

前段时间我用纯Python版本模拟了einsum。为此,我使用了np.lib.stride_tricks.as_stridednp.nditer。如果您想要更多混合和匹配尺寸的功能,请查看这些功能。

答案 2 :(得分:1)

作为另一个角度:如果您经常遇到这种模式,创建一个实用程序功能来强制进行正确广播可能会很有用:

def right_broadcasting(arr, target):
    return arr.reshape(arr.shape + (1,) * (target.ndim - arr.ndim))

虽然如果只有两种类型的输入(已经有3个dims或只有2个),id表示单个if语句更可取。

答案 3 :(得分:1)

为什么不装饰-process-undecorate:

def flipflop(func):
    def wrapper(a, mask):
        if len(a.shape) == 3:
            mask = mask[..., None]
        b = func(a, mask)
        return np.squeeze(b)
    return wrapper

@flipflop
def f(x, mask):
    return x * mask

然后

>>> N = 12
>>> gs = np.random.random((N, N))
>>> rgb = np.random.random((N, N, 3))
>>> 
>>> mask = np.ones((N, N))
>>> 
>>> f(gs, mask).shape
(12, 12)
>>> f(rgb, mask).shape
(12, 12, 3)

答案 4 :(得分:0)

使用np.newaxis进行索引会在该位置创建一个新轴。即

xyz = #some 3d array
xy = #some 2d array
xyz_sum = xyz + xy[:,:,np.newaxis]
or
xyz_sum = xyz + xy[:,:,None]

以这种方式建立索引会在此位置创建一个形状为1且步幅为0的轴。

答案 5 :(得分:0)

很容易,您只需在较小数组的末尾添加单例维度。例如,如果xyz_array的形状为(x,y,z),而xy_array的形状为(x,y),则可以

xyz_array + np.expand_dims(xy_array, xy_array.ndim)