是否有一个 Python 模块,我可以在其中创建具有地理位置坐标(纬度和经度)的对象,并在给定坐标的 5 公里距离(即半径)内查询所有对象?
我一直在尝试将纬度和经度存储为字典中的键(因为它们是由键索引的)并使用一些距离查找算法来查询它们。但这感觉就像一个可怕的黑客攻击。
本质上类似于 PostGIS for PostgreSQL,但都在我的 Python 应用程序的内存中。
是否有一个 Python 模块,我可以在其中创建具有地理位置坐标(纬度和经度)的对象,并在给定坐标的 5 公里距离(即半径)内查询所有对象?
我一直在尝试将纬度和经度存储为字典中的键(因为它们是由键索引的)并使用一些距离查找算法来查询它们。但这感觉就像一个可怕的黑客攻击。
本质上类似于 PostGIS for PostgreSQL,但都在我的 Python 应用程序的内存中。
是的,试试geopy。
import geopy
import geopy.distance
pt1 = geopy.Point(48.853, 2.349)
pt2 = geopy.Point(52.516, 13.378)
dist = geopy.distance.distance(pt1, pt2).km
# 878.25
之后您可以查询您的点列表:
[pt for pt in points if geopy.distance.distance(orig, pt).km < 5.]
我知道这不是您的意思,但是您可以将GeoDjango与内存中的 SQLite 数据库一起使用。它是作为 Web 应用程序公开的一整套 GIS 工具,这使其成为快速开发 GIS 应用程序的瑞士军刀,尤其是对于小型即席查询。
GIS 中的常用方法是在兴趣点周围创建一个缓冲区并查询交叉点。正如@RyanDalton 建议的那样,如果您打算做很多地理定位工作,请使用Python的GIS API Shapely。即使您仍然需要空间索引(见下文),了解 Shapely 也是一件好事。以下是在 Shapely 中创建缓冲区的方法:
distance = 3
center = Point(1, 1)
pts = [Point(1.1, 1.2),Point(1.2,1.2)]
center_buf = a.buffer(distance)
#filters the points list according to whether they are contained in the list
contained = filter(center_buf.contains,pts)
如果您没有很多,您可以自己索引您的点(例如按经度)。否则,您也可以使用 Rtree 包,查看名为Using Rtree as a Cheapo spatial database的链接!
您的字典想法听起来还不错,尽管您还需要检查属于“相邻”字典键的点。
如果你找不到合适的工具,并且像编码算法一样,你可以实现一个二进制空间分区树,这 afaik 是实现类似事情的一种不那么老套的方法。
您可以使用具有Rtree扩展的 SQLite 来进行这种存储和查询。如果您的数据大于您想要使用的内存,或者您想要在程序运行之间保存和操作数据,这种方法很有用。实际的存储和查询代码在 C 中,这意味着它必须被编译,但好处是比 geopy 之类的纯 Python 解决方案具有额外的性能。pysqlite 或 APSW 都适用于 SQLite 访问。(披露:我是 APSW 的作者。)
我有一个类似的问题,似乎使用SciPy的 cKDTree 进行快速最近点查找以及GeoPy进行地理距离计算工作正常。
In [1]: import numpy as np
In [2]: from scipy.spatial import cKDTree
In [3]: from geopy import Point, distance
In [4]: points = np.random.sample((100000, 2)) * 180 - 90 # make 100k random lat-long points
In [5]: index = cKDTree(points)
In [6]: %time lat_long_dist, inds = index.query(points[234], 20)
CPU times: user 118 µs, sys: 164 µs, total: 282 µs
Wall time: 248 µs
In [7]: points_geopy = [Point(*p) for p in points]
In [8]: %time geo_dists = [distance.great_circle(points_geopy[234], points_geopy[i]) for i in inds]
CPU times: user 244 µs, sys: 218 µs, total: 462 µs
Wall time: 468 µs
In [9]: geo_dists
Out[9]:
[Distance(0.0),
Distance(29.661520907955524),
...
Distance(156.5471729956897),
Distance(144.7528417712309)]
要获得半径内的所有点,需要做一些额外的工作。
我尝试了 Shapely 的 STRtree,但性能要差得多(我安装了pip install shapely[vectorized]
)。