基于Haversine公式计算房屋与餐厅全量坐标配对距离的实现方案
错误原因梳理
- 循环写法错误:
ll.append(rows(float(dist)))中rows是DataFrame遍历得到的Series对象,加括号会被识别为函数调用,触发Series object is not callable报错,直接追加距离值或关联信息即可。 - apply写法错误:lambda内传入的是完整的
df1['Latitude']等Series对象而非当前行的单个经纬度值,同时axis=1被错误放在haversine的参数括号内,导致返回的是Series无法转float。 - zip写法错误:zip仅会按索引位置一一配对两个DataFrame的行,无法生成所有两两组合的笛卡尔积,所以结果数量远小于预期。
小规模数据正确实现
适合小数据量验证逻辑,直接生成笛卡尔积后调用距离函数:
import pandas as pd import math # 你的haversine函数,返回单位为km,要米的话把radius改成6371*1000即可 def haversine(lat1, lon1, lat2, lon2): radius = 6371 dlat = math.radians(lat2-lat1) dlon = math.radians(lon2-lon1) a = math.sin(dlat/2) * math.sin(dlat/2) + math.cos(math.radians(lat1)) \ * math.cos(math.radians(lat2)) * math.sin(dlon/2) * math.sin(dlon/2) c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a)) d = radius * c return d # 方法1:修正后的双重循环 ll = [] for _, rest_row in df2.iterrows(): rest_lat, rest_lon = rest_row['Latitude'], rest_row['Longitude'] for _, house_row in df1.iterrows(): house_lat, house_lon = house_row['Latitude'], house_row['Longitude'] dist = haversine(house_lat, house_lon, rest_lat, rest_lon) # 可按需存储房屋ID、餐厅ID、距离,方便后续分析 ll.append({ 'house_id': house_row.get('id', _), # 有实际ID字段替换成对应列名即可 'restaurant_id': rest_row.get('id', _), 'distance_km': dist }) result_df = pd.DataFrame(ll) # 方法2:笛卡尔积+行处理,比双重循环效率更高 # 生成所有两两组合 df1['tmp_key'] = 0 df2['tmp_key'] = 0 cross_df = pd.merge(df1, df2, on='tmp_key').drop('tmp_key', axis=1) # 逐行计算距离 cross_df['distance_km'] = cross_df.apply(lambda x: haversine(x['Latitude_x'], x['Longitude_x'], x['Latitude_y'], x['Longitude_y']), axis=1)
大规模数据(10万房屋+2480餐厅)高性能实现
10万*2480的计算量约2.48亿次,普通Python循环/逐行apply性能极低,推荐用numpy向量化计算,速度可提升百倍以上:
import numpy as np # 向量化版haversine,支持数组批量输入 def haversine_vectorized(lat1, lon1, lat2, lon2): R = 6371.0 lat1, lon1, lat2, lon2 = map(np.radians, [lat1, lon1, lat2, lon2]) dlat = lat2[:, None] - lat1 dlon = lon2[:, None] - lon1 a = np.sin(dlat/2)**2 + np.cos(lat1) * np.cos(lat2[:, None]) * np.sin(dlon/2)**2 c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1-a)) return R * c # 返回shape为(餐厅数量, 房屋数量)的数组,单位为km # 提取经纬度数组 house_lats = df1['Latitude'].values house_lons = df1['Longitude'].values rest_lats = df2['Latitude'].values rest_lons = df2['Longitude'].values # 一次性计算所有两两距离 dist_matrix = haversine_vectorized(house_lats, house_lons, rest_lats, rest_lons) # dist_matrix[i][j] 即为第i个餐厅到第j个房屋的距离
如果需要转成结构化的长表,直接reshape即可:
result_df = pd.DataFrame({ 'restaurant_idx': np.repeat(np.arange(len(df2)), len(df1)), 'house_idx': np.tile(np.arange(len(df1)), len(df2)), 'distance_km': dist_matrix.flatten() })
内容的提问来源于stack exchange,提问作者amanda
相关产品推荐
相关产品推荐

