基于点间距高效精简GPS轨迹点数量的技术方案求助
高效精简GPS轨迹DataFrame方法
问题背景
现有包含车辆GPS坐标的DataFrame,字段为Timestamp、Latitude、Longitude。采样间隔在1秒到30秒之间,由GPS接收器逻辑(含速度因素)决定,间隔不稳定。低速行驶或静止时轨迹会包含数千个GPS点,数据量冗余,需要精简:仅保留与上一个保留点间距至少50米的点,两点间距离采用Haversine公式计算。
数据示例
| Timestamp | Latitude | Longitude |
|---|---|---|
| 0 days 00:00:00 | 51.1513 | 9.61053 |
| 0 days 00:00:28 | 51.1513 | 9.61049 |
| 0 days 00:00:29 | 51.1513 | 9.61048 |
| 0 days 00:00:31 | 51.1513 | 9.61048 |
| 0 days 00:00:33 | 51.1513 | 9.61048 |
Haversine距离计算实现
标量版本
from math import radians, cos, sin, asin, sqrt def haversine(lat1, lon1, lat2, lon2): """ 计算地球上两点间的大圆距离(单位:米) 参数为十进制度数格式的经纬度 """ # 转换为弧度 lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2]) # Haversine公式 dlon = lon2 - lon1 dlat = lat2 - lat1 a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2 c = 2 * asin(sqrt(a)) # 地球半径取6371000米 return 6371000 * c
向量化版本
适用于批量计算相邻点的距离:
import numpy as np def haversine_vec(df): data = np.deg2rad(df[['Latitude', 'Longitude']]) diff = data.shift() - data d = np.sin(diff['Latitude']/2)**2 + np.cos(data['Latitude'])*np.cos(data['Latitude'].shift()) * np.sin(diff['Longitude']/2)**2 return 2 * 6371000 * np.arcsin(np.sqrt(d))
现有低效方法
当前采用纯Python遍历标记的方式,效率极低,不适用于大型数据集:
import numpy as np def reduce_gps(df): mask = np.full(len(df), False) cpos = 0 lat_col = df.columns.get_loc('Latitude') lon_col = df.columns.get_loc('Longitude') for pos in range(len(mask)): if haversine(df.iloc[cpos, lat_col], df.iloc[cpos, lon_col], df.iloc[pos, lat_col], df.iloc[pos, lon_col]) > 50 or (pos==len(mask)-1): cpos = pos mask[pos] = True return df[mask]
高效解决方案
使用Numba的JIT编译加速循环逻辑,将Python循环转换为机器码,处理大型数据集速度提升显著:
import numpy as np import pandas as pd from math import radians, cos, sin, asin, sqrt from numba import jit @jit(nopython=True) def haversine_numba(lat1, lon1, lat2, lon2): """Numba加速的Haversine距离计算""" lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2]) dlon = lon2 - lon1 dlat = lat2 - lat1 a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2 c = 2 * asin(sqrt(a)) return 6371000 * c @jit(nopython=True) def reduce_gps_numba(lats, lons, threshold=50): """Numba加速的轨迹精简逻辑""" n = len(lats) mask = np.zeros(n, dtype=np.bool_) mask[0] = True # 保留第一个点 last_keep_idx = 0 for i in range(1, n): dist = haversine_numba(lats[last_keep_idx], lons[last_keep_idx], lats[i], lons[i]) # 满足距离阈值或最后一个点时标记保留 if dist > threshold or i == n-1: mask[i] = True last_keep_idx = i return mask def reduce_gps(df, threshold=50): """对外调用的精简函数""" lats = df['Latitude'].values lons = df['Longitude'].values mask = reduce_gps_numba(lats, lons, threshold) return df[mask]
使用方式
读取样本数据后,直接调用函数即可:
df = pd.read_csv('样本数据路径') reduced_df = reduce_gps(df)
内容的提问来源于stack exchange,提问作者aem
相关产品推荐
相关产品推荐

