如何用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
相关产品推荐
相关产品推荐

