Edit: Just as a note, if you just need a quick and easy way of finding the distance between two points, I strongly recommend using the approach described in Kurt’s answer below instead of re-implementing Haversine — see his post for rationale.
This answer focuses just on answering the specific bug OP ran into.
It’s because in Python, all the trig functions use radians, not degrees.
You can either convert the numbers manually to radians, or use the radians function from the math module:
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")
The distance is now returning the correct value of 278.545589351 km.
Update: 04/2018: Note that Vincenty distance is deprecated since GeoPy version 1.13 – you should use geopy.distance.distance() instead!
The answers above are based on the Haversine formula, which assumes the earth is a sphere, which results in errors of up to about 0.5% (according to help(geopy.distance)). Vincenty distance uses more accurate ellipsoidal models such as WGS-84, and is implemented in geopy. For example,
will print the distance of 279.352901604 kilometers using the default ellipsoid WGS-84. (You can also choose .miles or one of several other distance units).
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.
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()
另一个替代软件包是 [haversine][1]
from haversine import haversine,Unit
lyon =(45.7597,4.8422)# (lat, lon)
paris =(48.8567,2.3508)
haversine(lyon, paris)>>392.2172595594006# in kilometers
haversine(lyon, paris, unit=Unit.MILES)>>243.71201856934454# in miles# you can also use the string abbreviation for units:
haversine(lyon, paris, unit='mi')>>243.71201856934454# in miles
haversine(lyon, paris, unit=Unit.NAUTICAL_MILES)>>211.78037755311516# in nautical miles
他们声称对两个向量中所有点之间的距离进行了性能优化
from haversine import haversine_vector,Unit
lyon =(45.7597,4.8422)# (lat, lon)
paris =(48.8567,2.3508)
new_york =(40.7033962,-74.2351462)
haversine_vector([lyon, lyon],[paris, new_york],Unit.KILOMETERS)>> array([392.21725956,6163.43638211])
For people (like me) coming here via search engine and just looking for a solution which works out of the box, I recommend installing mpu. Install it via pip install mpu --user and use it like this to get the haversine distance:
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.
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()
The other alternative package is [haversine][1]
from haversine import haversine, Unit
lyon = (45.7597, 4.8422) # (lat, lon)
paris = (48.8567, 2.3508)
haversine(lyon, paris)
>> 392.2172595594006 # in kilometers
haversine(lyon, paris, unit=Unit.MILES)
>> 243.71201856934454 # in miles
# you can also use the string abbreviation for units:
haversine(lyon, paris, unit='mi')
>> 243.71201856934454 # in miles
haversine(lyon, paris, unit=Unit.NAUTICAL_MILES)
>> 211.78037755311516 # in nautical miles
They claim to have performance optimization for distances between all points in two vectors
from haversine import haversine_vector, Unit
lyon = (45.7597, 4.8422) # (lat, lon)
paris = (48.8567, 2.3508)
new_york = (40.7033962, -74.2351462)
haversine_vector([lyon, lyon], [paris, new_york], Unit.KILOMETERS)
>> array([ 392.21725956, 6163.43638211])
I arrived at a much simpler and robust solution which is using geodesic from geopy package since you’ll be highly likely using it in your project anyways so no extra package installation needed.
import numpy as np
defHaversine(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)
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)