You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 19:53:17