What is the best way to do this?
做这个的最好方式是什么?
a = 3x3 array
b = 20x3 array
c = 20x3 array = some_dot_function(a, b) where:
c[0] = np.dot(a, b[0])
c[1] = np.dot(a, b[1])
c[2] = np.dot(a, b[2])
...etc...
I know this can be done with a simple python loop or using numpy's apply_along_axis, but I'm wondering if there is any good way to do this entirely within the underlying C code of numpy. I looked at tensordot and some other functions, but didn't have any luck. I also tried the following:
我知道这可以通过一个简单的python循环或使用numpy的apply_along_axis来完成,但我想知道是否有任何好方法可以在numpy的底层C代码中完成。我查看了tensordot和其他一些功能,但没有任何运气。我也尝试了以下内容:
c = np.dot(a, b[:, :, np.newaxis]
#c.shape = (3, 59, 1)
This actually ran and gave results that looked approximately right, except that the resulting array is not 20x3. I may be able to find a way to reshape it into the array I want, but I figured that there must be an easier/cleaner/clearer built-in method that I'm missing?
这实际上运行并给出了看起来大致正确的结果,除了结果数组不是20x3。我或许可以找到一种方法将其重塑为我想要的数组,但我认为必须有一个更容易/更清晰/更清晰的内置方法,我缺少?
2 个解决方案
#1
6
This gives (what looks to me like) the correct result:
这给了(看起来像我的样子)正确的结果:
numpy.dot(b, a.T)
Here's some example output:
这是一些示例输出:
>>> a = numpy.arange(9).reshape(3, 3)
>>> b = numpy.arange(60).reshape(20, 3)
>>> numpy.dot(b, a.T)
array([[ 5, 14, 23],
[ 14, 50, 86],
[ 23, 86, 149],
[ 32, 122, 212],
....
#2
2
import numpy
a = numpy.arange(9).reshape(3,3)
b = numpy.arange(60).reshape(20,3)
c1 = numpy.dot(b, a.T) # as in the answer of senderle
c2 = numpy.einsum('ji,ki->kj',a,b)
and the resulting c1 and c2 are both the same as what you wish (verified with your c[i] = np.dot(a, b[i])
)
并且得到的c1和c2都与你想要的一样(用c [i] = np.dot(a,b [i])验证)
the advantage of numpy.einsum
is that this trick 'ji,ki->kj'
telling what has to be done on what dimension also works for larger dimensions.
numpy.einsum的优势在于,这个技巧'ji,ki-> kj'告诉必须在什么尺寸上做什么也适用于更大尺寸。
more explanation on einsum
关于einsum的更多解释
for example, if you want to do the following operation:
例如,如果要执行以下操作:
a = numpy.arange(60.).reshape(3,4,5)
b = numpy.arange(24.).reshape(4,3,2)
d1 = numpy.zeros((5,2))
for i in range(5):
for j in range(2):
for k in range(3):
for n in range(4):
d1[i,j] += a[k,n,i] * b[n,k,j]
you can do the same thing much faster by doing:
你可以通过以下方式更快地做同样的事情:
d2 = numpy.einsum('kni,nkj->ij', a, b)
# the 'kni,nkj->ij' is what you otherwise do with the indices as in
# d1[i,j] += a[k,n,i] * b[n,k,j]
or if you do not like this way of specifying what has to happen, you can also use numpy.tensordot
instead of numpy.einsum
, and specify the axes as follows:
或者如果你不喜欢这种指定必须发生的方式,你也可以使用numpy.tensordot而不是numpy.einsum,并指定轴如下:
d3 = numpy.tensordot(a,b, axes=([1,0],[0,1]))
so this einsum method is very general and can be used to shortcut for-loops (that are otherwise slow, if you do them in python), and are very interesting for funky tensor-stuff
所以这个einsum方法非常通用,可用于快捷方式for循环(如果你在python中执行它们会很慢),并且对于时髦的张量东西非常有趣
for more info, see http://docs.scipy.org/doc/numpy/reference/generated/numpy.tensordot.html and http://docs.scipy.org/doc/numpy/reference/generated/numpy.einsum.html
有关详细信息,请参阅http://docs.scipy.org/doc/numpy/reference/generated/numpy.tensordot.html和http://docs.scipy.org/doc/numpy/reference/generated/numpy.einsum html的
#1
6
This gives (what looks to me like) the correct result:
这给了(看起来像我的样子)正确的结果:
numpy.dot(b, a.T)
Here's some example output:
这是一些示例输出:
>>> a = numpy.arange(9).reshape(3, 3)
>>> b = numpy.arange(60).reshape(20, 3)
>>> numpy.dot(b, a.T)
array([[ 5, 14, 23],
[ 14, 50, 86],
[ 23, 86, 149],
[ 32, 122, 212],
....
#2
2
import numpy
a = numpy.arange(9).reshape(3,3)
b = numpy.arange(60).reshape(20,3)
c1 = numpy.dot(b, a.T) # as in the answer of senderle
c2 = numpy.einsum('ji,ki->kj',a,b)
and the resulting c1 and c2 are both the same as what you wish (verified with your c[i] = np.dot(a, b[i])
)
并且得到的c1和c2都与你想要的一样(用c [i] = np.dot(a,b [i])验证)
the advantage of numpy.einsum
is that this trick 'ji,ki->kj'
telling what has to be done on what dimension also works for larger dimensions.
numpy.einsum的优势在于,这个技巧'ji,ki-> kj'告诉必须在什么尺寸上做什么也适用于更大尺寸。
more explanation on einsum
关于einsum的更多解释
for example, if you want to do the following operation:
例如,如果要执行以下操作:
a = numpy.arange(60.).reshape(3,4,5)
b = numpy.arange(24.).reshape(4,3,2)
d1 = numpy.zeros((5,2))
for i in range(5):
for j in range(2):
for k in range(3):
for n in range(4):
d1[i,j] += a[k,n,i] * b[n,k,j]
you can do the same thing much faster by doing:
你可以通过以下方式更快地做同样的事情:
d2 = numpy.einsum('kni,nkj->ij', a, b)
# the 'kni,nkj->ij' is what you otherwise do with the indices as in
# d1[i,j] += a[k,n,i] * b[n,k,j]
or if you do not like this way of specifying what has to happen, you can also use numpy.tensordot
instead of numpy.einsum
, and specify the axes as follows:
或者如果你不喜欢这种指定必须发生的方式,你也可以使用numpy.tensordot而不是numpy.einsum,并指定轴如下:
d3 = numpy.tensordot(a,b, axes=([1,0],[0,1]))
so this einsum method is very general and can be used to shortcut for-loops (that are otherwise slow, if you do them in python), and are very interesting for funky tensor-stuff
所以这个einsum方法非常通用,可用于快捷方式for循环(如果你在python中执行它们会很慢),并且对于时髦的张量东西非常有趣
for more info, see http://docs.scipy.org/doc/numpy/reference/generated/numpy.tensordot.html and http://docs.scipy.org/doc/numpy/reference/generated/numpy.einsum.html
有关详细信息,请参阅http://docs.scipy.org/doc/numpy/reference/generated/numpy.tensordot.html和http://docs.scipy.org/doc/numpy/reference/generated/numpy.einsum html的