如何遍历两个DataFrame并保留首个DataFrame的索引?实现经纬度最小距离计算
代码问题排查与修正实现
现有代码的核心问题
- 元组类型不支持追加操作:你初始定义
values = ()是不可变的元组,后续调用values.append()会直接触发属性错误,程序无法正常运行 - 冗余低效的嵌套逻辑:就算把
values改成可变列表,它的设计也是每轮把之前所有历史计算的距离数组都存起来,再嵌套循环遍历整个列表取最后一个数组的最小值,纯纯浪费计算资源——本来每轮算完当前点位的距离数组直接取最小值就完事,完全没必要跨轮次存所有历史数据 - 计算过程未拆分作用域:单轮的距离数组没有做隔离,很容易出现跨点位的数据混杂
对齐需求的实现流程
严格按照你设定的执行逻辑落地:
- 对df1、df2按
code_postal列做升序排序 - 逐行遍历排序后的df1,全程保留df1的原始行索引作为结果字典的键
- 对当前遍历到的df1经纬度点,一次性计算它和df2所有经纬度点的球面距离
- 取出这一组距离的最小值,存入结果字典
- 跳转处理df1的下一个经纬度对,重复上述流程
修正后的可运行代码
import numpy as np from numpy import pi, cos, asin, sqrt # 注意:默认参数引用的School_usable需在函数定义前完成赋值,否则会触发未定义错误 def calc_min_distance(df1, df2=School_usable): result = {} # 按邮编列对两个DataFrame排序 df1_sorted = df1.sort_values(by="code_postal", ascending=True) df2_sorted = df2.sort_values(by="code_postal", ascending=True) # 提前提取df2的经纬度为数组,避免循环内重复取值 lat2_all = np.array(df2_sorted["latitude"]) lon2_all = np.array(df2_sorted["longitude"]) rad_factor = pi / 180 # 角度转弧度的固定系数,提前计算减少重复运算 # 逐行遍历排序后的df1,iterrows返回的第一个值就是df1的原始行索引 for orig_idx, row in df1_sorted.iterrows(): curr_lat = row["latitude"] curr_lon = row["longitude"] # 利用numpy广播特性,一次计算当前点和df2所有点的半正矢距离 a = 0.5 - cos((lat2_all - curr_lat) * rad_factor)/2 + \ cos(curr_lat * rad_factor) * cos(lat2_all * rad_factor) * \ (1 - cos((lon2_all - curr_lon) * rad_factor)) / 2 dist_array = 12742 * asin(sqrt(a)) # 取当前点对df2所有点的最小距离,保留两位小数 min_val = round(dist_array.min(), 2) # 以df1的原始索引为键,最小距离为值存入结果 result[orig_idx] = min_val return result
实现说明
- 全程没有丢失df1的索引对应关系:
iterrows()返回的orig_idx是df1原本的行号,哪怕对表做了排序操作,索引和原始数据的对应关系也完全不会被破坏 - 计算效率大幅提升:去掉了无意义的列表累积和嵌套循环,当df2的数据量较大时,运行速度会比原实现高一个数量级以上
- 计算逻辑完全符合预期:每处理一个df1的点位,都是独立计算它到所有df2点位的距离再取最小值,不会混入其他点位的计算数据
内容的提问来源于stack exchange,提问作者Matthieu Soundly
相关产品推荐
相关产品推荐

