【问题标题】:Compute distance for each element of two big lists in Python计算 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
  • 我没有找到这个扫描线算法的任何好的实现,这看起来很复杂,我的时间也很有限,但感谢你的想法:)

标签: python geolocation


【解决方案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 来完成此操作,它是Shapelypandas 的混搭。 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。我更新了我的答案,希望它仍然有用。
    猜你喜欢
    • 2021-07-09
    • 1970-01-01
    • 1970-01-01
    • 2018-09-21
    • 1970-01-01
    • 2021-05-15
    • 1970-01-01
    • 2011-12-18
    • 2020-02-06
    相关资源
    最近更新 更多