首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Python中Haversine距离的矢量化计算

Python中Haversine距离的矢量化计算
EN

Stack Overflow用户
提问于 2015-12-28 23:22:02
回答 3查看 6.3K关注 0票数 10

我试图使用哈弗森公式计算由纬度和经度确定的位置的长列表的距离矩阵,该公式采用两个坐标对的元组来生成距离:

代码语言:javascript
运行
复制
def haversine(point1, point2, miles=False):
    """ Calculate the great-circle distance bewteen two points on the Earth surface.

    :input: two 2-tuples, containing the latitude and longitude of each point
    in decimal degrees.

    Example: haversine((45.7597, 4.8422), (48.8567, 2.3508))

    :output: Returns the distance bewteen the two points.
    The default unit is kilometers. Miles can be returned
    if the ``miles`` parameter is set to True.

    """

我可以使用嵌套的for循环计算所有点之间的距离,如下所示:

代码语言:javascript
运行
复制
data.head()

   id                      coordinates
0   1   (16.3457688674, 6.30354512503)
1   2    (12.494749307, 28.6263955635)
2   3    (27.794615136, 60.0324947881)
3   4   (44.4269923769, 110.114216113)
4   5  (-69.8540884125, 87.9468778773)

使用一个简单的函数:

代码语言:javascript
运行
复制
distance = {}
def haver_loop(df):
    for i, point1 in df.iterrows():
        distance[i] = []
        for j, point2 in df.iterrows():
            distance[i].append(haversine(point1.coordinates, point2.coordinates))

    return pd.DataFrame.from_dict(distance, orient='index')

但考虑到时间的复杂性,这需要相当长的时间,我有一个更长的列表,大约要花500个点。这让我看到了向量化,我遇到了numpy.vectorize ((博士) ),但我不知道如何在这个上下文中应用它。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-12-28 23:24:28

您可以将函数作为参数提供给np.vectorize(),然后将其用作pandas.groupby.apply的参数,如下所示:

代码语言:javascript
运行
复制
haver_vec = np.vectorize(haversine, otypes=[np.int16])
distance = df.groupby('id').apply(lambda x: pd.Series(haver_vec(df.coordinates, x.coordinates)))

例如,使用以下示例数据:

代码语言:javascript
运行
复制
length = 500
df = pd.DataFrame({'id':np.arange(length), 'coordinates':tuple(zip(np.random.uniform(-90, 90, length), np.random.uniform(-180, 180, length)))})

比较500点:

代码语言:javascript
运行
复制
def haver_vect(data):
    distance = data.groupby('id').apply(lambda x: pd.Series(haver_vec(data.coordinates, x.coordinates)))
    return distance

%timeit haver_loop(df): 1 loops, best of 3: 35.5 s per loop

%timeit haver_vect(df): 1 loops, best of 3: 593 ms per loop
票数 5
EN

Stack Overflow用户

发布于 2015-12-29 18:54:51

haversine's function definition来看,它看起来相当可并行。因此,使用NumPy aka broadcasting的最好的矢量化工具之一,并用NumPy等效的ufuncs替换数学函数,这里有一个向量化的解决方案-

代码语言:javascript
运行
复制
# Get data as a Nx2 shaped NumPy array
data = np.array(df['coordinates'].tolist())

# Convert to radians
data = np.deg2rad(data)                     

# Extract col-1 and 2 as latitudes and longitudes
lat = data[:,0]                     
lng = data[:,1]         

# Elementwise differentiations for lattitudes & longitudes
diff_lat = lat[:,None] - lat
diff_lng = lng[:,None] - lng

# Finally Calculate haversine
d = np.sin(diff_lat/2)**2 + np.cos(lat[:,None])*np.cos(lat) * np.sin(diff_lng/2)**2
return 2 * 6371 * np.arcsin(np.sqrt(d))

运行时测试-

另一个np.vectorize based solution在性能改进方面表现出了比原始代码更好的前景,因此本节将比较基于广播的发布方法和该方法。

函数定义-

代码语言:javascript
运行
复制
def vectotized_based(df):
    haver_vec = np.vectorize(haversine, otypes=[np.int16])
    return df.groupby('id').apply(lambda x: pd.Series(haver_vec(df.coordinates, x.coordinates)))

def broadcasting_based(df):
    data = np.array(df['coordinates'].tolist())
    data = np.deg2rad(data)                     
    lat = data[:,0]                     
    lng = data[:,1]         
    diff_lat = lat[:,None] - lat
    diff_lng = lng[:,None] - lng
    d = np.sin(diff_lat/2)**2 + np.cos(lat[:,None])*np.cos(lat) * np.sin(diff_lng/2)**2
    return 2 * 6371 * np.arcsin(np.sqrt(d))

时间安排-

代码语言:javascript
运行
复制
In [123]: # Input
     ...: length = 500
     ...: d1 = np.random.uniform(-90, 90, length)
     ...: d2 = np.random.uniform(-180, 180, length)
     ...: coords = tuple(zip(d1, d2))
     ...: df = pd.DataFrame({'id':np.arange(length), 'coordinates':coords})
     ...: 

In [124]: %timeit vectotized_based(df)
1 loops, best of 3: 1.12 s per loop

In [125]: %timeit broadcasting_based(df)
10 loops, best of 3: 68.7 ms per loop
票数 18
EN

Stack Overflow用户

发布于 2015-12-28 23:28:23

从使用itertools.product获取所有组合开始

代码语言:javascript
运行
复制
 results= [(p1,p2,haversine(p1,p2))for p1,p2 in itertools.product(points,repeat=2)]

话虽如此,我不确定它的速度会有多快--看起来它可能是Python:加速地理比较的复制品

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34502254

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档