我正在尝试制作一个类似numpy.inner
的函数,但它在两个数组的第一个轴上求和,而不是在最后一个轴上求总和。目前我正在使用tensordot
和rollaxis
:
def inner1(a, b):
return numpy.tensordot(numpy.rollaxis(a, 0, len(a.shape)), b, 1)
但我想知道:有更好的方法吗?也许是一个不需要我转动斧头的?
我觉得einsum
应该使这成为可能,但我不确定如何在这里使用它
当我指定下标字符串时,似乎需要我对a
和b
的维度进行硬编码,但我在这里不能真正做到这一点,因为对输入维度没有特别的要求。
(注意:我知道在第一个轴而不是最后一个轴上求和会对性能产生影响,但我在这里忽略了它们。)
我想您想要的是np.tensordot(a, b, (0, 0))
。
这不如tensordot
解决方案漂亮,但您可以从输入的ndim
构造einsum
字符串:
ll = 'abcdefghijklmnopqrstuvw'
astr = ll[0]+ll[1:a.ndim]+','+ll[0]+ll[a.ndim:a.ndim+b.ndim-1]
np.einsum(astr,a,b)
np.einsum
允许您将轴指定为列表,而不是字符串
np.einsum(a, [0]+range(1,a.ndim), b, [0]+range(a.ndim,a.ndim+b.ndim-1))
对于一对3d和2d阵列,它们产生:
np.einsum('abc,ad', a, b)
np.einsum(a, [0,1,2], b, [0,3])
'...'
在这里不起作用,因为这意味着重复的轴(在可能的范围内),其中你想要唯一的轴(除了第一个)。
虽然写起来更混乱,但einsum
解决方案比tensordot
解决方案快(小型测试阵列快3倍)。
einsum
的另一个选项是重塑阵列,将"剩余"维度减少到一。这给计算增加了一点时间,但不是很多:
np.einsum('ij,ik',a.reshape(a.shape[0],-1), b.reshape(a.shape[0],-1)).reshape(a.shape[1:]+b.shape[1:])