一、轨迹数据基础:从原始坐标到可用轨迹

大家好,我是老张。做轨迹处理这么多年,我见过太多人一上来就急着做可视化、搞回放,结果数据本身就有问题——漂移点满天飞,时间戳乱七八糟。说白了,轨迹数据就像盖房子的地基,地基不稳,上面再花哨也没用。

今天这一章,我们就来聊聊GPS轨迹数据到底是什么,常见的格式有哪些,以及怎么把脏数据洗干净。嗯,这些都是我踩过坑之后总结出来的经验。

1.1 什么是GPS轨迹数据?

GPS轨迹数据,简单来说就是一系列带时间戳的坐标点。你想想看,一个人拿着手机从A点走到B点,每隔几秒记录一次位置,把这些点连起来就是一条轨迹。

一个标准的轨迹点通常包含:

  • 经度(Longitude):东西方向的位置,范围-180到180
  • 纬度(Latitude):南北方向的位置,范围-90到90
  • 时间戳(Timestamp):记录这个点的时间,精确到秒甚至毫秒
  • 可选字段:海拔、速度、方向、精度等

核心要点:轨迹数据的灵魂是「时间+空间」的组合。只有坐标没有时间,那只是一堆散点,不是轨迹。

我记得有一次做物流配送分析,客户给的数据只有经纬度,没有时间戳。我问他「这辆车什么时候到的?」他说「不知道」。嗯,那这数据基本废了。所以大家一定要记住:时间戳是轨迹数据的命根子。

1.2 轨迹数据的常见格式

实际工作中,你会遇到各种各样的轨迹格式。我整理了一下,最常见的就是下面这四种:

格式 本质 适用场景 优缺点
GPX XML 户外运动、GPS设备导出 标准化好,但文件偏大
KML XML(Google Earth) 地图可视化、Google Earth 可直接在Google Earth打开,但冗余信息多
CSV 纯文本表格 数据分析、数据库导入 轻量、易处理,但缺少元数据
JSON 结构化文本 Web应用、API交互 灵活、可读性好,但体积稍大

GPX格式

GPX(GPS Exchange Format)是最通用的轨迹格式。我个人习惯用GPX做数据交换,因为它结构清晰,几乎所有轨迹软件都支持。

<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.1" creator="handheld">
  <trk>
    <name>晨跑路线</name>
    <trkseg>
      <trkpt lat="39.9042" lon="116.4074">
        <ele>52.3</ele>
        <time>2024-01-15T06:30:00Z</time>
      </trkpt>
      <trkpt lat="39.9045" lon="116.4080">
        <ele>52.5</ele>
        <time>2024-01-15T06:30:05Z</time>
      </trkpt>
    </trkseg>
  </trk>
</gpx>

KML格式

KML是Google Earth的「母语」。如果你想把轨迹直接扔到Google Earth里看,KML是最方便的。但说实话,KML里有很多样式、描述之类的冗余信息,做数据分析时我一般会转成CSV或JSON。

CSV格式

CSV是最轻量的格式。我建议做批量处理时优先用CSV,因为它就是纯文本,用Excel都能打开。但要注意:CSV没有统一标准,字段顺序全靠约定。

latitude,longitude,time,altitude,speed
39.9042,116.4074,2024-01-15T06:30:00Z,52.3,0.0
39.9045,116.4080,2024-01-15T06:30:05Z,52.5,1.2
39.9048,116.4086,2024-01-15T06:30:10Z,52.4,1.5

JSON格式

JSON在Web开发中非常流行。如果你做前端轨迹可视化,JSON是首选。它的结构灵活,可以嵌套元数据。

{
  "name": "晨跑路线",
  "points": [
    {"lat": 39.9042, "lon": 116.4074, "time": "2024-01-15T06:30:00Z", "alt": 52.3},
    {"lat": 39.9045, "lon": 116.4080, "time": "2024-01-15T06:30:05Z", "alt": 52.5},
    {"lat": 39.9048, "lon": 116.4086, "time": "2024-01-15T06:30:10Z", "alt": 52.4}
  ]
}

我的建议:做数据清洗和预处理时,先把所有格式统一成CSV或JSON。GPX和KML解析起来麻烦,统一格式后处理逻辑就简单了。

1.3 轨迹数据清洗与预处理

好,格式讲完了。接下来是重头戏——数据清洗。为什么需要清洗?因为原始GPS数据真的很「脏」。我在项目中遇到过各种奇葩情况:手机在口袋里乱晃、过隧道信号丢失、高楼遮挡导致定位漂移……

下面我总结三个最常见的清洗步骤:

1.3.1 去除漂移点

漂移点是什么?就是那些明显不合理的坐标。比如一个人走路速度不可能超过20km/h,但GPS突然跳到了几百米外,这就是漂移。

我常用的方法是「速度阈值法」:

  1. 计算相邻两个点之间的距离
  2. 除以时间差,得到瞬时速度
  3. 如果速度超过阈值(比如步行设为10km/h,驾车设为200km/h),就判定为漂移点
def remove_drift_points(points, max_speed_kmh=10):
    """
    去除漂移点
    points: 按时间排序的轨迹点列表
    max_speed_kmh: 最大允许速度(km/h)
    """
    cleaned = [points[0]]  # 第一个点保留
    
    for i in range(1, len(points)):
        prev = cleaned[-1]
        curr = points[i]
        
        # 计算距离(单位:米)
        dist = haversine_distance(prev.lat, prev.lon, curr.lat, curr.lon)
        
        # 计算时间差(单位:小时)
        time_diff = (curr.time - prev.time).total_seconds() / 3600
        
        if time_diff > 0:
            speed = dist / 1000 / time_diff  # km/h
            if speed <= max_speed_kmh:
                cleaned.append(curr)
            else:
                print(f"发现漂移点:速度 {speed:.1f} km/h,已过滤")
    
    return cleaned

注意:阈值设置要合理。我曾经帮一个骑行项目做清洗,默认设了10km/h,结果把骑手的正常加速都过滤掉了。后来改成30km/h才合适。所以一定要根据实际场景调整参数。

1.3.2 时间戳对齐

时间戳对齐是个容易被忽视的问题。不同设备记录轨迹的时间间隔可能不一样——有的1秒一次,有的5秒一次,甚至有的设备会「跳秒」。

为什么要对齐?因为后续做轨迹回放、速度分析、路径匹配时,需要统一的时间基准。

我常用的方法是「线性插值」:

  1. 设定一个目标时间间隔(比如1秒)
  2. 在原始轨迹中找出每个目标时间点前后两个点
  3. 用线性插值计算出目标时间点的位置
def align_timestamps(points, interval_sec=1.0):
    """
    时间戳对齐:将轨迹点对齐到固定时间间隔
    points: 原始轨迹点(已按时间排序)
    interval_sec: 目标时间间隔(秒)
    """
    if len(points) < 2:
        return points
    
    start_time = points[0].time
    end_time = points[-1].time
    
    aligned = []
    current_time = start_time
    
    while current_time <= end_time:
        # 找到 current_time 前后的两个点
        before, after = find_surrounding_points(points, current_time)
        
        if before and after:
            # 线性插值
            ratio = (current_time - before.time) / (after.time - before.time)
            lat = before.lat + (after.lat - before.lat) * ratio
            lon = before.lon + (after.lon - before.lon) * ratio
            
            aligned.append({
                'time': current_time,
                'lat': lat,
                'lon': lon
            })
        
        current_time += timedelta(seconds=interval_sec)
    
    return aligned

小技巧:如果原始数据采样率很高(比如0.1秒一次),可以先降采样再对齐,能省不少计算量。我一般先降采样到0.5秒,再对齐到1秒。

1.3.3 其他常见清洗操作

  • 去除重复点:有时候设备会连续记录多个完全相同的坐标,这些点没有信息量,直接删掉
  • 填补缺失段:如果轨迹中间有超过30秒的空白,我建议标记为「中断段」,而不是强行插值
  • 坐标格式统一:有的数据用度分秒,有的用十进制,统一转成十进制方便计算

1.4 本章知识体系

下面这张图是我自己画的,把本章的核心逻辑串起来了。你看一遍应该就能明白轨迹数据处理的完整流程:

轨迹数据处理流程 原始GPS数据 GPX / KML / CSV / JSON 格式统一 统一为 CSV 或 JSON 数据清洗与预处理 去除漂移点 · 时间戳对齐 · 去重 去除漂移点 时间戳对齐 去重与填补 速度阈值法 计算相邻点速度 超过阈值则过滤 线性插值法 设定目标时间间隔 插值计算新坐标 规则判断法 删除完全重复点 标记长时中断段 ✅ 干净可用的轨迹数据

你看,整个流程其实不复杂。从原始数据到格式统一,再到清洗预处理,最后得到干净可用的轨迹。每一步都有对应的技术手段,而且这些手段在实际项目中已经验证过无数次了。

一句话总结:轨迹数据清洗不是锦上添花,而是必修课。跳过这一步,后面所有的分析、可视化、回放都是空中楼阁。

好了,这一章的内容就到这里。记住我强调的:先看数据质量,再做后续处理。下一章我们会聊轨迹回放的核心技术——如何把清洗好的数据流畅地播放出来。


可可精品资料库