【发布时间】:2019-02-01 11:15:44
【问题描述】:
我在 python 中有一个 numpy 数组,其中包含许多 (10k+) 个 3D 顶点(坐标为 [x,y,z] 的向量)。我需要计算所有可能的这些点对之间的距离。
使用 scipy 很容易做到:
import scipy
D = spdist.cdist(verts, verts)
但我不能使用它,因为项目策略是引入新的依赖项。
所以我想出了这个幼稚的代码:
def vert_dist(self, A, B):
return ((B[0]-A[0])**2+(B[1]-A[1])**2+(B[2]-A[2])**2)**(1.0/2)
# Pairwise distance between verts
#Use SciPy, otherwise use fallback
try:
import scipy.spatial.distance as spdist
D = spdist.cdist(verts, verts)
except ImportError:
#FIXME: This is VERY SLOW:
D = np.empty((len(verts), len(verts)), dtype=np.float64)
for i,v in enumerate(verts):
#self.app.setStatus(_("Calculating distance %d of %d (SciPy not installed => using SLOW AF fallback method)"%(i,len(verts))), True)
for j in range(i,len(verts)):
D[j][i] = D[i][j] = self.vert_dist(v,verts[j])
vert_dist() 计算两个顶点之间的 3D 距离,其余代码仅迭代 1D 数组中的顶点,并为每个顶点计算同一数组中彼此之间的距离并生成 2D 距离数组。
但是与 scipy 的原生 C 代码相比,这非常慢(1000 倍)。我想知道我是否可以使用纯 numpy 加速它。至少在某种程度上。
更多信息:https://github.com/scipy/scipy/issues/9172
顺便说一句,我尝试过 PyPy JIT 编译器,它甚至比纯 python 慢(10 倍)。
更新:我能够像这样加快速度:
def vert_dist_matrix(self, verts):
#FIXME: This is VERY SLOW:
D = np.empty((len(verts), len(verts)), dtype=np.float64)
for i,v in enumerate(verts):
D[i] = D[:,i] = np.sqrt(np.sum(np.square(verts-verts[i]), axis=1))
return D
这通过一次计算整行来消除内部循环,这使得事情变得相当快,但仍然明显比 scipy 慢。所以我还是看@Divakar 的解决方案
【问题讨论】:
-
您在寻找这样的东西吗? stackoverflow.com/a/51352819/4909087
-
这个答案在讨论性能时也很有趣:stackoverflow.com/a/37903795/8069403
-
@coldspeed 我已经看过这篇文章,但我不清楚如何修改它以进行
((B[0]-A[0])**2+(B[1]-A[1])**2+(B[2]-A[2])**2)**(1.0/2)计算,而不仅仅是减法。 -
@xdze2 我试过这个,但它只替换了
vert_dist()函数,这已经足够快了。当我将((B[0]-A[0])**2+(B[1]-A[1])**2+(B[2]-A[2])**2)**(1.0/2)替换为np.sqrt(np.sum(np.square(B-A)))时,它的可读性更高,但它仍然没有消除 2D for 循环,这是这段代码的实际缓慢部分。
标签: python numpy multidimensional-array scipy vertex