scipy 如何有效地找到两个非常大的3D坐标数组中的点的最小距离值?

jk9hmnmh  于 2023-08-05  发布在  其他
关注(0)|答案(4)|浏览(119)

假设我们有两个3D坐标点数组。
A =(1000000,3),浮点型,B =(100000,3),浮点型
对于A中的每个坐标,我想找到到B中任何坐标的最小欧氏距离。这意味着它应该计算A[0]与所有B之间的欧氏距离,然后取最小值。
我写了代码来使用循环来完成这一点。它工作,但由于我的数组的大小,它需要一个多小时才能完成。伪代码看起来像这样:

minDistances = np.zeros(A.shape)
for i in range(len(A)):
  queriedPoint = A[i]
  distances = B - queriedPoint
  euclideanDistances = np.linalg.norm(distances, axis=1)
  minDistance = np.min(euclideanDistances)
  minDistances[i] = minDistance

字符串
理想情况下,我希望将其向量化,但这样做似乎会使我的程序因RAM使用而崩溃。对于如何更有效地做到这一点,有什么想法或提示吗?我在想,也许我可以把这个问题简化成更简单的问题,或者重新思考如何一起解决它。谢谢你,谢谢

pjngdqdw

pjngdqdw1#

最快的方法可能是使用scipy.spatial.KDTreeproposed duplicate建议使用scipy.spatial.distance.cdist,但您的数组太大,会占用太多内存。

import numpy as np
from scipy.spatial import KDTree

rng = np.random.default_rng(42)
A = rng.uniform(low=-100, high=100, size=(1_000_000, 3))
B = rng.uniform(low=-100, high=100, size=(100_000, 3))

tree = KDTree(B)
distances = tree.query(A)[0]

字符串
我不知道AB的实际取值范围,所以我只使用了(-100, 100)。这需要大约2.2秒的时间来运行。

iyzzxitl

iyzzxitl2#

蛮力将需要NxN距离计算。
更简单的方法是使用“桶”,即使用一些特殊的盒子。
构建盒子需要大约4N次计算。例如,第一遍确定每个数组的最大和最小X,Y,Z坐标。然后你把“空间”分成比如4x4x4=64个盒子,用于array_1,另外64个盒子用于array_2。
通过简单的顶点比较,您可以得到两个更接近的框(每个数组一个)。是的,这是蛮力,但数据量很小。
注意:如果盒子相交或有多个接近的对,那么你需要一个候选列表,更多的盒子,但仍然不是初始的大数据。
然后在数组上运行new pass。仅获取位于方框列表中的那些点。
最后,你可以运行一个蛮力与选定的点。
对于最小的情况,array_1的大多数框与array_2的一些框相交(或距离相同),然后只需将每个框分割成八个较小的框并再次检查。最坏的情况可能是(但很少)最坏的情况,即使用阵列的蛮力。

yrefmtwq

yrefmtwq3#

如果两个数组都是完全随机的数字,那么可能就没什么可做的了。如果每个数组对应于例如车辆轨迹,那么您应该查看Hausdorff距离和Fréchet度量。

r7knjye2

r7knjye24#

是的,所以最好的办法就是把问题分成子问题,分而治之的算法;)所以给出了上面的伪代码,我们可以尝试利用dict & list理解来尝试它

import numpy as np
A = np.random.rand(1000000,3)
B = np.random.rand(1000000,3)

minDistance = {i: np.linalg.norm(B-A[i],axis=1).min() for i in range(len(A))}
minDistance = [minDistance[i] for i in range(len(A))]

print(minDistance)

字符串
通过使用dict和list理解,它们有助于优化时间和复杂性。希望能帮上忙
或者,您可以尝试基于循环的方法

import numpy as np
from scipy.spatial.distance import cdist

A = np.random.rand(1000000,3)
B = np.random.rand(1000000,3)

minDist = np.zeros(len(A))

for i, coord in enumerate(A):
    distances = cdist(np.expand_dims(coord,axis=0),B)
    minDist[i] = np.min(distances)
print(minDist)

相关问题