【问题标题】:Efficient manipulation of a list of cartesian coordinates in PythonPython中笛卡尔坐标列表的有效操作
【发布时间】:2013-08-19 22:52:16
【问题描述】:

背景:

我正在编写一个程序来处理与各种规则形状的顶点网络相关的大量数据。我有一个工作生成器,它根据一系列用户输入参数生成与所述形状的顶点相对应的笛卡尔坐标列表。然后将数据传递给过滤器,过滤器清除重复条目、对数据进行排序和各种其他功能,从那里将清理后的数据馈送到画布模块,该模块循环并绘制顶点。

问题:

我需要实现一个有效循环坐标的新过滤器,将每一对与其他每一对进行比较,即(x1,y1)->(x2,y2)(x1,y1)->(xn,yn)(x2,y2)->@对于所有条目,987654328@ 到 (x2,y2)->(xn,yn) 等,例如,如果 (x1,y1)(x5,y5) 之间的关系适合 [(x5-x1)^2+(y5-y1)^2]=vertex_spacing^2,那么这两组坐标然后与它们各自的列表配对条目号并附加到一个新列表中,其中一个条目的形式为:例如[(x1,y1), (x5,y5), 0, 4]。实现这一目标的最有效方法是什么?

我的尝试:

我在此处和各种指南中查看了很多处理列表的方法。我尝试过嵌套的“for”和“if”循环,但发现虽然这种方法可以工作,但它会导致运行时间过长,并试图将问题分解为许多较小的 for 循环。

补充说明:

这样做的最终目的是将生成的坐标用于前端界面元素,并根据需要进行保存和导入。 [(x1,y1), (x5,y5), 0, 4] 中的列表位置 0 和 4 的作用是使界面能够对坐标进行分组,以供以后在画布对象中使用。该方法应该能够处理潜在的数千个坐标。

提前感谢您的帮助,我当然愿意改进我提供的措辞/信息和/或添加示例代码,如果不清楚我的要求是什么 - 我还是新手到这个! :)

【问题讨论】:

  • 恭喜您提出了一个很好的问题!问题是天真的方法(将每一对与所有其他对进行比较)会导致二次运行时间。你的积分分布如何?如果它们都在一个相对较小的空间中(很小的顺序是vertex_spacing),这将是一个难题,否则您可以做一些简单的优化(我将根据分布将它们作为答案发布)。
  • 谢谢! :) 我注意到情况确实如此,并且我知道它会发生,尽管我想不出解决这个问题的方法。 vertex_spacing 本身的值默认设置为 60,但由于它是用户定义的,理论上它可以是任何大小。数据也是使用 vertex_spacing 基于倍数和三角恒等式计算的。本质上,vertex_spacing 是我数据中的基本单位。希望我能理解你的意思,谢谢你的帮助!
  • 这是个好问题。我在想一个决策树是要走的路,我查看了维基百科条目中的“最近的点对问题”,因为这似乎是该问题的扩展(?)对于背景,它看起来像一个好的决策树可以得到你 O (n log n)。在这种情况下是真的吗? en.wikipedia.org/wiki/Closest_pair_of_points_problem
  • "我有一个工作生成器,它根据一系列用户输入参数生成与所述形状的顶点相对应的笛卡尔坐标列表" 听起来你是生成这些形状 - 您是否可以只存储有关哪些顶点是边缘邻居的数据?而不是以后计算?只是一个想法。
  • @erewok a kd-tree 在分区谓词中可能更有用。

标签: python algorithm list python-2.7 coordinates


【解决方案1】:

你基本上检查的是:

对于每个顶点v,找到所有顶点u,使得uv周围的半径vertex_spacing的圆上。

如果你的点分布不是所有点都靠得很近,我想了两种加快搜索速度的方法:

  1. 加快此过程的最简单方法是按 x 坐标对点进行排序。这样,您可以跳过许多比较。举个简单的例子,假设 x 坐标是 [1, 2, 10, 15, 18, 20, 21]vertex_spacing = 5。您只需将第一个顶点与第二个顶点进行比较,因为所有其他顶点显然都在第一个顶点周围的圆之外。

    请注意,如果所有点都靠得很近,这种方法是没有用的。也就是说,如果vertex_spacing = 25,则不能跳过任何比较。

  2. 同样,您可以使用二维k-d tree。这等效于排序方法,但在两个维度上。给定一个顶点(x, y)vertex_spacing = v,您必须检查([x-v, x+v], [y-v, y+v]) 范围内的所有点。使用与之前相同的示例,假设第一个点的坐标为(1, 0),第二个点的坐标为(2, 10),则无需将第一个顶点与任何东西进行比较。

这两种方法都是启发式的,在最坏情况下的运行时间上没有任何改进(恰恰相反:你也有排序/构建 kd 树的开销),但如果顶点通常至少是 vertex_space除此之外,这可以大大加快您的搜索速度。

【讨论】:

    【解决方案2】:

    我太慢了,无法击败 Heuster 对算法的描述,但这里有一个按 x 坐标排序方法的实现:

    def pairs(coords, vertex_spacing):
        results = []
        vsquared = vertex_spacing * vertex_spacing
        coords = sorted(coords)
        for ia, (xa, ya) in enumerate(coords):
            for ib, (xb, yb) in enumerate(coords[ia:]):
                dx = xb - xa
                if dx > vertex_spacing:
                    break
                dy = yb - ya
                if dx * dx + dy * dy == vsquared:
                    results.append([(xa, ya), (xb, yb), ia, ia + ib])
        return results
    

    ...它正在行动:

    >>> coords = list((x, y) for x in range(100) for y in range(100))
    >>> p = pairs(coords, 5)
    >>> from random import choice
    >>> choice(p)
    [(93, 36), (96, 40), 9336, 9640]
    >>> choice(p)
    [(9, 57), (13, 54), 957, 1354]
    >>> choice(p)
    [(46, 69), (46, 74), 4669, 4674]
    

    在我的机器上,pairs(coords, 5) 需要 1.5 秒来检查 10,000 个坐标对(检查 2,500 个坐标对需要 0.15 秒)。

    编辑:我忘记将 ia 添加到 ib 以补偿对切片的枚举 - 现在已修复。

    【讨论】:

    • +1 我的 Python 能力不够强,无法编写代码 ;-)
    • @Heuster 发布后,我就开始写类似的东西,但这似乎已经死了,所以我会批量复制它,我只是在确认它之前完成改编它回答了,但谢谢你们俩!
    • @MarkyD43 请注意我刚刚所做的修复 :-)
    • 这太棒了,谢谢!我想将两者都标记为已回答,但@Heuster 的回答对于任何有类似问题的人来说都是一个很好的通用解决方案,我会接受。再次感谢您!
    • 感谢您构建算法。我最初的想法是以相同的方式在两个 for 循环中使用 enumerate 以便将一个点与 rest 点进行比较,但我无法弄清楚算法的其余部分是如何工作的。再次感谢您花时间写出来。
    【解决方案3】:

    算法中最慢的部分是分别处理 xy 坐标以及斜边计算。这两个都可以通过使用 Python 的原生复数类型来加速:

    >>> from itertools import starmap
    >>> parray = list(starmap(complex, [(5, 1), (8.5, 3), (3.75, 4.25)]))
    >>> a = parray[0]
    >>> b = parray[1]
    >>> a
    (5+1j)
    >>> b
    (8.5+3j)
    >>> a-b
    (-3.5-2j)
    >>> abs(a-b)
    4.031128874149275
    

    【讨论】:

      【解决方案4】:

      加快速度的一种方法是使用某种空间索引,以便排除明显相距甚远的搜索点。这是一个可能有用的模块:http://toblerity.org/rtree/。另见http://en.wikipedia.org/wiki/R-tree

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-04-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多