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

基于经纬度与迭代在Pandas中匹配最近行的问题排查

解决方案:修复Haversine距离函数并实现站点-气象数据匹配

错误原因分析

你遇到的TypeError是因为自定义的haversine函数参数格式不符合scipy.cdist的要求。cdist会将两个坐标数组的每一对点作为两个一维数组传入距离函数(比如u代表第一个点的[lat1, lon1],v代表第二个点的[lat2, lon2]),但你之前的函数可能期望接收四个单独的lat1, lon1, lat2, lon2参数,导致参数缺失报错。

步骤1:修正Haversine距离函数

重新定义适配cdist的距离函数,参数为两个一维坐标数组:

import numpy as np
from scipy.spatial.distance import cdist

def haversine(u, v):
    # u: 第一个点的[纬度, 经度], v: 第二个点的[纬度, 经度]
    lat1, lon1 = u
    lat2, lon2 = v
    # 转换为弧度(Haversine公式要求)
    lat1, lon1, lat2, lon2 = map(np.radians, [lat1, lon1, lat2, lon2])
    # 计算Haversine距离
    dlat = lat2 - lat1
    dlon = lon2 - lon1
    a = np.sin(dlat/2)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2)**2
    c = 2 * np.arcsin(np.sqrt(a))
    earth_radius_km = 6371  # 地球平均半径(公里)
    return c * earth_radius_km

步骤2:实现分组匹配逻辑

针对df1的每个num和valid_time分组,为df2的每个站点找到组内最近的气象数据行:

基础实现(基于scipy.cdist)

import pandas as pd

# 提取df2的站点经纬度数组
stations_coords = df2[['station_lat', 'station_lon']].values

def match_nearest(group):
    # 提取当前组的气象数据经纬度数组
    group_coords = group[['lat', 'lon']].values
    # 计算组内所有点与所有站点的距离矩阵
    dist_matrix = cdist(group_coords, stations_coords, metric=haversine)
    # 对每个站点,找到组内距离最小的行索引
    nearest_idx = dist_matrix.argmin(axis=0)
    # 获取最近行并关联站点信息
    nearest_rows = group.iloc[nearest_idx].reset_index(drop=True)
    return pd.concat([df2.reset_index(drop=True), nearest_rows], axis=1)

# 按num和valid_time分组处理,合并结果得到df3
df3 = df1.groupby(['num', 'valid_time'], group_keys=False).apply(match_nearest)

优化实现(大数据量场景,基于sklearn BallTree)

如果df1数据量较大,cdist的全量距离计算效率较低,可使用BallTree做空间索引加速最近邻查找:

from sklearn.neighbors import BallTree

def match_nearest_optimized(group):
    # 转换经纬度为弧度(BallTree的Haversine metric要求)
    group_coords_rad = np.radians(group[['lat', 'lon']].values)
    stations_coords_rad = np.radians(stations_coords)
    # 创建BallTree索引
    tree = BallTree(group_coords_rad, metric='haversine')
    # 查询每个站点的最近邻(k=1表示只取最近的一个)
    distances_rad, nearest_idx = tree.query(stations_coords_rad, k=1)
    # 获取最近行并关联站点信息
    nearest_rows = group.iloc[nearest_idx.flatten()].reset_index(drop=True)
    result = pd.concat([df2.reset_index(drop=True), nearest_rows], axis=1)
    # 将弧度距离转换为公里
    result['distance_km'] = distances_rad.flatten() * 6371
    return result

df3 = df1.groupby(['num', 'valid_time'], group_keys=False).apply(match_nearest_optimized)

验证结果

生成的df3会包含df2的所有站点信息,以及对应每个num和valid_time下距离该站点最近的df1气象数据行,同时可保留距离字段用于验证。

内容的提问来源于stack exchange,提问作者user2100039

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 00:47:01