Python 点(A,B,3)的Numpy当量

Python 点(A,B,3)的Numpy当量,python,matlab,numpy,matrix,dot-product,Python,Matlab,Numpy,Matrix,Dot Product,假设我有两个三维矩阵,就像这样(取自这个matlab示例): 如果我想沿着三维方向进行两两点积,我可以在matlab中这样做: C = dot(A,B,3) 结果是: C = 106 140 178 220 numpy中的等效操作是什么,最好是矢量化选项,以避免在整个数组中写入双for循环。我似乎无法理解np.tensordot或np.inner应该做什么,但它们可能是选项 In [169]: A = np.dstack([[[1, 1],[1 ,1]],[[2 ,3],[

假设我有两个三维矩阵,就像这样(取自这个matlab示例):

如果我想沿着三维方向进行两两点积,我可以在matlab中这样做:

C = dot(A,B,3)
结果是:

C =
  106   140
  178   220
numpy中的等效操作是什么,最好是矢量化选项,以避免在整个数组中写入双for循环。我似乎无法理解
np.tensordot
np.inner
应该做什么,但它们可能是选项

In [169]:

A = np.dstack([[[1, 1],[1 ,1]],[[2 ,3],[4, 5]],[[6, 7],[8, 9]]])
B = np.dstack([[[2, 2],[2, 2]],[[10, 11],[12, 13]],[[14, 15], [16, 17]]])
c=np.tensordot(A, B.T,1)
np.vstack([np.diag(c[:,i,i]) for i in range(A.shape[0])]).T
Out[169]:
array([[106, 140],
       [178, 220]])
但令人惊讶的是,它是最慢的:

In [170]:

%%timeit
c=np.tensordot(A, B.T,1)
np.vstack([np.diag(c[:,i,i]) for i in range(A.shape[0])]).T
10000 loops, best of 3: 95.2 µs per loop
In [171]:

%timeit np.einsum('i...,i...',a,b)
100000 loops, best of 3: 6.93 µs per loop
In [172]:

%timeit inner1d(A,B)
100000 loops, best of 3: 4.51 µs per loop
这里有一个解决方案:

A = dstack([[[1, 1],[1 ,1]],[[2 ,3],[4, 5]],[[6, 7],[8, 9]]])
B = dstack([[[2, 2],[2, 2]],[[10, 11],[12, 13]],[[14, 15], [16, 17]]])

C = einsum('...k,...k',A,B)
基本上,
dstack
沿着第三个轴连接,(),然后使用numpy()提供的强大的爱因斯坦求和工具
einsum
,使用np.einsum:

In [9]: B = np.array([[[2, 2],[2, 2]],[[10, 11],[12, 13]],[[14, 15],[16, 17]]])

In [10]: A = np.array([[[1, 1],[1, 1]],[[2, 3],[4, 5]],[[6, 7],[8, 9]]]) 

In [11]: np.einsum('i...,i...',A,B)
Out[11]:
array([[106, 140],
       [178, 220]])
或者这里有另一个有趣的例子:

In [37]: from numpy.core.umath_tests import inner1d

In [38]: inner1d(A,B)
Out[38]:
array([[106, 140],
       [178, 220]])
Edit针对@flebool的评论,
inner1d
适用于(2,2,3)和(3,2,2)形状的数组:

In [41]: A = dstack([[[1, 1],[1 ,1]],[[2 ,3],[4, 5]],[[6, 7],[8, 9]]])

In [42]: B = dstack([[[2, 2],[2, 2]],[[10, 11],[12, 13]],[[14, 15], [16, 17]]])

In [43]: inner1d(A,B)
Out[43]:
array([[106, 140],
       [178, 220]])

两个
nxn
矩阵的一般情况是什么?@flebool,与joshAdel的另一个答案类似,请参见编辑。请注意
A,B
的大小不正确。在Matlab代码中,数组具有shape
2,2,3
,而您的数组具有shape
3,2,2
,需要更改程序的所有逻辑。@flebool,已更新。令人惊讶的是,
tensordot
速度最慢。我实际上避免了Einsterin求和,假设它会很慢。我想它会比较慢,因为for循环和调用
diag
。显然,我希望
inner1d
更快,但它甚至没有文档记录,或者至少我找不到它的文档。所以,假设我已经有了我的23-d
nxnxk
数组,我所需要做的就是
C=einsum('…k,…k',A,B)
?这会比双for循环更有效吗?是的,如果你习惯于爱因斯坦求和,它会更有效,甚至更可读。请注意,
a,B
没有合适的大小。在Matlab代码中,数组具有shape
2,2,3
,而您的数组具有shape
3,2,2
,需要更改程序的所有逻辑这似乎是最干净的解决方案。与einsum相比,它有任何性能下降吗?@Stankalank对于OP中的测试阵列,
einsum
=5.33µs/循环,
inner1d
=4.3µs/循环。对于(2,210000)
einsum
=42.6µs/循环和
inner1d
=41.6µs/循环,尽管时间会因硬件和numpy版本/编译设置而异
inner1d
?它的
\uuuuu doc\uuuuuu
非常简陋。@hpaulj我不记得我第一次在哪里偶然发现这个方法,但是你可以从导入中看到,它不是一个明显的使用方法。您可以在以下位置查看源代码(C代码):
In [41]: A = dstack([[[1, 1],[1 ,1]],[[2 ,3],[4, 5]],[[6, 7],[8, 9]]])

In [42]: B = dstack([[[2, 2],[2, 2]],[[10, 11],[12, 13]],[[14, 15], [16, 17]]])

In [43]: inner1d(A,B)
Out[43]:
array([[106, 140],
       [178, 220]])