使用Numpy和Pandas计算经纬度之间的距离
在数据分析中,经纬度信息在不同的场景中都起到了关键的作用,如地理位置数据、旅游业、物流等。因此,经纬度之间的距离计算也成为了一个非常实用的功能,Numpy和Pandas是两个Python中非常流行的数据处理库,本文主要介绍使用Numpy和Pandas计算经纬度之间的距离。
阅读更多:Numpy 教程
经纬度换算公式
经纬度距离的计算是基于地球为一个近似椭圆体,我们可以利用经纬度换算公式来计算两点地理位置的距离。
- 海伦公式(Haversine Formula):
海伦公式用于计算大圆线上两点之间的距离,是最为经典和常用的计算方式。该公式是由16世纪的航海家约翰·海伦提出的,用于航海中计算船航行的距离。
公式如下:
d=2r\arcsin\sqrt{\sin^2\frac{\varphi_2-\varphi_1}{2}+\cos\varphi_1\cos\varphi_2\sin^2\frac{\lambda_2-\lambda_1}{2}}
其中,r为地球半径(单位为千米),\varphi_1,\lambda_1,\varphi_2,\lambda_2分别表示两点的经度和纬度。
Python代码实现:
import math
def haversine(lon1, lat1, lon2, lat2):
"""
Calculate the great circle distance between two points
on the earth (specified in decimal degrees)
"""
# 将十进制转为弧度
lon1, lat1, lon2, lat2 = map(math.radians, [lon1, lat1, lon2, lat2])
# haversine公式
dlon = lon2 - lon1
dlat = lat2 - lat1
a = math.sin(dlat/2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon/2)**2
c = 2 * math.asin(math.sqrt(a))
r = 6371 # 地球平均半径,单位为公里
return c*r
- vicenty公式(适用于近距离):
Vicenty公式是一种更为精确的公式,适用于计算两点之间的精确距离,实际上是近似于解析方法。由于不涉及任何开方等不能被唯一解析解决的表达式,因此该公式是非常高效的。
公式如下:
d = a\tan \bigg(\dfrac{\sqrt{\cos ^2b_2\sin ^2(\lambda_2 – \lambda_1) + [\cos b_1\sin b_2 – \sin b_1\cos b_2 \cos (\lambda_2-\lambda_1)]^2}}{\sin b_1\sin b_2 + \cos b_1\cos b_2\cos(\lambda_2-\lambda_1)}\bigg)
其中,a为长轴,b为短轴,一般使用WGS-84椭球体,b_1,\lambda_1,b_2,\lambda_2分别表示两点的经度和纬度。
Python代码实现:
def vicenty(lon1, lat1, lon2, lat2):
'''
Calculate the geodesic distance (in meters)
between any two points on the Earth's surface
'''
from math import atan2, cos, sin, sqrt, pi
# WGS-84 ellipsoid parameters
a = 6378137.0
b = 6356752.3142
f = (a - b) /a # flattening
L = abs(lon2 - lon1)
if L > pi:
L = 2*pi - L
U1 = atan2(b, a*sin(lat1))
U2 = atan2(b, a*sin(lat2))
sinU1 = sin(U1)
cosU1 = cos(U1)
sinU2 = sin(U2)
cosU2 = cos(U2)
lamb = L
iterlimit = 100
while iterlimit > 0:
sinlamb = sin(lamb)
coslamb = cos(lamb)
sinSigma = sqrt((cosU2*sinlamb)**2 +
(cosU1*sinU2 - sinU1*cosU2*coslamb)**2)
if sinSigma == 0:
return 0 # co-incident points
cosSigma = sinU1*sinU2 + cosU1*cosU2*coslamb
sigma = atan2(sinSigma, cosSigma)
alpha = asin(cosU1*cosU2*sinlamb / sinSigma)
cosSqAlpha = cos(alpha)**2
cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha
C = f*cosSqAlpha*(4 + f*(4 - 3*cosSqAlpha))/16
lambPrev = lamb
lamb = L + (1 - C)*f*sin(alpha)*(sigma +
C*sinSigma*(cos2SigmaM +
C*cosSigma*(-1 + 2*cos2SigmaM**2)))
iterlimit -= 1
if iterlimit == 0:
return 0 # formula failed to converge
uSq = cosSqAlpha*(a**2 - b**2)/b**2
A = 1 + uSq/16384*(4096 + uSq*(-768 + uSq*(320 - 175*uSq)))
B = uSq/1024 * (256 + uSq*(-128 + uSq*(74 - 47*uSq)))
deltaSigma = B*sinSigma*(cos2SigmaM + B/4 *
(cosSigma*(-1 + 2*cos2SigmaM**2) - B/6*cos2SigmaM*(-3 + 4*sinSigma**2)*
(-3 + 4*cos2SigmaM**2)))
s = b*A*(sigma - deltaSigma)
return s
Numpy和Pandas实现
- Numpy实现
我们可以利用Numpy对计算海伦公式的函数进行封装,从而可以更加方便的进行实现,在进行计算前,先将经纬度转换为弧度制。
Python代码实现:
import numpy as np
def distance_numpy(lon1, lat1, lon2, lat2):
"""
Compute the distance between successive rows using numpy
Use the Haversine formula to compute the distance between each pair of (lat, long) points.
"""
R = 6371 # Earth radius in km
lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2])
dlon = lon2 - lon1
dlat = lat2 - lat1
a = np.sin(dlat/2)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2)**2
c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1-a))
distance = R * c
return distance
- Pandas实现
Pandas是另一个非常流行的Python数据处理库,它提供了DataFrame和Series等高效的数据结构和操作,可以方便地处理大量数据。Pandas提供了apply函数,可以利用其进行距离计算。
Python代码实现:
import pandas as pd
def distance_pandas(df):
"""
Compute the distance between successive rows using pandas
"""
R = 6371 # Earth radius in km
dlat = df['latitude'].shift(-1) - df['latitude']
dlon = df['longitude'].shift(-1) - df['longitude']
a = pd.np.sin(dlat/2)**2 + pd.np.cos(df['latitude']) * pd.np.cos(df['latitude'].shift(-1)) * pd.np.sin(dlon/2)**2
c = 2 * pd.np.arctan2(pd.np.sqrt(a), pd.np.sqrt(1-a))
distance = R * c
return distance
总结
本文介绍了Numpy和Pandas两个Python数据处理库的经纬度计算方法,我们可以根据需要选择相应的方法来计算两个经纬度之间的距离。在实际应用中,需要注意采用合适的地球椭球体模型进行计算。
极客教程