Python:确保每个成对的距离> =一些最小距离

时间:2018-07-06 16:32:36

标签: python algorithm numpy

我有一个约200,000个点的2D数组,希望“抖动”这些点,以使任何点与其最近邻点之间的距离大于或等于某个最小值。

在从头开始编写此算法之前,我想问:是否有任何规范的方法或常用的算法来实现此行为?我认为在进行此设置之前先回顾一下这些算法是很有意义的。

对于此问题,其他人可以提出的任何建议将不胜感激。

3 个答案:

答案 0 :(得分:1)

我最终使用了一种称为"Lloyd iteration"的技术来解决这个问题。算法背后的思想很简单;在一组点上运行Lloyd迭代,我们:

  1. 建立点的Voronoi图
  2. 将每个点置于Voronoi单元格的中心
  3. 重复直到点充分分开

This gist包含一些示例代码(具有可视化效果):

from lloyd import Field
from scipy.spatial import voronoi_plot_2d
import matplotlib.pyplot as plt
import numpy as np
import umap, os

def plot(vor, name, e=0.3):
  '''Plot the Voronoi map of 2D numpy array X'''
  plot = voronoi_plot_2d(vor, show_vertices=False, line_colors='y', line_alpha=0.5, point_size=5)
  plot.set_figheight(14)
  plot.set_figwidth(20)
  plt.axis([field.bb[0]-e, field.bb[1]+e, field.bb[2]-e, field.bb[3]+e])
  if not os.path.exists('plots'): os.makedirs('plots')
  if len(str(name)) < 2: name = '0' + str(name)
  plot.savefig( 'plots/' + str(name) + '.png' )

# get 1000 observations in two dimensions and plot their Voronoi map
np.random.seed(1144392507)
X = np.random.rand(1000, 4)
X = umap.UMAP().fit_transform(X)

# run 20 iterations of Lloyd's algorithm
field = Field(X)
for i in range(20):
  print(' * running iteration', i)
  plot(field.voronoi, i)
  field.relax()

结果是,点的移动就像在以下gif中一样:

enter image description here

NB:上面的gif显示不受限制的Lloyd迭代,其中输出域可能非常大。为了进行一些讨论和用Python构造约束Lloyd迭代的代码,我写了一点blog post

答案 1 :(得分:0)

您的问题与气泡图构造(examples)非常相似:将N个指定半径的球体放置在图表中,使得:

  • 它们不重叠
  • 总图表尽可能小

我在这方面知识不是很丰富,所以我无法详尽列出该问题的算法。在这篇文章中,我将介绍我唯一认识的一个,以及如何使它适应您的问题。

javascript图表库使用的一种常见方法似乎是基于物理的(例如:d3.js force clusters)。简而言之(据我了解),他们:

  1. 随机(或采用启发式)为球体赋予初始位置。
  2. 通过施加以下力来运行一个小的物理模拟,以球体为对象:
    • 引力吸引着各个领域。
    • 碰撞以分离重叠的球体。
    • “流体”摩擦:减慢具有速度的每个对象。这样可以确保仿真在某个点停止(防止出现振荡)。

这可以解决您的问题:将每个点视为直径为DD是每个点之间的最小距离)的球心。所有球体都具有相同的质量(您可以忽略质量,而直接使用加速度而不是力来工作)。

  1. 球的初始位置是输入数据。
  2. 物理:只丢弃重力,因为您不想/不需要“打包”这些点。

正如我所说,我对气泡图不是很熟悉。寻找与此主题相关的替代算法,看看它们是否适合您的情况可能很有趣。

答案 2 :(得分:0)

  1. 计算所有点之间的成对距离- sklearn.metrics.pairwise.euclidean_distances
  2. 计算所有成对距离的最小值
  3. 如果最小值足够小,请退出
  4. 计算每两个点之间的成对向量,以便它们指向 彼此
  5. 除以成对距离,因此它们是单位 向量
  6. 对于每个点,计算将其微移至多远 其他点:成对向量/成对距离平方*一些 常数(应设置力常数,以便当点在最小距离处时力很小但不是无限小)
  7. 按金额微调所有积分 在6中计算得出的结果也应将微移的上限设置为最小值/ 10,因此,如果2个点最终位于同一点,则它们不会被微距相隔无限远
  8. 重复直到最小值足够小

应在所有情况下收敛,但会根据需要扩展画布。此外,它也是内存和计算密集型的,例如200,000点,但是忽略大向量/小力的稀疏矩阵使它更易于处理。