Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 多个无回路的numpy点产品_Python_Loops_Numpy_Matrix - Fatal编程技术网

Python 多个无回路的numpy点产品

Python 多个无回路的numpy点产品,python,loops,numpy,matrix,Python,Loops,Numpy,Matrix,有没有可能在没有循环的情况下计算几个点积? 假设你有以下几点: a = randn(100, 3, 3) b = randn(100, 3, 3) 我想得到一个形状为(100,3,3)的数组z,这样对于所有I z[i, ...] == dot(a[i, ...], b[i, ...]) 换句话说,这验证了: for va, vb, vz in izip(a, b, z): assert (vq == dot(va, vb)).all() 简单的解决办法是: z = array([d

有没有可能在没有循环的情况下计算几个点积? 假设你有以下几点:

a = randn(100, 3, 3)
b = randn(100, 3, 3)
我想得到一个形状为(100,3,3)的数组
z
,这样对于所有
I

z[i, ...] == dot(a[i, ...], b[i, ...])
换句话说,这验证了:

for va, vb, vz in izip(a, b, z):
    assert (vq == dot(va, vb)).all()
简单的解决办法是:

z = array([dot(va, vb) for va, vb in zip(a, b)])
它使用隐式循环(列表理解+数组)


有没有更有效的方法来计算z?

此解决方案仍然使用循环,但速度更快,因为它通过使用
点的
out
arg来避免不必要的临时数组创建:

def dotloop(a,b):
    res = empty(a.shape)
    for ai,bi,resi in zip(a,b,res):
        np.dot(ai, bi, out = resi)
    return res

%timeit dotloop(a,b)
1000 loops, best of 3: 453 us per loop
%timeit array([dot(va, vb) for va, vb in zip(a, b)])
1000 loops, best of 3: 843 us per loop

np.einsum
在这里很有用。尝试运行此复制+可粘贴代码:

import numpy as np

a = np.random.randn(100, 3, 3)
b = np.random.randn(100, 3, 3)

z = np.einsum("ijk, ikl -> ijl", a, b)

z2 = np.array([ai.dot(bi) for ai, bi in zip(a, b)])

assert (z == z2).all()
einsum
是一种编译代码,运行速度非常快,甚至比
np.tensordot
还要快(这里并不完全适用,但通常是适用的)。以下是一些统计数据:

In [8]: %timeit z = np.einsum("ijk, ikl -> ijl", a, b)
10000 loops, best of 3: 105 us per loop


In [9]: %timeit z2 = np.array([ai.dot(bi) for ai, bi in zip(a, b)])
1000 loops, best of 3: 1.06 ms per loop

尝试用numpy进行爱因斯坦求和:

z = np.einsum('...ij,...jk->...ik', a, b)
它很优雅,不需要按照您的要求编写循环。 它使我的系统速度提高了4.8倍:

%timeit z = array([dot(va, vb) for va, vb in zip(a, b)])
1000 loops, best of 3: 454 µs per loop

%timeit z = np.einsum('...ij,...jk->...ik', a, b)
10000 loops, best of 3: 94.6 µs per loop

除了其他答案外,我想补充一点:

np.einsum("ijk, ijk -> ij", a, b)
适用于我遇到的一个相关案例,其中有两个3D数组,由2D向量(点或方向)的匹配2D字段组成。这将在这些2D向量之间提供一种“元素”点积

例如:

np.einsum("ijk, ijk -> ij", [[[1,2],[3,4]]], [[[5,6],[7,8]]])
# => array([[17, 53]])
其中:

np.dot([1,2],[5,6])
# => 17
np.dot([3,4],[7,8])
# => 53

在Python3.5中,它将是
a@b
(除非此后情况发生了变化)。不幸的是,
dot
不是这样工作的。我不知道为什么。tensordot在这里非常适用;简单地在轴上收缩=[[2],[1]]。虽然我怀疑einsum会更快,考虑到大量的小宫缩。我相信tensordot更适合大尺寸的收缩。Eelco,使用这些轴求和不会得到与einsum相同的结果。
np。tensordot
会做一种外积,将
a
中的每个矩阵与
b
中的每个矩阵相乘,从而产生两个大小为100的轴。理想的结果是它的对角线,因此
np.tensordot
计算的系数太多。