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

如何用Pandas计算房屋坐标到学校的最短距离并优化效率?

房屋到最近学校的最短距离计算

问题说明

现有两个Pandas DataFrame,分别存储学校和房屋的坐标(纬度、经度),需要给房屋DataFrame新增一列,记录该房屋到任意学校的最短距离。原尝试代码存在变量未定义、逻辑错误等问题,无法得到正确结果。

原代码问题点

  • 未定义变量t和private,实际应对应houses和schools的坐标行
  • 逻辑错误:代码试图筛选大于x=0的距离,而非取最小距离
  • 语法错误:minimum_distance.append(v).km是无效操作,v已经是计算好的公里数
  • 错误地将结果赋值给schools的列,实际应赋值给houses

解决方案

方法1:修正双重循环(小数据量适用)

修复循环逻辑,遍历每个房屋,计算其到所有学校的距离后取最小值:

import pandas as pd
import geopy.distance

# 初始化数据
schools = pd.DataFrame([(29.775803, -95.56353), (40.060276, -83.004196), (40.70592, -74.010765)], columns=['lat', 'lon'])
houses = pd.DataFrame([(41.291989997, -73.087632372), (41.16741635, -73.188437585), (41.038689564, -73.635282641), (40.825542, -96.60775)], columns=['lat', 'lon'])

minimum_distances = []
# 遍历每个房屋坐标
for house_coord in houses.itertuples(index=False):
    # 计算该房屋到所有学校的距离
    distances = [geopy.distance.geodesic(house_coord, school_coord).km for school_coord in schools.itertuples(index=False)]
    # 取最小距离存入列表
    minimum_distances.append(min(distances))

# 将结果添加到houses的新列中
houses['shortest_distance'] = minimum_distances
print(houses)

运行后会得到预期结果:

lat        lon  shortest_distance
0  41.291990 -73.087632         101.332983
1  41.167416 -73.188438          86.153595
2  41.038690 -73.635283          48.656830
3  40.825542 -96.607750        1156.075739

方法2:向量化/空间索引计算(大数据量高效)

当两个DataFrame各有20000行时,双重循环的时间复杂度为O(M*N)(4亿次计算),速度极慢。以下是两种优化方案:

方案A:用Scipy+Haversine公式(快速球面距离计算)

利用Numpy向量化运算加速,避免循环:

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

def haversine(latlon1, latlon2):
    # 转换坐标为弧度
    lat1, lon1 = np.radians(latlon1)
    lat2, lon2 = np.radians(latlon2)
    
    # 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))
    return c * 6371  # 地球平均半径(公里)

# 提取坐标数组
school_coords = schools[['lat', 'lon']].values
house_coords = houses[['lat', 'lon']].values

# 计算所有房屋到所有学校的距离矩阵
distance_matrix = cdist(house_coords, school_coords, metric=haversine)

# 取每行最小值(每个房屋到最近学校的距离)
houses['shortest_distance'] = distance_matrix.min(axis=1)

方案B:用Geopandas空间索引(大规模地理数据最优)

通过R-tree空间索引快速定位最近邻,大幅减少计算量:

import geopandas as gpd
from shapely.geometry import Point
import geopy.distance

# 转换为GeoDataFrame
schools_gdf = gpd.GeoDataFrame(schools, geometry=gpd.points_from_xy(schools.lon, schools.lat))
houses_gdf = gpd.GeoDataFrame(houses, geometry=gpd.points_from_xy(houses.lon, houses.lat))

# 创建学校的空间索引
sindex = schools_gdf.sindex

# 定义函数:查找单个房屋的最近学校距离
def get_nearest_dist(row):
    # 空间索引快速筛选候选学校
    possible_matches_idx = list(sindex.nearest((row.geometry.x, row.geometry.y), 1))
    possible_matches = schools_gdf.iloc[possible_matches_idx]
    # 计算精确距离并取最小值
    nearest_idx = possible_matches.distance(row.geometry).idxmin()
    return geopy.distance.geodesic((row.lat, row.lon), (schools_gdf.loc[nearest_idx, 'lat'], schools_gdf.loc[nearest_idx, 'lon'])).km

# 批量计算所有房屋的最短距离
houses_gdf['shortest_distance'] = houses_gdf.apply(get_nearest_dist, axis=1)

大数据量(20000行)效率分析

  • 双重循环:4亿次计算,单线程下需几十分钟,完全不可用
  • Scipy向量化:利用Numpy并行运算,时间压缩到几分钟,比循环快几十倍
  • Geopandas空间索引:将最近邻查找复杂度降到O(logN),总时间控制在几秒到十几秒,是大规模地理数据的最优选择

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 20:01:13