用于将网格放置在无序点集上的算法

时间:2011-09-21 22:52:23

标签: python algorithm vector bioinformatics cartesian

给定一组大的(数万到数百万)无序点表示为3D笛卡尔向量,用于制作包含所有点的常规方形网格(用户定义的间距)的好算法是什么?一些约束:

  1. 网格必须是正方形和常规
  2. 我需要能够调整网格间距(其中一个方格的边长),理想情况下是单个变量
  3. 我想要一个最小尺寸的网格,即网格中的每个“块”应至少包含一个无序点,每个无序点都应包含在“块”中
  4. 算法的返回值应该是网格点的坐标列表
  5. 为了在2D中进行说明,给出了这一点:

    set of points

    对于某些网格间距X,算法的一个可能的返回值是这些红点的坐标(虚线仅用于说明目的):

    grid spacing x

    对于网格间距X / 2,算法的一个可能的返回值是这些红点的坐标(虚线仅用于说明目的):

    grid spacing x/2

    对于任何有兴趣的人来说,我正在使用的无序点是大蛋白分子的原子坐标,就像你可以从.pdb文件中得到的那样。

    Python是解决方案的首选,尽管伪代码也很好。

    编辑:我认为我对所需内容的第一次描述可能有点模糊,所以我添加了一些约束和图像以澄清事情。

6 个答案:

答案 0 :(得分:4)

我建议你制作k-d tree。它快速,简单,易于实现:

k-d tree

维基百科代码:

class Node: pass

def kdtree(point_list, depth=0):
    if not point_list:
        return

    # Select axis based on depth so that axis cycles through all valid values
    k = len(point_list[0]) # assumes all points have the same dimension
    axis = depth % k

    # Sort point list and choose median as pivot element
    point_list.sort(key=lambda point: point[axis])
    median = len(point_list) // 2 # choose median

    # Create node and construct subtrees
    node = Node()
    node.location = point_list[median]
    node.left_child = kdtree(point_list[:median], depth + 1)
    node.right_child = kdtree(point_list[median + 1:], depth + 1)
    return node

但是,您必须稍微修改它,以适应您的约束。

答案 1 :(得分:2)

Voronoi Diagram怎么样?它可以使用Fortunes algorithmO(n log n)中生成。

我不知道它是否解决了你的问题,但Voronoi Diagrams非常“自然”。它们在本质上非常普遍。

示例(来自维基百科):

enter image description here

答案 2 :(得分:2)

因为您要求使用用户指定间距的常规方格,所以听起来似乎是一种相当简单的方法。

首先通过数据来计算每个维度中的最小和最大坐标。计算出覆盖最大值和最小值之间距离所需的用户指定间距的步数。

再次通过数据,将每个点分配到网格中的单元格,使用每个坐标最小点和指定间距的网格(例如X_cell = Math.floor((x_i - x_min) /间距))。使用字典或数组记录每个单元格中的点数。

现在打印出细胞的坐标,其中至少有一个点。

你确实有一些我没有尝试优化的自由:除非最小坐标和最大坐标之间的距离是网格间距的精确倍数,否则会有一些允许你滑动网格的斜率它包含所有点:此时网格从最低点的位置开始,但它可能在最高点之前结束,因此您有足够的空间在每个维度上向下移动一点。当你这样做时,一些点将从一个单元移动到另一个单元,并且被占用的单元的数量将改变。

如果您一次只考虑一个维度的移动,您可以合理有效地计算出会发生什么。计算每个点与其单元格维度中的最大坐标之间的维度距离,然后对这些值进行排序。当您向下移动网格时,距离最大坐标最小的点将首先交换单元格,您可以按排序顺序逐个遍历这些点。如果您在执行此操作时更新单元格中的点数,则可以确定哪个位移最小化了已占用单元格的数量。

当然,您需要担心三个方面。您可以逐个处理它们,直到您减少单元格数量。这是当地的最低要求,但可能不是全球最低要求。寻找其他局部最小值的一种方法是从随机选择的起点重新开始。

答案 3 :(得分:1)

找到包含所有点的最小面积平方。将每个方块重复细分为4个子方块(因此从1到4到16到64到......)。在其中一个方块变空之前停止。不难证明得到的网格最多是最佳解决方案的四倍(关键洞察力:保证空方格至少包含任意网格中的一个方格至少两倍)。

可能通过引入随机翻译可以减少常量。

答案 4 :(得分:1)

我有2D网格聚类的经验,并在C#代码中实现了一个例子。 http://kunuk.wordpress.com/2011/09/15/clustering-grid-cluster/

这可以处理步骤处理步骤1,2和4。 您必须修改代码并将其更新为3D空间。希望这会给你一些想法。

代码在O(m * n)中运行,其中m是网格数,n是点数。

答案 5 :(得分:0)

如果您希望网格单元格为正方形且常规,则很可能需要Octree。如果您可以放宽正方形和常规约束,则可以制作k-d-tree