使用 python 使用 haversine 公式对 gps 数据进行下采样

downsampling gps data using haversine formula using python

我有一个高频率的 gps 数据,我想每 50 米进行一次下采样,即保持 gps 纬度和经度每 50 米并丢弃中间点。我在互联网上找到了一个 python 代码,它基本上可以计算两点之间的距离。但我不确定如何基本上从 csv 中读取纬度和经度值并将其输入函数并计算距离。如果距离达到 50 米,我只需保存该 gps 坐标。到目前为止,我有以下 python 代码

from math import radians, cos, sin, asin, sqrt
def haversine(lon1, lat1, lon2, lat2):
    lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])

    # haversine formula 
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a)) 
    r = 6371 # Radius of earth in kilometers. Use 3956 for miles
    return c * r

x1 = 52.19421607 
x2 = 52.20000327 
y1 = -1.484984011 
y2 = -1.48533465
result = haversine(x1,y1,x2,y2)    #need to give input from a csv
#if result is greater than 50m , save the coordinates
print(result)   

我该如何解决这个问题?任何方向将不胜感激。

这是一个大纲和一个工作代码示例 - 我在其中做出了一些关于 keep/drop 的假设。我假设数据框已排序。

  1. 首先计算到下一个点的距离,确实对 lat/long 对使用半正弦。这部分在我的实现中并不快 - 你可以找到更快的。
  2. 使用 cumsum() 个距离来创建距离组,其中第 1 组是所有小于 50 的距离,第 2 组是 50 到 100 之间的所有距离,等等...
  3. 在每个组中,例如仅保留 first()

请注意,这大约是基于组的每 50 个单位,因此请注意,这不同于取一个点并跳到下一个最接近 50 个单位的点并重复。但为了减少数据的目的,它应该没问题。

在伦敦附近生成一些随机数据。

import numpy as np
import sklearn
import pandas as pd

LONDON =  (51.509865, -0.118092)

random_gps = np.random.random( (10000,2) ) / 25
random_gps[:,0] += np.arange(random_gps.shape[0]) / 25

random_gps[:,0] += LONDON[0]
random_gps[:,1] += LONDON[1]

gps_data = pd.DataFrame( random_gps, columns=["lat","long"] )

移位数据得到下一个点的lat/long

gps_data['next_lat'] = gps_data.lat.shift(1)
gps_data['next_long'] = gps_data.long.shift(1)

gps_data.head()

定义距离度量。这部分可以通过使用带有 numpy 的向量表达式来提高速度,所以如果速度很重要,请改变这部分。

from sklearn.neighbors import DistanceMetric

dist = DistanceMetric.get_metric('haversine')

EARTH_RADIUS = 6371.009

def haversine_distance(row):
    point_a = np.array([[row.lat, row.long]])
    point_b = np.array([[row.next_lat, row.next_long]])
    return EARTH_RADIUS * dist.pairwise(np.radians(point_a), np.radians(point_b) )[0][0]
    

并应用我们的距离函数(慢的部分,可以改进)

gps_data["distance_to_next"] = gps_data.apply( haversine_distance, axis=1)
gps_data["distance_cumsum"] = gps_data.distance_to_next.cumsum()

最后,创建组并删除。 (!) haversine 以公里为单位返回距离 - 所以在这里我错误地做了一个 50 公里而不是米的例子。

gps_data["distance_group"] = gps_data.distance_cumsum // 50

filtered = gps_data.groupby(['distance_group']).first()