Numpy:多种外部产品

时间:2013-12-19 14:03:11

标签: python arrays numpy

一般问题

假设我有ndarray v形状(nrow,ncols,3)。我想计算形状outer_array的ndarray (nrow,ncols,3,3),其中包含每个索引(3)处形状(nrow,ncol)的向量的所有外积。当然,这是numpy.einsum存在的问题。 现在,我尝试过的是:

outer_array = numpy.einsum("xyi,xyj->xyij",v,v.conjugate())

现在,我不确定这是否会奏效:尽管outer_array具有预期的形状,但外部产品矩阵的元素与我期望的不一致。

我认为这是由于einsum表达式中标签的选择:产品应该在xy上求和,因为索引会重复,但是因为我在输出表达式中重用它们,总和的结果以某种方式广播。

另一方面,如果我写:

outer_array = numpy.einsum("xyi,uvj->...ij",v,v.conjugate())

numpy将为每对(x,y)(u,v)计算外部产品的所有可能组合,从而生成一个形状为(ncols,nrow,ncols,nrow,3,3)的数组,其中对角线(u,v) = (x,y)将包含期望的输出。

精确问题

如何选择einsum表示法中的前两个索引以获得一个数组,其中每个索引x,y我得到了向量v的外积而不必求助于第二个表达?

修改 显然,这种形式似乎也有效:

outer_array = numpy.einsum("...i,...j->...ij",v,v.conjugate())

我只能欣赏numpy广播的有用性!

1 个答案:

答案 0 :(得分:5)

'xyi,xyj->xyij'工作的关键是输出字符串中重复xy

让我们使用更简单的数组:

x = np.arange(6).reshape(3,2)
np.einsum.einsum('ij->j',x)
# array([6, 9])  # sums on the 1st dimension of `x`

现在有关此x的外部产品:

In [20]: x[:,:,None]*x[:,None,:]  # shape (3,2,2)
Out[20]: 
array([[[ 0,  0],
        [ 0,  1]],

       [[ 4,  6],
        [ 6,  9]],

       [[16, 20],
        [20, 25]]])

这是numpy广播的一个例子(即添加尺寸并扩展它们)

"...i,...j->...ij"中,...更像是现有但匿名维度的占位符。

einsum等价的是:

np.einsum('ij,ik->ijk',x,x)

(我应该在最后2个维度中进行非对称的计算)。

我已经找到了einsum的纯Python工作。重点是解析参数字符串,以及它如何为iter对象创建输入。它可以在github上找到:https://github.com/hpaulj/numpy-einsum/blob/master/einsum_py.py欢迎你玩它。它有一个debug标志来显示中间步骤。

我的einsum有调试输出:

In [23]: einsum_py.myeinsum('ij,ik->ijk',x,x,debug=True)
# ... some parsing information
[('ij', [105, 106], 'NONE'), ('ik', [105, 107], 'NONE')]
('ijk', [105, 106, 107], 'NONE')
iter labels: [105, 106, 107],'ijk'

op_axes [[0, 1, -1], [0, -1, 1], [0, 1, 2]]

op_axes是用于创建iter的关键参数,该对象迭代输入和输出数组的轴。它遍历所有数组的第1轴。对于第一个op和输出,第二个轴是1,对于第二个op,第二个轴是newaxis( - 1)。

使用ellipsis

In [24]: einsum_py.myeinsum('...j,...k->...jk',x,x,debug=True)
...
iter labels: [0, 106, 107],'0jk'
op_axes [[0, 1, -1], [0, -1, 1], [0, 1, 2]]

这会生成相同的op_axes,因此计算相同。