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

如何基于经纬度对距离合并两个25万行DataFrame(仅保留50米内配对)

实现步骤与代码

1. 数据准备与命名

先给两个DataFrame分配不同名称,避免变量覆盖,确保后续操作清晰:

import pandas as pd
import numpy as np

# 第一个DataFrame(记为df1)
latitude1 = [40.7128, 37.7749, 34.0522]
longitude1 = [-74.0060, -122.4194, -118.2437]
index1 = [1, 2, 3]
df1 = pd.DataFrame({'latitude': latitude1, 'longitude': longitude1, 'index': index1})

# 第二个DataFrame(记为df2)
latitude2 = [40.7324, 37.7569, 34.0612]
longitude2 = [-74.0070, -122.4284, -118.2507]
index2 = [1, 2, 3]
df2 = pd.DataFrame({'latitude': latitude2, 'longitude': longitude2, 'index': index2})

2. 按Index合并DataFrame

通过merge方法按index字段关联两个DataFrame,自动给右侧重复列名添加_x后缀,正好符合你需要的latitude_x、longitude_x列名:

merged_df = pd.merge(df1, df2, on='index', suffixes=('', '_x'))

3. 高效计算球面距离

使用Haversine公式的向量化实现(基于numpy),处理25万行数据时效率远高于循环或apply:

def haversine(lat1, lon1, lat2, lon2):
    # 经纬度转换为弧度
    lat1_rad = np.radians(lat1)
    lon1_rad = np.radians(lon1)
    lat2_rad = np.radians(lat2)
    lon2_rad = np.radians(lon2)
    
    # Haversine核心计算
    dlat = lat2_rad - lat1_rad
    dlon = lon2_rad - lon1_rad
    a = np.sin(dlat/2)**2 + np.cos(lat1_rad) * np.cos(lat2_rad) * np.sin(dlon/2)**2
    c = 2 * np.arcsin(np.sqrt(a))
    
    # 地球平均半径(单位:米)
    earth_radius = 6371000
    return c * earth_radius

# 批量计算距离
merged_df['distance'] = haversine(
    merged_df['latitude'], merged_df['longitude'],
    merged_df['latitude_x'], merged_df['longitude_x']
)

4. 过滤结果并保留指定列

筛选距离≤50米的记录,同时保留你需要的6列:

result_df = merged_df[merged_df['distance'] <= 50][
    ['index', 'latitude', 'longitude', 'latitude_x', 'longitude_x', 'distance']
]

补充说明

如果你的需求不是按index一对一匹配,而是要从两个DataFrame中找出所有距离≤50米的经纬度对(不限制index),直接笛卡尔积运算会产生625亿条数据,完全不可行。此时需要用空间索引优化,借助geopandas的R-tree索引实现近邻查询:

import geopandas as gpd
from shapely.geometry import Point

# 转换为GeoDataFrame
gdf1 = gpd.GeoDataFrame(df1, geometry=gpd.points_from_xy(df1.longitude, df1.latitude), crs='EPSG:4326')
gdf2 = gpd.GeoDataFrame(df2, geometry=gpd.points_from_xy(df2.longitude, df2.latitude), crs='EPSG:4326')

# 转换为米制坐标系(避免球面距离计算误差)
gdf1 = gdf1.to_crs('EPSG:3857')
gdf2 = gdf2.to_crs('EPSG:3857')

# 近邻查询,找出50米内的配对
joined = gpd.sjoin_nearest(gdf1, gdf2, max_distance=50, distance_col='distance')
# 转换回原始坐标系并整理列名
joined = joined.to_crs('EPSG:4326')
result_df = joined.rename(columns={'latitude_right': 'latitude_x', 'longitude_right': 'longitude_x'})[
    ['index_left', 'latitude', 'longitude', 'latitude_x', 'longitude_x', 'distance']
].rename(columns={'index_left': 'index'})

这种方法利用空间索引大幅减少计算量,能高效处理25万行的规模。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 16:23:16