Haversine公式处理大数据集时出现KeyError问题的解决方法
问题描述
我用Python实现了Haversine公式,用于根据给定坐标查找最近的地铁站。小数据集下公式运行正常,但切换到大数据集时抛出KeyError: 'lon'错误。修改代码后虽能运行,但结果不准确,现寻求适配大数据集的可行方案。
相关代码与信息
Haversine公式实现代码
def dist_between_two_lat_lon(*args): from math import asin, cos, radians, sin, sqrt lat1, lat2, long1, long2= map(radians, args) dist_lats= abs(lat2-lat1) dist_longs= abs(long2-long1) a= sin(dist_lats/2)**2+ cos(lat1) * cos(lat2) * sin(dist_longs/2)**2 c= asin(sqrt(a)) * 2 radius_earth= 6378 return c* radius_earth def find_closest_lat_lon(data, v): try: return min(data, key=lambda p: dist_between_two_lat_lon(v['lat'],p['lat'],v['lon'],p['lon'])) except TypeError: print('Not a list or not a number.')
数据集示例
ActonTown= {'lat': 51.5028, 'lon': -0.2801, 'name': 'Acton Town'} Aldgate= {'lat': 51.5143, 'lon': -0.0755, 'name': 'Aldgate'} # 更多站点数据... station_list =[ActonTown, Aldgate, ...] stationToFind= {'lat': 51.5886014, 'lon': -0.1059771} print(find_closest_lat_lon(station_list, stationToFind))
错误信息
KeyError: 'lon'
解决方案
1. 修复KeyError问题
大数据集中必然存在部分条目缺失lat或lon键(可能是数据导入错误或格式不一致),先过滤无效数据:
def find_closest_lat_lon(data, v): # 过滤缺少必要字段的无效站点 valid_stations = [station for station in data if all(k in station for k in ['lat', 'lon'])] if not valid_stations: print('无有效站点数据') return None try: return min(valid_stations, key=lambda p: dist_between_two_lat_lon(v['lat'], p['lat'], v['lon'], p['lon'])) except TypeError: print('输入不是列表或包含非数值类型') return None
2. 修正Haversine公式精度问题
之前结果不准确大概率是公式实现的细节问题,优化后的标准实现:
def dist_between_two_lat_lon(lat1, lon1, lat2, lon2): from math import radians, sin, cos, sqrt, atan2 # 直接明确传参,避免*args的歧义 lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2]) dlat = lat2 - lat1 dlon = lon2 - lon1 # 标准Haversine公式,用atan2避免近距数值精度问题 a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2 c = 2 * atan2(sqrt(a), sqrt(1 - a)) radius = 6371 # 地球平均半径(公里),比赤道半径6378更通用 return c * radius
同步修改查找函数中的调用逻辑:
return min(valid_stations, key=lambda p: dist_between_two_lat_lon(v['lat'], v['lon'], p['lat'], p['lon']))
3. 大数据集性能优化(可选)
如果数据集规模达到上万条,遍历计算会很慢。可以用scipy的KDTree做空间索引加速查询:
from scipy.spatial import KDTree import numpy as np from math import radians def find_closest_lat_lon_fast(data, v): valid_stations = [station for station in data if all(k in station for k in ['lat', 'lon'])] if not valid_stations: print('无有效站点数据') return None # 将经纬度转为弧度,构建KDTree coords = np.array([[radians(s['lat']), radians(s['lon'])] for s in valid_stations]) tree = KDTree(coords) # 查询最近点 target = np.array([radians(v['lat']), radians(v['lon'])]) _, idx = tree.query(target) return valid_stations[idx]
注意:该方法用欧氏距离近似球面距离,适合城市范围内的地铁站查询,全球范围误差较大,但速度比纯遍历快一个数量级以上。
内容的提问来源于stack exchange,提问作者Sakir Aksoy
相关产品推荐
相关产品推荐

