解密地球两点的距离:SQL 与 Python 联合实现 Haversine 公式计算

首先讲述一下为什么要用半正矢函数来计算,原因是因为,经纬度坐标是基于地球表面上的球面几何,而不是平面几何。直接使用平面几何公式(如欧几里得距离)计算两点间的距离,会因为地球的球面形状而产生较大的误差。球面上的两点距离是沿弧线的,而不是直线的距离。Haversine 公式通过半正矢函数计算角距离,再结合地球半径计算弧长,适应了球面的特性。

在这里插入图片描述

尽管半正矢函数(Haversine)在某些情况下已经不再是最精确的选择,但它依然适合用于计算经纬度之间的距离,尤其在以下几个方面:

1. 计算简便且效率高
Haversine公式的计算过程相对简单,公式只涉及到三角函数(正弦、余弦等)和基本的算数运算。对于大多数常规应用,计算速度非常快,尤其是当需要处理大量的地理数据时,Haversine函数能够在不增加过多计算负担的情况下提供快速的结果。

2. 足够的精度(在短距离情况下)
对于计算短距离(通常在几十公里范围内)的经纬度,Haversine公式已经足够精确。尽管它假设地球是一个完美的球体,而不是椭球体,这种假设在短距离的情况下不会引入显著误差。地球的曲率在较小范围内对结果的影响微乎其微,因此Haversine公式可以在这种情况下满足大多数应用的需求。

3. 适用于大多数常规应用
Haversine公式是大多数简单地理应用中常用的公式,特别是当计算精度要求不高时。很多场景下,比如城市范围内的导航、距离估算等,Haversine公式的精度已经足够满足需求,而其计算简便、实现容易,成为了广泛采用的标准方法。

4. 误差较小
尽管现代的算法(如Vincenty公式)提供了更高的精度,但Haversine公式在地理距离较短的情况下,误差非常小。对于短距离(几十公里以内),误差通常不会超过1公里,很多应用场景中并不需要超高精度,因此Haversine公式足够实用。

在这里插入图片描述
Haversine 公式推导

地球表面上两点的弧长距离可以用以下公式计算:
在这里插入图片描述
Φ₁和Φ₂表示两点的纬度(弧度表示)。
ΔΦ是两点纬度的差值。
Δλ是两点经度的差值。

然后使用以下公式计算弧长:
在这里插入图片描述
R 是地球半径(通常取 6371 公里)。arcsin 反正弦函数,用于将结果映射回角度值。

在 MaxCompute 上实现

MaxCompute 支持 SQL 提供了足够的函数来实现上述公式,例如 SIN、COS 和 POWER 等数学函数。
示例数据坐标取自于(链接:某德地图坐标

idlatitude1longitude1latitude2longitude2
123.108748113.45347123.120604113.448547
SELECT
  id,
  6371 * 2 * ASIN(SQRT(
    POWER(SIN((RADIANS(latitude2) - RADIANS(latitude1)) / 2), 2) +
    COS(RADIANS(latitude1)) * COS(RADIANS(latitude2)) *
    POWER(SIN((RADIANS(longitude2) - RADIANS(longitude1)) / 2), 2)
  )) AS distance_km
FROM
  locations;

结果图
在这里插入图片描述

同时用某德地图测算,计算结果准确!
在这里插入图片描述

使用 Python 实现 Haversine 公式

基于python的计算还是针对于点对点的方式,如果数据体量多建议还是使用SQL来实现,这样执行效率更为高效。

import math

def haversine(lat1, lon1, lat2, lon2):
    """
    计算两点之间的地理距离(单位:公里)
    :param lat1: 点 1 的纬度
    :param lon1: 点 1 的经度
    :param lat2: 点 2 的纬度
    :param lon2: 点 2 的经度
    :return: 距离(公里)
    """
    # 将角度转换为弧度
    lat1, lon1, lat2, lon2 = map(math.radians, [lat1, lon1, lat2, lon2])

    # Haversine 公式
    dlat = lat2 - lat1
    dlon = lon2 - lon1
    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

# 示例
point1 = (23.108748, 113.453471)
point2 = (23.120604, 113.448547)
distance = haversine(*point1, *point2)
print(f"两点之间的距离是 {distance:.2f} 公里")

输出结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KennySKwan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值