计算 Python 中两个大列表的每个元素的距离

Posted

技术标签:

【中文标题】计算 Python 中两个大列表的每个元素的距离【英文标题】:Compute distance for each element of two big lists in Python 【发布时间】:2015-06-22 13:32:58 【问题描述】:

我有两个大的元组列表(大小 > 5000),其中包含如下坐标:

l1 = [ (33.5779, -111.925),
 (33.5738, -111.906),
 (33.5556, -111.899),
...
 (33.5646, -111.915),
 (33.5733, -111.863)]

l2 = [ (33.4318, -111.938),
 (33.5228, -111.9),
 (33.5387, -111.885),
...
 (33.5264, -111.925),
 (33.538, -111.888)]

我想找出符合以下条件的组合:

distance <= arbitraryDistance

距离是:

 from geopy.distance import great_circle
 great_circle((longitude1,latitude1), (longitude2,latitude2))

最快的方法是什么?

【问题讨论】:

为了澄清您的问题,您想从列表一中选择一个点,从列表二中选择一个点,使得它们的距离小于或等于某个值? 正是,我想找到这两个点之间的距离小于或等于“arbitraryDistance”的点的所有组合 我要在这里链接这个;我相信这将是解决您的答案的最快方法 - 并且肯定比将每个元素与另一个元素进行比较更快。由于我并没有真正提供代码 sn-ps,而是为您指明正确的方向,因此我将把它留在 cmets 中。 en.wikipedia.org/wiki/Sweep_line_algorithm 我没有找到这个扫描线算法的任何好的实现,这看起来很复杂,我的时间也很有限,但感谢你的想法:) 【参考方案1】:

我找到的一个相对较快的解决方案是使用来自 scipy.spatial.distance 的函数cdist

它计算两个列表中每个点组合之间的欧几里得距离。即使它不计算以米为单位的距离,但以度为单位,我仍然可以将我的米要求转换为度数。

所以我目前的解决方案是这样的:

from scipy.spatial.distance import cdist
l1 = [ (33.5779, -111.925),
 (33.5738, -111.906),
 (33.5556, -111.899),
...
 (33.5646, -111.915),
 (33.5733, -111.863)]

l2 = [ (33.4318, -111.938),
 (33.5228, -111.9),
 (33.5387, -111.885),
...
 (33.5264, -111.925),
 (33.538, -111.888)]

distanceRequired = 0.02 #arbitrary number in degrees

matrixOfDistances = cdist(l1,l2)
for index1,value1 in enumerate(matrixOfDistances):
  isABusinessOpportunity = True
  for index2,value2 in enumerate(value1):
    if value2 <= distanceRequired:
      isABusinessOpportunity = False
        break

  if isABusinessOpportunity:
    print "The combination is:" + str(index1) + str(index2)

【讨论】:

【参考方案2】:

我认为列表理解在这里会很好用

Result = []
Result = [great_circle(x,y) for x in l1 for y in l2 if great_circle(x,y) <= ArbitraryDist]

print(Result)

试试这个

【讨论】:

此解决方案有效,但速度很慢。比较两个约 5000 个项目的列表可能需要 30 秒,这对我来说太长了【参考方案3】:

你的回答有两个意思,我都会回答。

您想要列表一中的元素 1 和列表二中的元素 2 的距离:

我会使用Geopandas 来完成此操作,它是Shapely 和pandas 的混搭。 Shapely 很像 geopy,而 pandas 是一个用于进行矢量化计算的数学库。您的问题非常适合矢量化,因此您可以获得一些非常好的加速。

Shapely 中两点之间的距离可以这样计算:

from shapely.geometry import Point

Point(1,1).distance(Point(4,3))
3.605551275463989

从两个列表中创建两个 GeoSeries,其中 x、y 的每个元组都应该是一个 Shapely Point。

然后您可以使用本机 GeoSeries.distance 方法,该方法采用您的另一个 GeoSeries 并返回距离列表。

from geopandas import GeoSeries

s1 = GeoSeries([Point(1,1), Point(2,1)])
s2 = GeoSeries([Point(4,3), Point(2,5)])

s1.distance(s2)
0    3.605551
1    4.000000
dtype: float64

有了这个GeoSeries的距离,你可以简单地说

gs_dist = s1.distance(s2)
mask = gs_dist < 4

您将收到True / False 的列表,其中匹配条件。

您可以使用此蒙版切入您的 GeoSeries,如下所示:

s1[mask]
0    POINT (1 1)
dtype: object

或者你想要两个列表中每个元素和所有元素之间的距离

由于两个包含 5000 个对象的列表的组合往往会在内存中爆炸,因此您可能需要使用生成器。

itertools 有一个很好的组合生成器。

使用itertools.izip 以生成器的方式获取所有元素的所有可能对:

for pair in itertools.izip(l1, l2):
   point1, point2 = pair
   distance = point1.distance(point2)

【讨论】:

我无法使用 pip 安装 geopandas(安装过程中出现许多错误),所以我无法尝试此解决方案:/ pip install geopandas [...] 命令 python setup.py egg_info failed with error code 1 in /tmp/pip_build_michael/rtree 完整代码:pastebin.com/PhANgM15 您的 pastebin 的第二行显示它已经安装,但是是旧的 beta 版本。使用 --upgrade 非常感谢,我能够安装 geopandas :) 但是当我运行 gs1.distance(gs2) 时,我得到一个“AttributeError: 'Point' object has no attribute 'distance'”。 pastebin.com/482kF9mq我的 GeoSeries 有什么问题吗? 看来我混淆了 geopy 和 shapely。我更新了我的答案,希望它仍然有用。

以上是关于计算 Python 中两个大列表的每个元素的距离的主要内容,如果未能解决你的问题,请参考以下文章

【python】求数组中两个元素的最小距离?

使用python中的内置函数查找3d距离

如何计算两个 ZIP 之间的距离?

我有一个列表,我想计算列表中每个项目与列表中所有其他项目的平均距离

列表内列表之间的欧几里得距离

Python:使用两列计算两点坐标之间的距离