多维 numpy.outer 没有展平

Multidimensional numpy.outer without flatten

x 是 N × M 矩阵。

y是L向量的1。

我想return "outer product"在x和y之间,我们称它为z吧。

z[n,m,l] = x[n,m] * y[l]

我可能可以使用 einsum 来做到这一点。

np.einsum("ij,k->ijk", x[:, :, k], y[:, k])

或之后重塑。

 np.outer(x[:, :, k], y).reshape((x.shape[0],x.shape[1],y.shape[0]))

但我正在考虑仅在 np.outer 中执行此操作,或者看起来更简单、内存效率更高。

有办法吗?

它是 numpy "can't know unless you happen to know" 位之一:np.outer 扁平化多维输入而 np.multiply.outer 不:

m,n,l = 3,4,5
x = np.arange(m*n).reshape(m,n)
y = np.arange(l)
np.multiply.outer(x,y).shape
# (3, 4, 5)

outer 的代码是:

multiply(a.ravel()[:, newaxis], b.ravel()[newaxis, :], out)

正如它的文档所说,它变平了(即 ravel)。如果数组已经是 1d,则该表达式可以写成

a[:,None] * b[None,:]
a[:,None] * b        # broadcasting auto adds the None to b

我们可以将广播规则应用于您的 (n,m)*(1,l):

In [2]: x = np.arange(12).reshape(3,4); y = np.array([[1,2]])                                                
In [3]: x.shape, y.shape                                                                                     
Out[3]: ((3, 4), (1, 2))

你想要一个 (n,m,1) * (1,1,l) 实现的 (n,m,l)。我们需要向 x 添加尾随维度。 y 上的额外前导 1 是自动的:

In [4]: z = x[...,None]*y                                                                                    
In [5]: z.shape                                                                                              
Out[5]: (3, 4, 2)
In [6]: z                                                                                                    
Out[6]: 
array([[[ 0,  0],
        [ 1,  2],
        [ 2,  4],
        [ 3,  6]],

       [[ 4,  8],
        [ 5, 10],
        [ 6, 12],
        [ 7, 14]],

       [[ 8, 16],
        [ 9, 18],
        [10, 20],
        [11, 22]]])

使用einsum:

In [8]: np.einsum('nm,kl->nml', x, y).shape                                                                  
Out[8]: (3, 4, 2)

您批准的事实:

In [9]: np.multiply.outer(x,y).shape                                                                         
Out[9]: (3, 4, 1, 2)

表明 y 并不是真正的 (1,l) 而是 (l,)`。调整两者都很容易。

我认为它们之间的内存效率没有太大差异。在这个小例子中 In[4] 是最快的,但不是很多。