【发布时间】:2015-06-25 03:19:05
【问题描述】:
看起来显式计算向量数组的叉积比使用np.cross 快得多。我已经尝试过矢量优先和矢量最后,它似乎没有什么区别,尽管这是在类似question 的回答中提出的。是我用错了,还是变慢了?
在笔记本电脑上,每个交叉产品的显式计算似乎需要大约 60ns。这〜大致〜尽可能快吗?在这种情况下,似乎没有任何理由去 Cython 或 PyPy 或写一个特殊的ufunc。
我也看到了使用 einsum 的参考资料,但我不太了解如何使用它,并且怀疑它不会更快。
a = np.random.random(size=300000).reshape(100000,3) # vector last
b = np.random.random(size=300000).reshape(100000,3)
c, d = a.swapaxes(0, 1), b.swapaxes(0, 1) # vector first
def npcross_vlast(): return np.cross(a, b)
def npcross_vfirst(): return np.cross(c, d, axisa=0, axisb=0)
def npcross_vfirst_axisc(): return np.cross(c, d, axisa=0, axisb=0, axisc=0)
def explicitcross_vlast():
e = np.zeros_like(a)
e[:,0] = a[:,1]*b[:,2] - a[:,2]*b[:,1]
e[:,1] = a[:,2]*b[:,0] - a[:,0]*b[:,2]
e[:,2] = a[:,0]*b[:,1] - a[:,1]*b[:,0]
return e
def explicitcross_vfirst():
e = np.zeros_like(c)
e[0,:] = c[1,:]*d[2,:] - c[2,:]*d[1,:]
e[1,:] = c[2,:]*d[0,:] - c[0,:]*d[2,:]
e[2,:] = c[0,:]*d[1,:] - c[1,:]*d[0,:]
return e
print "explicit"
print timeit.timeit(explicitcross_vlast, number=10)
print timeit.timeit(explicitcross_vfirst, number=10)
print "np.cross"
print timeit.timeit(npcross_vlast, number=10)
print timeit.timeit(npcross_vfirst, number=10)
print timeit.timeit(npcross_vfirst_axisc, number=10)
print all([npcross_vlast()[7,i] == npcross_vfirst()[7,i] ==
npcross_vfirst_axisc()[i,7] == explicitcross_vlast()[7,i] ==
explicitcross_vfirst()[i,7] for i in range(3)]) # check one
explicit
0.0582590103149
0.0560920238495
np.cross
0.399816989899
0.412983894348
0.411231040955
True
【问题讨论】:
-
查看
np.cross的代码。它正在做你正在做的事情,加上一些处理大小为 2 的情况的掩护,以及一些轴交换,因此它可以使用像a[1]*b[2] - a[2]*b[1]这样的表达式。只要对大维度进行矢量化处理,在小维度(大小 3)上执行一些显式步骤就不会影响您的速度。 -
(其中一个)我的问题是:为什么 np.cross 几乎慢了 10 倍,与大小或顺序无关?
-
正如@Jaime 暗示的那样,更新
numpy可能会解决这个问题。我在1.9.2看到非常相似的时间。 -
swapaxes对速度没有任何帮助,因为内存布局仍然相同。如果从一开始就以这种方式生成数组,vfirst会稍微快一些。
标签: python-2.7 numpy numpy-ufunc