在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}},但我必须记住我真正想要的维度。
答案 0 :(得分:7)
如何使用转置:
(a.T + c.T).T
答案 1 :(得分:4)
numpy
函数通常具有检查维度的代码块,将数组重新整形为兼容的形状,所有这些都在进入添加或乘法的核心业务之前。它们可能会重塑输出以匹配输入。所以滚动自己做类似的操作并没有错。
不要随意忽略将变量3
维度旋转到维度开头的想法。这样做利用了numpy
在开始时自动添加维度的事实。
对于逐元素乘法,einsum
非常强大。
np.einsum('ij...,ij...->ij...',im,mask)
将处理im
和mask
是2维或3维混合的情况(假设前2个始终是兼容的。不幸的是,这不会推广到添加或其他操作。
前段时间我用纯Python版本模拟了einsum
。为此,我使用了np.lib.stride_tricks.as_strided
和np.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)