【发布时间】:2014-10-02 12:43:03
【问题描述】:
考虑一个维度为 NxM 的 numpy 数组 A。目标是计算欧几里得距离矩阵 D,其中每个元素 D[i,j] 是行 i 和 j 之间的欧几里得距离。最快的方法是什么?这不完全是我需要解决的问题,但它是我正在尝试做的一个很好的例子(通常,可以使用其他距离度量)。
这是迄今为止我能想到的最快的:
n = A.shape[0]
D = np.empty((n,n))
for i in range(n):
D[i] = np.sqrt(np.square(A-A[i]).sum(1))
但这是最快的方法吗?我主要关心for循环。我们可以用 Cython 来打败它吗?
为了避免循环,我尝试使用广播,并执行以下操作:
D = np.sqrt(np.square(A[np.newaxis,:,:]-A[:,np.newaxis,:]).sum(2))
但结果证明这是个坏主意,因为在构建维度为 NxNxM 的中间 3D 数组时存在一些开销,因此性能更差。
我试过 Cython。但是我是 Cython 的新手,所以我不知道我的尝试有多好:
def dist(np.ndarray[np.int32_t, ndim=2] A):
cdef int n = A.shape[0]
cdef np.ndarray[np.float64_t, ndim=2] dm = np.empty((n,n), dtype=np.float64)
cdef int i = 0
for i in range(n):
dm[i] = np.sqrt(np.square(A-A[i]).sum(1)).astype(np.float64)
return dm
上面的代码比 Python 的 for 循环慢一点。我对 Cython 了解不多,但我认为我至少可以达到与 for 循环 + numpy 相同的性能。我想知道如果以正确的方式完成,是否有可能实现一些显着的性能改进?或者是否有其他方法可以加快速度(不涉及并行计算)?
【问题讨论】:
-
N 和 M 有多大?在 Python 中而不是 NumPy 中执行 N 循环当然会减慢您的速度,但它并不像执行 NxM 循环那么糟糕。它真的太慢了,还是你只是为了优化它?
-
另外,为此,在 Cython 中编写一个 ufunc 可能更容易,然后将其爆破
A,而不是将整个循环放在 Cython 中。这样就不会出错了,如果没有别的…… -
There's a SciPy method specifically for performing this task,所以这可能是一个相当快的选择。
-
@user2357112,是的,刚刚尝试了 scipy,速度非常快,谢谢。但我仍然需要弄清楚如何实现这一点,因为这只是我遇到的更普遍问题的一个例子。
-
对于 Cython,如果您正在使用它,您可能希望自己进行数学运算,而不是调用 NumPy 例程。当您已经在编写编译为 C 的代码时,NumPy 向量化并没有太大帮助。
标签: python performance optimization numpy cython