首页 > 解决方案 > 使用python使用haversine公式对gps数据进行下采样

问题描述

我有高频率的 gps 数据,我想每 50 米下采样一次,即每 50 米保持 gps 纬度和经度,并在点之间丢弃。我在互联网上找到了一个python代码,它基本上计算了两点之间的距离。但我不确定如何从 csv 中读取 lat 和 long 值并将其输入函数并计算距离。如果距离达到 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)   

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

标签: pythonpandasgpshaversinedownsampling

解决方案


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

  1. 首先计算到下一个点的距离,确实对纬度/经度对使用半正弦。这部分在我的实现中并不快——你可以找到更快。
  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"] )

移动数据以获得下一个点的纬度/经度

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()

推荐阅读