我需要确定一组点(每个由浮点元组给出,每个都在[0,1]中)包含两个相互之间的某个阈值(例如0.01)。我还要提一下,在我感兴趣的问题版本中,这些"点"由长度为〜30的元组给出,即它们是[0,1] ^ 30中的点。
我可以使用以下内容测试任何两个是否在此阈值范围内:
def is_near(p1, p2):
return sqrt(sum((x1 - x2)**2 for x1, x2 in zip(p1, p2))) < 0.01 # Threshold.
使用此功能,我可以使用以下内容检查每一对:
def contains_near(points):
from itertools import combinations
return any(is_near(p1, p2) for p1, p2 in combinations(points, r=2))
然而,这是列表长度的二次方,这对于我所拥有的长点列表来说太慢了。
是否有解决此问题的方法?
我尝试过将这些点捕捉到网格中,以便我可以使用字典/哈希映射来存储它们:
def contains_near_hash(points):
seen = dict()
for point in points:
# The rescaling constant should be 1 / threshold.
grid_point = tuple([round(x * 100, 0) for x in point])
if grid_point in seen:
for other in seen[grid_point]:
if is_near(point, other):
return True
seen[grid_point].append(point)
else:
seen[grid_point] = [point]
return False
然而,当
时,这不起作用points = [(0.1149999,), (0.1150001,)]
因为这些圆到两个不同的网格点。我还尝试了一个版本,其中点被附加到所有相邻的网格点,但是我想要做的示例有~30个坐标,每个网格点有2 ^ 30个邻居,这使得这完全不切实际。
答案 0 :(得分:6)
一对积分只能靠近&#39;如果它们在至少一个维度上的距离小于阈值则彼此相对。这可以被利用来通过一个接一个地过滤一个维度来减少候选对的数量。
我建议:
- 在一个维度上对点进行排序(例如:x)
- 找到与排序列表中下一个点足够接近的所有点,并将其索引放入set
个候选者中
- 不要使用sqrt()
,而是使用二次距离(x1 - x2)**2
甚至abs(x1 - x2)
来提高效率
- 为第二个维度做这个
- 确定两组的相交,这些是彼此靠近的点
通过这种方式,您可以避免代价高昂的is_near()
调用,以较小的集合进行操作,仅使用唯一的点,并且设置查找非常有效。
该方案可以轻松扩展到包含2个以上的维度。