计算两组矢量numpy之间的交叉乘积的有效方法

时间:2018-04-17 14:58:51

标签: python numpy

我每组都有两组2000个3D矢量,我需要计算每个可能的一对之间的交叉积。我目前这样做

for tx in tangents_x:
    for ty in tangents_y:
         cross = np.cross(tx, ty)
         (... do something with the cross variable...)

这很有效,但速度很慢。有没有办法让它更快?

如果我对元素产品感兴趣,我可以执行以下操作

# Define initial vectors
tx = np.array([np.random.randn(3) for i in range(2000)])
ty = np.array([np.random.randn(3) for i in range(2000)])
# Store them into matrices
X = np.array([tx for i in range(2000)])
Y = np.array([ty for i in range(2000)]).T
# Compute the element-wise product
ew = X * Y
# Use the element_wise product as usual
for i,tx in enumerate(tangents_x):
    for j,ty in enumerate(tangents_y):
        (... use the element wise product of tx and ty as ew[i,j])

如何将其应用于跨产品而非元素方式?或者,你看到另一种选择吗?

非常感谢:)

5 个答案:

答案 0 :(得分:5)

与许多numpy函数cross支持广播一样,您可以这样做:

np.cross(tangents_x[:, None, :], tangents_y)

或 - 更详细但可能更容易阅读

np.cross(tangents_x[:, None, :], tangents_y[None, :, :])

这会将tangents_xtangents_y重塑为形状2000, 1, 31, 2000, 3。根据广播规则,这将被解释为两个形状2000, 2000, 3阵列,其中tangents_x沿轴1重复,tangents_y沿轴0重复。

答案 1 :(得分:4)

只需写出来并编译它

import numpy as np
import numba as nb

@nb.njit(fastmath=True,parallel=True)
def calc_cros(vec_1,vec_2):
    res=np.empty((vec_1.shape[0],vec_2.shape[0],3),dtype=vec_1.dtype)
    for i in nb.prange(vec_1.shape[0]):
        for j in range(vec_2.shape[0]):
            res[i,j,0]=vec_1[i,1] * vec_2[j,2] - vec_1[i,2] * vec_2[j,1]
            res[i,j,1]=vec_1[i,2] * vec_2[j,0] - vec_1[i,0] * vec_2[j,2]
            res[i,j,2]=vec_1[i,0] * vec_2[j,1] - vec_1[i,1] * vec_2[j,0]

    return res

<强>性能

#create data
tx = np.random.rand(3000,3)
ty = np.random.rand(3000,3)
#don't measure compilation overhead
comb=calc_cros(tx,ty)

t1=time.time()
comb=calc_cros(tx,ty)
print(time.time()-t1)

This gives 0.08s for the two (3000,3) matrices.

答案 2 :(得分:2)

np.dot几乎总是会更快。因此,您可以将其中一个向量转换为matrix

def skew(x):
    return np.array([[0, -x[2], x[1]],
                     [x[2], 0, -x[0]],
                     [-x[1], x[0], 0]])

在我的机器上运行得更快:

tx = np.array([np.random.randn(3) for i in range(100)])
ty = np.array([np.random.randn(3) for i in range(100)])

tt=time.clock()
for x in tx:
    for y in ty:
         cross = np.cross(x, y)
print(time.clock()-tt)

0.207秒

tt=time.clock()
for x in tx:
    m=skew(x)
    for y in ty:
         cross = np.dot(m, y)
print(time.clock()-tt)

0.015秒

此结果可能因计算机而异。

答案 3 :(得分:1)

您可以使用np.meshgrid()构建组合矩阵,然后分解交叉产品。剩下的就是用轴等摆弄:

# build two lists of 5 3D vecotrs as example values:
a_list = np.random.randint(0, 10, (5, 3))
b_list = np.random.randint(0, 10, (5, 3))

# here the original approach using slow list comprehensions:
slow = np.array([[ np.cross(a, b) for a in a_list ] for b in b_list ])

# now the faster proposed version:
g = np.array([ np.meshgrid(a_list[:,i], b_list[:,i]) for i in range(3) ])
fast = np.array([ g[1,0] * g[2,1] - g[2,0] * g[1,1],
                  g[2,0] * g[0,1] - g[0,0] * g[2,1],
                  g[0,0] * g[1,1] - g[1,0] * g[0,1] ]).transpose(1, 2, 0)

我用10000×10000元素测试了这个(而不是上面例子中的5×5),快速版需要6.4秒。对于500个元素,慢速版已经花了27秒。

对于2000×2000元素,快速版本在我的电脑上需要0.23秒。对你来说够快吗?

答案 4 :(得分:0)

使用笛卡尔积来获得所有可能的对

import itertools as it
all_pairs = it.product(tx, ty)

然后使用map遍历所有对并计算交叉乘积:

map(lambda x: np.cross(x[0], x[1]), all_pairs)