在Python中高效处理笛卡尔坐标列表

时间:2013-08-17 18:04:18

标签: python algorithm list python-2.7 coordinates

背景

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

问题:

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

我的尝试:

我在这里和各种指南上看了很多处理列表的方法。我尝试嵌套'for'和'if'循环,但发现这个方法可以工作时会导致运行时间过长,并试图将问题分解成许多较小的for循环。

进一步说明:

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

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

4 个答案:

答案 0 :(得分:6)

您基本上检查的是:

  

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

如果您的积分分布不是所有积分都很接近,我想到两种加速搜索的方法:

  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),则不需要将第一个顶点与任何东西进行比较。

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

答案 1 :(得分:4)

我太慢了,无法击败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个坐标对(和0.15秒来检查2,500个坐标)。

编辑:我忘了将ia添加到ib以补偿在切片上进行枚举 - 现在已修复。

答案 2 :(得分:2)

算法中最慢的部分是单独处理 x y 坐标以及斜边计算。通过使用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

答案 3 :(得分:1)

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