计算 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 中两个大列表的每个元素的距离的主要内容,如果未能解决你的问题,请参考以下文章