首页 > 解决方案 > 对haversine公式使用列表推导

问题描述

我有两个数据框。房屋位置之一和餐厅位置之一,其坐标均以纬度/经度为单位。我需要创建一个新列来计算它们之间的距离。例如,如果我有一个包含 5 个房屋位置的列表,则预期结果将是每个餐厅的 5 次距离计算(25 个值)。df1 是位置,df2 是餐厅。

我的距离计算在这里,但我确实改变了几次:

版本 1:

def distance(location, restaurant): 
    lat1, lon1 = location
    lat2, lon2 = restaurant
    radius = 6371 *1000# km
    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

版本 2:

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

我试过写一个循环,但它返回'Series object is not callable'错误:

ll = [] 
for index,rows in df2.iterrows():
        lat1 = rows['Latitude']
        lon1 = rows['Longitude']
        for i,r in df1.iterrows():
                dist = distance((lat1,lon1),(r['Latitude'],r['Longitude']))
                ll.append(rows(float(dist)))

然后我尝试使用列表推导,两种不同的方式:

df1['result'] = df1.apply(lambda x: float(haversine(df1['Latitude'], df1['Longitude'], df2['Latitude'], df2['Longitude']), axis=1)) 

第一个返回错误“无法将系列转换为 <class 'float'>

第二个没有给我我正在寻找的结果:

Dist = []
for w, x, y, z in zip(df1['Latitude'], df2['Longitude'], df2['Latitude'], df2['Longitude']):
    Dist.extend([distance((w,x),(y,z))])
print(Dist)

output: [515.38848499753, 54.26312420254462, 10.563518031233743, 374.5045129388741, 451.6737920301973]

这样做的正确方法是什么?最终,我将不得不将其扩展到 10 万间房屋和 2480 间餐厅。不幸的是,我无权共享数据。

标签: pythonpandasdataframelist-comprehensionhaversine

解决方案


您可以使用运行速度更快的矢量化操作,这是一个片段,它采用两个维度为 nX2、mX2 的数组,即保存 n 和 m 个位置

import numpy as np
from sklearn.metrics.pairwise import haversine_distances


def haversine(locations1, locations2):
    locations1 = np.deg2rad(locations1)
    locations2 = np.deg2rad(locations2)
    return haversine_distances(locations1, locations2) * 6371000

使用您的尺寸,它会在 10 秒内在我的机器上运行


推荐阅读