出租车轨迹数据怎么洗?噪点如何去除?

GIS基础理论
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

“出租车轨迹数据怎么洗?噪点如何去除?”是很多 GIS 初学者、交通数据分析人员和 WebGIS 开发者都会遇到的问题。出租车 GPS 轨迹看起来只是经纬度和时间戳,但真实数据里经常混有漂移点、重复点、时间乱序、速度异常、跨城市跳点等问题。如果不先做轨迹数据清洗,后续的路径重建、OD 分析、热力图、道路匹配和出行特征统计都会被明显带偏。

出租车轨迹数据清洗与出租车轨迹噪点去除流程示意图
出租车轨迹数据清洗的典型流程:先处理时间和重复记录,再识别空间漂移点与速度异常点。

引言:出租车轨迹数据清洗到底要解决什么问题

出租车轨迹数据清洗的核心目标,不是把轨迹“修得好看”,而是尽量保留真实行驶过程,去除明显不符合车辆运动规律和数据采集逻辑的记录。

一条常见的出租车 GPS 记录通常包含以下字段:

  • 车辆 ID:用于区分不同出租车。
  • 经度、纬度:车辆定位点坐标。
  • 时间戳:GPS 上报时间。
  • 速度、方向角:部分数据会提供,也可能缺失。
  • 载客状态:空车、载客、停运等状态,常用于 OD 提取。

实际分析中,出租车轨迹噪点去除通常要处理四类问题:记录层面的错误、时间层面的错误、空间层面的错误、运动规律层面的异常。本文用 GIS 分析视角,给出一套可复用的清洗流程,适合在 Python、PostGIS、QGIS 或 ArcGIS Pro 前处理阶段使用。

背景:为什么出租车 GPS 轨迹会有噪点

出租车轨迹噪点并不一定是数据供应商“质量差”,更多时候来自 GPS 定位机制和车载终端上报机制。

1. 城市峡谷导致定位漂移

高楼密集区、隧道口、立交桥下方、地下停车场附近,经常会出现 GPS 信号反射或遮挡。结果是车辆明明在道路上行驶,定位点却漂到河里、楼里、隔壁道路甚至几百米之外。

2. 上报间隔不稳定

有的车辆每 10 秒上报一次,有的车辆可能 30 秒或 1 分钟才上报一次。网络延迟、设备休眠、信号丢失还会导致时间间隔忽长忽短。时间间隔不稳定会影响速度计算和轨迹插值。

3. 设备重复上传或补传

出租车终端可能会重复上传同一时刻的记录,也可能在网络恢复后集中补传历史记录。如果不按车辆 ID 和时间戳排序,就会看到轨迹线来回穿插。

4. 坐标系或经纬度字段错误

有些数据使用 WGS84,有些经过 GCJ-02 偏移,也有数据在导出时把经纬度字段写反。坐标系问题会造成整体偏移,经纬度反置则会让点直接落到错误区域。

判断出租车轨迹数据是否需要清洗,不要只看表格字段是否完整,一定要把点加载到地图上,并按车辆和时间连线检查。

原理:出租车轨迹噪点去除的判断逻辑

出租车轨迹数据清洗一般遵循“先简单规则,后复杂模型”的原则。不要一开始就做道路匹配或机器学习异常检测,否则很容易把基础数据错误掩盖掉。

1. 唯一性规则

同一辆车、同一时间戳、同一坐标的记录通常只需要保留一条。重复点会放大停留时间、影响轨迹点密度统计,也会干扰后续速度计算。

2. 时间连续性规则

同一辆车的轨迹必须按时间升序排列。如果时间倒序或乱序,计算出来的速度、距离、行驶方向都不可靠。

3. 空间范围规则

出租车轨迹点应位于研究区范围或合理缓冲区内。例如研究对象是北京市出租车,就可以用北京市行政边界外扩一定距离作为空间过滤范围。

4. 速度阈值规则

出租车在城市道路中的速度有合理上限。若相邻两个 GPS 点之间的距离除以时间间隔得到极高速度,通常说明其中至少一个点是漂移点。

5. 加速度和转向规则

如果车辆在极短时间内出现不合理加速、急停、反向跳变,也可能是轨迹噪点。但这类规则要谨慎使用,因为真实交通中确实存在急刹车、掉头、拥堵等情况。

步骤:出租车轨迹数据怎么洗

下面给出一套适合大多数出租车轨迹数据清洗的操作流程。无论你使用 Python、PostGIS、QGIS 还是 ArcGIS Pro,都可以按照这个顺序处理。

步骤 1:统一字段和数据类型

先把字段整理成稳定结构,至少包括车辆 ID、时间戳、经度、纬度。如果速度、方向角和载客状态可用,也建议保留。

字段 建议名称 说明
车辆编号 taxi_id 用于分组处理每辆车的轨迹
时间 timestamp 转换为标准日期时间类型
经度 lon 通常为 WGS84 或 GCJ-02 经度
纬度 lat 通常为 WGS84 或 GCJ-02 纬度
载客状态 status 可用于 OD 提取和行程切分

如果时间字段仍是字符串,必须先转换为日期时间类型。经纬度字段也要转换为数值型,避免出现空格、中文符号或异常字符。

步骤 2:删除空值和明显非法坐标

先删除 taxi_id、timestamp、lon、lat 中为空的记录。然后检查经纬度范围。

  • 经度通常应在 -180 到 180 之间。
  • 纬度通常应在 -90 到 90 之间。
  • 中国城市出租车数据一般不会出现负经度。
  • 如果 lon 小于 lat,且数据落点明显异常,要检查是否经纬度写反。

这一步属于基础轨迹数据清洗,能快速去掉一批明显无效点。

步骤 3:按车辆 ID 和时间排序

出租车轨迹噪点去除必须按单车轨迹进行,不能把所有车辆混在一起计算距离和速度。正确顺序是先按 taxi_id 分组,再按 timestamp 排序。

import pandas as pd

df = pd.read_csv("taxi_gps.csv")

df["timestamp"] = pd.to_datetime(df["timestamp"], errors="coerce")
df["lon"] = pd.to_numeric(df["lon"], errors="coerce")
df["lat"] = pd.to_numeric(df["lat"], errors="coerce")

df = df.dropna(subset=["taxi_id", "timestamp", "lon", "lat"])
df = df.sort_values(["taxi_id", "timestamp"])

如果这一步不做,后面的速度异常检测基本没有意义。

步骤 4:删除重复记录

重复记录可以按业务目标分两种情况处理。如果同一辆车、同一时间戳、同一坐标完全一致,一般直接删除。如果同一辆车、同一时间戳出现多个不同坐标,则需要进一步判断。

df = df.drop_duplicates(subset=["taxi_id", "timestamp", "lon", "lat"])

对于同一 taxi_id 和 timestamp 对应多个坐标的情况,建议先标记出来,不要立即随机保留一条。可以结合速度、空间范围和前后点连续性决定保留哪一个。

步骤 5:做研究区空间范围过滤

如果你的研究区是某个城市,建议准备行政边界面数据,外扩 1 到 5 公里作为容差范围,再用空间连接或点面包含关系过滤。这样可以去除落在海上、外省、远离城市区域的异常点。

在 QGIS 中可以这样做:

  1. 加载出租车点数据和城市边界面数据。
  2. 确认两者坐标系一致。
  3. 对城市边界执行缓冲区工具,例如外扩 3000 米。
  4. 使用“按位置提取”工具,保留落在缓冲区内的轨迹点。
  5. 导出为新的 GeoPackage 或 CSV 文件。

在 PostGIS 中,可使用 ST_Within 或 ST_Intersects 配合城市边界过滤:

SELECT t.*
FROM taxi_points t
JOIN city_boundary b
ON ST_Intersects(t.geom, ST_Buffer(b.geom, 3000));

注意:如果 geom 使用经纬度坐标系,直接缓冲 3000 并不代表 3000 米。应先转换到适合本地的投影坐标系,或者使用 geography 类型处理距离。

步骤 6:计算相邻点距离、时间差和速度

速度异常检测是出租车轨迹噪点去除最常用的方法。基本思路是:对同一辆车的相邻两点计算距离和时间差,再得到平均速度。

import geopandas as gpd
from shapely.geometry import Point

gdf = gpd.GeoDataFrame(
    df,
    geometry=gpd.points_from_xy(df["lon"], df["lat"]),
    crs="EPSG:4326"
)

# 示例:如果研究区适合使用 Web Mercator,可临时投影到米单位坐标系
# 更严谨做法是选择本地投影坐标系
gdf_m = gdf.to_crs("EPSG:3857")

gdf_m["prev_geom"] = gdf_m.groupby("taxi_id")["geometry"].shift(1)
gdf_m["prev_time"] = gdf_m.groupby("taxi_id")["timestamp"].shift(1)

gdf_m["dt_sec"] = (gdf_m["timestamp"] - gdf_m["prev_time"]).dt.total_seconds()
gdf_m["dist_m"] = gdf_m.apply(
    lambda row: row["geometry"].distance(row["prev_geom"]) if row["prev_geom"] else None,
    axis=1
)

gdf_m["speed_kmh"] = gdf_m["dist_m"] / gdf_m["dt_sec"] * 3.6

计算速度时要特别注意投影坐标系。不要直接用经纬度坐标计算欧氏距离,否则距离单位是“度”,不是米。

步骤 7:根据速度阈值标记噪点

城市出租车轨迹中,如果相邻点推算速度远高于城市道路可能速度,通常可以标记为异常。阈值应结合城市道路条件、采样间隔和业务目的设定。

  • 普通城市道路分析:可先检查大于 120 km/h 的点段。
  • 包含高速路场景:阈值可适当放宽。
  • 采样间隔很长的数据:速度阈值不能过于严格。
  • 用于精细道路匹配:应更谨慎,避免删除真实快速路轨迹。
speed_threshold = 120

gdf_m["is_speed_noise"] = (
    (gdf_m["dt_sec"] > 0) &
    (gdf_m["speed_kmh"] > speed_threshold)
)

clean_gdf = gdf_m[~gdf_m["is_speed_noise"]].copy()

更稳妥的做法不是只删除当前点,而是同时检查前一个点和后一个点。如果某个点与前后点都形成异常跳变,而前后点之间相对连续,那么这个中间点很可能是漂移点。

步骤 8:处理时间间隔异常

如果相邻点时间差为 0 或负数,说明有重复时间或时间乱序,应删除或单独检查。如果时间差过大,例如超过 30 分钟,通常不应把两个点直接连成一条连续轨迹。

可以用时间间隔进行行程切分:

max_gap_sec = 30 * 60

gdf_m["new_segment"] = (
    (gdf_m["dt_sec"].isna()) |
    (gdf_m["dt_sec"] <= 0) |
    (gdf_m["dt_sec"] > max_gap_sec)
)

gdf_m["segment_id"] = gdf_m.groupby("taxi_id")["new_segment"].cumsum()

这样处理后,轨迹线生成、道路匹配和停留点识别会更合理。

步骤 9:结合道路数据做进一步检查

如果你有道路中心线数据,可以检查出租车点到最近道路的距离。距离道路过远的点可能是 GPS 漂移点,但不能简单一刀切删除。

  • 高架桥、辅路、隧道附近容易出现道路数据不完整问题。
  • 新建道路可能不在旧版路网中。
  • 停车场、加油站、出租车场站不一定在道路中心线上。
  • 坐标系不一致会导致所有点到道路距离都异常。

道路距离过滤更适合作为“疑似噪点标记”,而不是唯一删除条件。

步骤 10:导出清洗结果并保留质量字段

完成出租车轨迹数据清洗后,不建议只导出一个“干净数据”。更好的做法是保留质量控制字段,方便追溯。

  • is_duplicate:是否重复记录。
  • is_outside_area:是否超出研究区。
  • speed_kmh:相邻点推算速度。
  • is_speed_noise:是否速度异常。
  • segment_id:轨迹分段编号。
  • clean_status:保留、删除、待人工检查。

这些字段对后续复核、论文方法说明、项目交付都很有用。

常见坑:出租车轨迹噪点去除时最容易犯的错误

1. 直接用经纬度计算距离

经纬度坐标的单位是度,不是米。出租车轨迹数据清洗中如果要计算距离、速度、缓冲区,应转换到合适的投影坐标系,或使用支持椭球距离计算的方法。

2. 把所有超速点直接删除

速度异常只能说明相邻点段异常,不一定说明当前点一定是噪点。特别是一个点前后都异常时,需要判断是当前点漂移,还是前一个点或后一个点异常。

3. 忽略采样间隔

10 秒采样和 5 分钟采样的轨迹,清洗策略不能完全一样。采样间隔越长,轨迹越稀疏,短距离绕行、快速路通行、隧道补点都会使速度判断变得不稳定。

4. 没有区分停留点和重复点

同一辆车在同一地点停留很久,不等于重复点。真正的重复点通常是同一时间戳、同一坐标重复出现。停留点在出租车候客、等红灯、拥堵分析中可能很有价值。

5. 先做道路匹配再清洗

道路匹配可以修正轨迹,但不能替代基础清洗。大量漂移点、乱序点和重复点会让道路匹配结果出现跳路、绕路、错误吸附等问题。

6. 坐标系混用

如果出租车点是 GCJ-02,而道路数据是 WGS84 或投影坐标,二者会产生系统偏移。做道路距离检查或道路匹配前,必须确认坐标体系一致。

方法比较:不同出租车轨迹数据清洗方法怎么选

方法 适用场景 优点 局限
字段规则清洗 空值、非法经纬度、重复记录 简单、稳定、适合第一步处理 不能识别复杂漂移点
空间范围过滤 研究区外异常点 直观,适合城市级数据 边界外真实运营点可能被误删
速度阈值过滤 跳点、漂移点、定位异常 通用性强,易解释 阈值需要结合采样间隔和道路条件
加速度与方向变化检测 精细轨迹质量控制 能识别不连续运动 对低频数据不稳定
道路距离过滤 有可靠路网数据的城市交通分析 接近真实道路约束 依赖路网质量和坐标一致性
地图匹配 路径还原、路段流量分析 可得到道路级轨迹 不适合作为原始数据第一步清洗

实际项目中,推荐组合使用:字段规则清洗、时间排序、空间范围过滤、速度异常检测、轨迹分段、道路距离复核。这样既能覆盖大部分出租车轨迹噪点,又不会过度删除有效数据。

检查清单:清洗后如何验证出租车轨迹数据是否可靠

完成出租车轨迹数据清洗后,建议按下面清单复查,不要只看删除了多少记录。

  • 是否每辆车的轨迹都按时间升序排列?
  • 是否删除了 taxi_id、timestamp、lon、lat 为空的记录?
  • 经纬度是否落在合理范围内?
  • 是否检查过经纬度字段是否写反?
  • 是否统一了坐标系和坐标偏移类型?
  • 是否按车辆 ID 分组计算速度,而不是全表直接计算?
  • 速度计算是否使用米单位距离?
  • 是否保留了异常标记字段,方便后续追溯?
  • 是否抽样在 QGIS 或 ArcGIS Pro 中连线查看轨迹形态?
  • 是否对删除前后点数、车辆数、时间范围做了统计对比?

如果清洗后车辆数大幅减少、某些时间段完全消失、轨迹集中断裂,说明规则可能过严,需要回看阈值设置。

FAQ:出租车轨迹数据清洗常见问题

出租车轨迹数据清洗一定要做道路匹配吗?

不一定。道路匹配适合需要还原行驶路段、统计道路流量或计算路径的场景。如果只是做点密度、热力图、OD 分析,基础轨迹数据清洗和合理的轨迹分段通常已经足够。

出租车轨迹噪点去除的速度阈值应该设多少?

没有固定答案。城市道路分析可以先从 100 到 120 km/h 作为检查阈值,高速路较多的城市可适当提高。更好的方式是先统计速度分布,查看极端值,再结合城市道路条件设置阈值。

时间间隔很大的两个点要不要删除?

通常不需要直接删除,但不应把它们当作连续轨迹连接。建议用时间间隔生成新的 segment_id,把长时间中断前后的轨迹分成不同片段。

停在原地的点算噪点吗?

不一定。出租车可能在等客、等红灯、拥堵或停车场停留。只有同一时间戳、同一坐标重复出现,或者数据明显由设备重复上传造成,才应作为重复记录处理。

QGIS 可以完成出租车轨迹数据清洗吗?

可以完成一部分,例如加载点数据、检查空间分布、删除非法点、按位置提取、生成轨迹线、可视化抽查。但如果数据量很大,建议使用 Python、PostGIS 或数据库流程批量处理。

为什么清洗后轨迹还是会穿过建筑物或河流?

基础清洗只能去除明显异常点,不能保证轨迹线完全沿道路行驶。GPS 点之间的连线是直线连接,不等于真实行驶路线。如果需要道路级路径,需要进一步做地图匹配。

出租车轨迹数据清洗后应该保存成什么格式?

小规模数据可以保存为 GeoPackage、GeoJSON 或 CSV。大规模城市出租车轨迹建议存入 PostGIS,便于建立空间索引、按时间和车辆查询,并支持后续空间分析。

结论:先保证轨迹可信,再做空间分析

出租车轨迹数据怎么洗,关键在于按顺序处理:统一字段、删除空值和非法坐标、按车辆和时间排序、去重、空间范围过滤、计算速度、标记异常点、分段保存。出租车轨迹噪点去除不能只依赖一个阈值,而应结合时间、空间、速度、道路约束和业务场景综合判断。

对 GIS 读者来说,最重要的习惯是:每一步清洗都保留标记字段,每一类规则都抽样上图检查。只有确认轨迹数据本身可靠,后续的 OD 分析、出行热力图、路径重建和交通运行评价才有可信基础。