【发布时间】:2015-02-11 22:08:13
【问题描述】:
我正在研究如何在 python3 中尽可能高效地计算形式的双倍和内的点积:
import cmath
for j in range(0,N):
for k in range(0,N):
sum_p += cmath.exp(-1j * sum(a*b for a,b in zip(x, [l - m for l, m in zip(r_p[j], r_p[k])])))
其中 r_np 是一个包含数千个三元组的数组,而 x 是一个常数三元组。长度为N=1000 三元组的时间约为2.4s。同样使用numpy:
import numpy as np
for j in range(0,N):
for k in range(0,N):
sum_np = np.add(sum_np, np.exp(-1j * np.inner(x_np,(r_np[j] - r_np[k]))))
实际上速度较慢,运行时间约为4.0s。我认为这是由于没有大的矢量化优势,只有短的 3 点 3 是 np.dot,它被循环中的 N^2 吃掉了。
但是,通过使用带有 map 和 mul 的普通 python3,我可以获得对第一个示例的适度加速:
from operator import mul
for j in range(0,N):
for k in range(0,N):
sum_p += cmath.exp(-1j * sum(map(mul,x, [l - m for l, m in zip(r_p[j], r_p[k])])))
运行时间约为2.0s
尝试使用 if 条件不计算 case j=k,其中
r_np[j] - r_np[k] = 0
因此点积也变为0,或者将总和分成两部分以达到相同的效果
for j in range(0,N):
for k in range(j+1,N):
...
for k in range(0,N):
for j in range(k+1,N):
...
两者都让它变得更慢。所以整个事情的比例为 O(N^2),我想知道是否有一些方法,如排序或其他东西,可以摆脱循环并使其按 O(N logN) 进行缩放。
问题是我需要一组 N~6000 三元组的个位数秒运行时,因为我有数千个这样的总和要计算。否则我必须尝试 scipy 的 weave、numba、pyrex 或 python,或者完全走 C 路径……
提前感谢您的帮助!
编辑:
这就是数据样本的样子:
# numpy arrays
x_np = np.array([0,0,1], dtype=np.float64)
N=1000
xy = np.multiply(np.subtract(np.random.rand(N,2),0.5),8)
z = np.linspace(0,40,N).reshape(N,1)
r_np = np.hstack((xy,z))
# in python format
x = (0,0,1)
r_p = r_np.tolist()
【问题讨论】:
-
您能否将您的测试数据放到一个代码块中,以便我们使用它来测试自己?
-
x是否总是等于(0, 0, 1)? -
对于给定的金额,是的。但是,这就是为什么我最终必须为不同的
x计算其中许多总和的原因@ -
对不起,我应该更清楚。如果
x == (0, 0, 1)在计算中您实际上只使用了r_np的第三列,那么只索引第三列而不是计算所有3 的成对差异会节省一些时间,例如r_np[:, None, 2] - r_np[None, :, 2]而不是r_np[:, None, :] - r_np[None, :, :]。x中的一个元素是否总是为 1 而另外两个为 0? -
我明白了,对于三个主轴,其实是这样的。是的,对于
(x,0,0); (0,x,0) and (0,0,x)案例,将三元组减少到一个是有意义的。 IVlad 通过预先计算点积,然后只对 1-dim 数字求和,已经用他的代码做到了这一点。但我也需要一些混合的(x1,x2,x3)案例,在 IVlad 代码中是相同的。
标签: algorithm python-3.x numpy sum dot-product