根据纬度/经度获取两点之间的距离

gwa*_*dze 121 python geocoding geography geo

我尝试实现这个公式:http ://andrew.hedges.name/experiments/haversine/ aplet对我测试的两个点有好处:

在此输入图像描述

但我的代码不起作用.

from math import sin, cos, sqrt, atan2

R = 6373.0

lat1 = 52.2296756
lon1 = 21.0122287
lat2 = 52.406374
lon2 = 16.9251681

dlon = lon2 - lon1
dlat = lat2 - lat1
a = (sin(dlat/2))**2 + cos(lat1) * cos(lat2) * (sin(dlon/2))**2
c = 2 * atan2(sqrt(a), sqrt(1-a))
distance = R * c

print "Result", distance
print "Should be", 278.546
Run Code Online (Sandbox Code Playgroud)

它返回的距离是5447.05546147.为什么?

Kur*_*eek 180

更新:04/2018:请注意,自GeoPy版本1.13起,Vincenty距离已弃用- 您应该使用geopy.distance.distance()代替!


上面的答案基于Haversine公式,该公式假设地球是一个球体,导致误差高达约0.5%(根据help(geopy.distance)).Vincenty距离使用更精确的椭圆体模型,如WGS-84,并在地理位置实施.例如,

import geopy.distance

coords_1 = (52.2296756, 21.0122287)
coords_2 = (52.406374, 16.9251681)

print geopy.distance.vincenty(coords_1, coords_2).km
Run Code Online (Sandbox Code Playgroud)

279.352901604使用默认椭球WGS-84 打印公里距离.(您也可以选择.miles其他几个距离单位之一).

  • 您应该在代码中使用`geopy.distance.distance(...)`,这是当前最佳(=最准确)距离公式的别名.(文森特此刻.) (3认同)
  • 在geopy-1.18.1输出中使用geopy.distance.vincenty:不推荐使用Vincenty,并将在geopy 2.0中将其删除。请改用“ geopy.distance.geodesic”(或默认的“ geopy.distance.distance”),它更准确且始终收敛。 (3认同)
  • 谢谢。您能否使用我提供的坐标而不是纽波特和克利夫兰来更新您的答案。它将为未来的读者提供更好的理解。 (2认同)
  • Newport 和 Cleveland 的任意位置来自 PyPI 列表中的示例 geopy 文档:https://pypi.python.org/pypi/geopy (2认同)
  • 我不得不修改 Kurt Peek 对此的回答:Capitalization required: `print geopy.distance.VincentyDistance(coords_1, coords_2).km 279.352901604` (2认同)
  • 弃用警告:Vincenty 已弃用,并将在 geopy 2.0 中删除。使用“geopy.distance.geodesic”(或默认的“geopy.distance.distance”)代替,它更准确并且始终收敛。#供参考 (2认同)
  • 更新geopy 2.0.0:“from geopy import distance”,然后使用“dist = distance.distance(coords_1, coords_2).km”,默认获取测地距离。 (2认同)

Mic*_*x2a 172

这是因为在Python中,所有trig函数都使用弧度,而不是度.

您可以手动将数字转换为弧度,也可以使用radians数学模块中的函数:

from math import sin, cos, sqrt, atan2, radians

# approximate radius of earth in km
R = 6373.0

lat1 = radians(52.2296756)
lon1 = radians(21.0122287)
lat2 = radians(52.406374)
lon2 = radians(16.9251681)

dlon = lon2 - lon1
dlat = lat2 - lat1

a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
c = 2 * atan2(sqrt(a), sqrt(1 - a))

distance = R * c

print("Result:", distance)
print("Should be:", 278.546, "km")
Run Code Online (Sandbox Code Playgroud)

距离现在返回正确的278.545589351km 值.

编辑:就像一个注释,如果你偶然发现这篇文章,因为你只需要一种快速简便的方法来找到两点之间的距离,我建议你使用下面Kurt答案中推荐的方法- 见他的帖子的理由.

  • 在任何编程语言中都是如此,在微积分中也是如此.使用度数是例外,仅用于人类语音. (13认同)
  • 明智的话,这个公式要求所有程度都是积极的.`radians(abs(52.123))`应该做的诀窍...... (10认同)
  • 您确定所有度数(角度?)都是正数吗?我认为这是错误的。考虑是否 lat1, lon1 = 10, 10(度)和 lat2, lon2 = -10, -10(度)。通过在度数周围添加 abs(),距离将为零,这是不正确的。也许你的意思是取 dlon 和/或 dlat 的绝对值,但是如果你看一下 a 计算中的 dlon、dlat 值,正弦是偶函数,余弦平方是偶函数,所以我不看看取 dlat 或 dlon 的绝对值有什么好处。 (4认同)

Mar*_*oma 74

对于那些通过搜索引擎来到这里并且只是寻找开箱即用的解决方案的人(像我一样),我建议安装mpu.通过pip install mpu --user它安装并像这样使用它来获得半径距离:

import mpu

# Point one
lat1 = 52.2296756
lon1 = 21.0122287

# Point two
lat2 = 52.406374
lon2 = 16.9251681

# What you were looking for
dist = mpu.haversine_distance((lat1, lon1), (lat2, lon2))
print(dist)  # gives 278.45817507541943.
Run Code Online (Sandbox Code Playgroud)

另一种方案是gpxpy.

如果您不想要依赖项,可以使用:

import math


def distance(origin, destination):
    """
    Calculate the Haversine distance.

    Parameters
    ----------
    origin : tuple of float
        (lat, long)
    destination : tuple of float
        (lat, long)

    Returns
    -------
    distance_in_km : float

    Examples
    --------
    >>> origin = (48.1372, 11.5756)  # Munich
    >>> destination = (52.5186, 13.4083)  # Berlin
    >>> round(distance(origin, destination), 1)
    504.2
    """
    lat1, lon1 = origin
    lat2, lon2 = destination
    radius = 6371  # 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


if __name__ == '__main__':
    import doctest
    doctest.testmod()
Run Code Online (Sandbox Code Playgroud)


Ram*_*usa 23

我找到了一个更简单和强大的解决方案,它使用geodesicfrom geopypackage 因为无论如何你很可能在你的项目中使用它,所以不需要额外的包安装。

这是我的解决方案:

from geopy.distance import geodesic


origin = (30.172705, 31.526725)  # (latitude, longitude) don't confuse
dist = (30.288281, 31.732326)

print(geodesic(origin, dist).meters)  # 23576.805481751613
print(geodesic(origin, dist).kilometers)  # 23.576805481751613
print(geodesic(origin, dist).miles)  # 14.64994773134371
Run Code Online (Sandbox Code Playgroud)

地理


Pat*_*mil 12

有多种方法可以根据坐标计算距离,即纬度和经度

安装和导入

from geopy import distance
from math import sin, cos, sqrt, atan2, radians
from sklearn.neighbors import DistanceMetric
import osrm
import numpy as np
Run Code Online (Sandbox Code Playgroud)

定义坐标

lat1, lon1, lat2, lon2, R = 20.9467,72.9520, 21.1702, 72.8311, 6373.0
coordinates_from = [lat1, lon1]
coordinates_to = [lat2, lon2]
Run Code Online (Sandbox Code Playgroud)

使用半正弦

dlon = radians(lon2) - radians(lon1)
dlat = radians(lat2) - radians(lat1)
    
a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
c = 2 * atan2(sqrt(a), sqrt(1 - a))
    
distance_haversine_formula = R * c
print('distance using haversine formula: ', distance_haversine_formula)
Run Code Online (Sandbox Code Playgroud)

将半正弦与 sklearn 结合使用

dist = DistanceMetric.get_metric('haversine')
    
X = [[radians(lat1), radians(lon1)], [radians(lat2), radians(lon2)]]
distance_sklearn = R * dist.pairwise(X)
print('distance using sklearn: ', np.array(distance_sklearn).item(1))
Run Code Online (Sandbox Code Playgroud)

使用 OSRM

osrm_client = osrm.Client(host='http://router.project-osrm.org')
coordinates_osrm = [[lon1, lat1], [lon2, lat2]] # note that order is lon, lat
    
osrm_response = osrm_client.route(coordinates=coordinates_osrm, overview=osrm.overview.full)
dist_osrm = osrm_response.get('routes')[0].get('distance')/1000 # in km
print('distance using OSRM: ', dist_osrm)
Run Code Online (Sandbox Code Playgroud)

使用 geopy

distance_geopy = distance.distance(coordinates_from, coordinates_to).km
print('distance using geopy: ', distance_geopy)
    
distance_geopy_great_circle = distance.great_circle(coordinates_from, coordinates_to).km 
print('distance using geopy great circle: ', distance_geopy_great_circle)
Run Code Online (Sandbox Code Playgroud)

输出

distance using haversine formula:  26.07547017310917
distance using sklearn:  27.847882224769783
distance using OSRM:  33.091699999999996
distance using geopy:  27.7528030550408
distance using geopy great circle:  27.839182219511834
Run Code Online (Sandbox Code Playgroud)


Ran*_*ara 11

您可以使用Uber 的 H3函数point_dist()来计算两个(纬度、经度)点之间的球面距离。我们可以设置返回单位(“km”、“m”或“rads”)。默认单位为公里。

例子:

import h3

coords_1 = (52.2296756, 21.0122287)
coords_2 = (52.406374, 16.9251681)
distance = h3.point_dist(coords_1, coords_2, unit='m') # To get distance in meters
Run Code Online (Sandbox Code Playgroud)

  • @PeterMortensen,我认为回答这个特定问题没有意义,因为我在差不多 9 年后回答了这个问题。我的目的是为该线程提供有价值的信息,因为当有人在 Google 上搜索“使用 Python 获取两点之间的距离”时,它会显示为顶部结果。 (3认同)

小智 7

import numpy as np


def Haversine(lat1,lon1,lat2,lon2, **kwarg):
    """
    This uses the ‘haversine’ formula to calculate the great-circle distance between two points – that is, 
    the shortest distance over the earth’s surface – giving an ‘as-the-crow-flies’ distance between the points 
    (ignoring any hills they fly over, of course!).
    Haversine
    formula:    a = sin²(??/2) + cos ?1 ? cos ?2 ? sin²(??/2)
    c = 2 ? atan2( ?a, ?(1?a) )
    d = R ? c
    where   ? is latitude, ? is longitude, R is earth’s radius (mean radius = 6,371km);
    note that angles need to be in radians to pass to trig functions!
    """
    R = 6371.0088
    lat1,lon1,lat2,lon2 = map(np.radians, [lat1,lon1,lat2,lon2])

    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.arctan2(a**0.5, (1-a)**0.5)
    d = R * c
    return round(d,4)
Run Code Online (Sandbox Code Playgroud)