根据经纬度在一个json列表中找到最近的位置

4

给定一个JSON文件,

{"BusStopCode": "00481", "RoadName": "Woodlands Rd", "Description": "BT PANJANG TEMP BUS PK", "Latitude": 1.383764, "Longitude": 103.7583},
{"BusStopCode": "01012", "RoadName": "Victoria St", "Description": "Hotel Grand Pacific", "Latitude": 1.29684825487647, "Longitude": 103.85253591654006}

在众多的公交站中,我试图根据这个包含5000个公交站的列表以及任何用户给定的经纬度使用给定的公式找到最近的公交站。

import math
R = 6371000 #radius of the Earth in m
x = (lon2 - lon1) * cos(0.5*(lat2+lat1)) 
y = (lat2 - lat1) 
d = R * sqrt( x*x + y*y ) 

我的问题是,针对用户输入的lat1和lon1,如何计算lat1 lon1与所有5000个json文件中的lat2 lon2之间的所有距离,并打印出最低的5个距离?我考虑使用list.sort,但不确定如何使用python计算所有5000个距离。非常感谢。
编辑:
根据Eric Duminil的代码,以下代码适用于我的需求。
from math import cos, sqrt
import sys
import json
busstops = json.loads(open("stops.json").read())
R = 6371000 #radius of the Earth in m 
def distance(lon1, lat1, lon2, lat2): 
  x = (lon2-lon1) * cos(0.5*(lat2+lat1)) 
  y = (lat2-lat1) 
  return R * sqrt( x*x + y*y )
buslist = sorted(busstops, key= lambda d: distance(d["Longitude"], d["Latitude"], 103.5, 1.2))
print(buslist[:5])

输入的经度和纬度示例为 103.5, 1.2,来自 buslist。


只需查看 https://pypi.python.org/pypi/geopy。您可能会找到某种方法。还要检查此评论 https://dev59.com/sGIk5IYBdhLWcg3wTcYr#19412565 - Manoj Jadhav
谢谢提供链接。然而,我不关心如何计算两个经纬度之间的距离,而是想知道如何在一个包含5000个公交站点的JSON文件中,找到距离用户给定的经纬度最近的5个公交站点。 - Joey Ngo
抱歉如果我的问题没有表达清楚。 - Joey Ngo
2个回答

3

您可以定义一个函数来计算距离,并使用它来通过 key 参数对公交车站进行排序:

from math import cos, sqrt, pi

R = 6371000 #radius of the Earth in m
def distance(lon1, lat1, lon2, lat2):
    x = (lon2 - lon1) * cos(0.5*(lat2+lat1))
    y = (lat2 - lat1)
    return (2*pi*R/360) * sqrt( x*x + y*y )

bustops = [{"BusStopCode": "00481", "RoadName": "Woodlands Rd", "Description": "BT PANJANG TEMP BUS PK", "Latitude": 1.383764, "Longitude": 103.7583},
{"BusStopCode": "01012", "RoadName": "Victoria St", "Description": "Hotel Grand Pacific", "Latitude": 1.29684825487647, "Longitude": 103.85253591654006}]

print(sorted(bustops, key= lambda d: distance(d["Longitude"], d["Latitude"], 103.5, 1.2)))
# [{'BusStopCode': '01012', 'RoadName': 'Victoria St', 'Description': 'Hotel Grand Pacific', 'Latitude': 1.29684825487647, 'Longitude': 103.85253591654006}, {'BusStopCode': '00481', 'RoadName': 'Woodlands Rd', 'Description': 'BT PANJANG TEMP BUS PK', 'Latitude': 1.383764, 'Longitude': 103.7583}]

一旦这个列表被排序,你只需要用[:5]提取出最近的五个公交车站。

即使有5000个公交车站,它也应该足够快了。

请注意,如果你不关心具体的距离而只想对公交车站进行排序,你可以使用这个函数作为键:

def distance2(lon1, lat1, lon2, lat2):
    x = (lon2 - lon1) * cos(0.5*(lat2+lat1))
    y = (lat2 - lat1)
    return x*x + y*y

谢谢,这正是我所需要的。然而,当我尝试使用[:5]时,出现了以下错误:“NoneType”对象不可订阅。 - Joey Ngo
已经修改了代码并且运行正常(请参考问题帖子)。 - Joey Ngo

1
我曾为类似的项目做过同样的事情,但计算大型数据集的所有距离可能需要很长时间。
最终我使用了knn 最近邻居,它速度更快,而且你不需要一直重新计算距离:
import numpy as np
from sklearn.neighbors import NearestNeighbors

buslist = [{ ...., 'latitude':45.5, 'longitude':7.6}, { ...., 'latitude':48.532, 'longitude':7.451}]

buslist_coords = np.array([[x['latitude'], x['longitude']] for x in buslist]) #extracting x,y coordinates

# training the knn with the xy coordinates
knn = NearestNeighbors(n_neighbors=num_connections)
knn.fit(buslist_coords)
distances, indices = knn.kneighbors(xy_coordinates)
# you can pickle these and load them later to determinate the nearest point to an user


# finding the nearest point for a given coordinate
userlocation = [47.456, 6.25]
userlocation = np.array([[userlocation[0], userlocation[1]]])
distances, indices = knn.kneighbors(userlocation)

# get the 5 nearest stations in a list
nearest_stations = buslist[indices[0][:5]] # the order of the buslist must be the same when training the knn and finding the nearest point

# printing the 5 nearest stations
for station in nearest_stations :
    print(station)

在此之后,我使用networkx构建了一个图形,但仍然使用knn.kneighbors(userlocation)来查找用户最近的点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接