☰
交通流预测爬坑记:原始数据清洗与预处理全指南
2026/10/5 4:51:53 网站建设 项目流程

做交通流预测这一年多,我踩得最深的坑不在模型结构,而在数据本身。好多来问经验的同学,开口就是“GCN和Transformer哪个效果好”,我的回答永远先反问一句:“你手里那份原始数据弄干净了没?”一份采样异常、缺数严重、传感器乱报的数据集,喂给再先进的模型也是白搭。

这个“交通流预测爬坑记”系列,第一篇先聊最底层的东西——交通流数据集和原始数据。数据从哪来、长什么样、隐藏哪些坑、怎么处理,这些我都会结合自己实际跑实验、做项目的经历写清楚。不管你是准备用开源数据集复现论文,还是要在自己项目里处理路况检测数据,这一篇应该都能帮你少走点弯路。

1. 交通数据是怎么采出来的:先搞懂喂给模型的料

1.1 主流的交通流采集方式

很多人拿到一份数据集就直接开始写模型,从没想过数据是怎么来的。其实采集方式决定了数据质量的上限。我梳理一下几种常见的采集手段:

  • 感应线圈检测器:这是最传统、也是最常见的路面检测设备。线圈埋设在路面下方,车辆经过时会引起磁场变化,从而触发信号。双线圈结构还能估算车长和瞬时速度。它的精度高、不受天气影响,但缺点是安装要开挖路面,线圈故障后维修麻烦,而且对低速蠕行车流的检测会偏差。

  • 视频检测器:用摄像头配合图像识别算法,可以同时识别流量、车型、车道占用情况,还能做轨迹跟踪。优点是信息丰富,缺点是强光、阴影、雨雾天容易误判,夜间效果普遍打折。

  • 微波雷达/超声波:靠多普勒效应或反射波测速测距,安装方式灵活,但多车道干扰、遮挡会让数据毛刺很多。

  • 浮动车GPS数据:来自出租车、网约车、导航软件的定位轨迹,覆盖面广,能反映路网运行状态。但缺点是它有偏向性——出租车多的地方数据密,郊区稀疏,而且只能推断速度,很难给出精确到车道的交通流量。

  • 蓝牙/Wi-Fi嗅探与手机信令:成本低,能估算路段旅行时间,但采样率不稳定,涉及隐私合规,不适合直接当精确流量数据用。

我的体会是:如果你做的是短时交通流预测,最佳选择是线圈或雷达这类“点式检测器”数据;如果你做的是路径级旅行时间预测,浮动车数据更合适。不同的采集方式对应不同的任务假设,别混着用。

1.2 交通流数据的四个核心量

交通流预测里,研究“流量”只是其中一部分。真正核心的量有四个:

  • 流量(Flow/Volume):单位时间内通过某断面的车辆数,常见单位是辆/小时或辆/5分钟。
  • 速度(Speed):通过某断面的平均车速,一般分为时间平均速度和空间平均速度,单位是km/h。
  • 占有率(Occupancy):检测器被车辆占用的时间比例,取值范围0到100%,它比流量更直接地反映拥堵程度。
  • 密度(Density):单位路段长度内的车辆数,单位是辆/公里/车道。

这四个量不是孤立的,交通流基本图告诉我们:流量 = 密度 × 速度。也就是说,当数据同时包含流量和速度时,你可以用它们推出密度,但要注意单位换算和时间粒度的一致性。比如5分钟流量乘以12才能变成小时流量,速度也要保持同一时间窗口内的均值口径。

在实际预测任务里,速度是最常用的目标量,因为它在稀疏路网上也相对稳定;流量预测最容易受检测器故障影响,一个线圈坏掉,断面流量直接变零;占有率预测在paper里相对少,但它对识别排队和拥堵拐点非常敏感。选哪个作为预测目标,直接决定了你对数据清洗的要求强度。

1.3 时空分辨率:采样间隔与空间粒度

原始数据进入模型前,必须统一时空粒度。先说时间粒度。

交通流预测最常用的是5分钟聚合和15分钟聚合。5分钟意味着一天24小时被切成288个时间步;15分钟则是96步。很多经典数据集都采用5分钟粒度,因为它在捕捉短时突变(比如事故后的拥堵扩散)和保留数据稳定性之间取得了平衡。

如果你的原始数据是30秒或1分钟一条记录,就需要做聚合。聚合方式别直接用算数平均完事——流量适合求和,速度适合加权平均或中位数。举个例子,1分钟流量聚合到5分钟,就是对5条记录求和;速度聚合则可以用“以流量为权重”的加权平均,更符合物理意义。

空间粒度上,常见的数据组织模式有三种:

  • 断面检测器:每个传感器是一个空间节点,代表路网中的一个点位置。
  • 路段/网格:把道路按长度切分或把城市网格化,每个格子是一个节点。
  • 卡口/收费站:以收费站或路口识别点作为节点,数据来自交易记录。

同一份原始数据在不同空间粒度下构建的预测问题完全不同。比如线圈数据,天然就是断面级;但如果你要做城市级网格流量预测,就必须做空间映射和插值。我见过很多人拿断面级数据硬套网格预测模型,最后结果一团糟,原因就是空间语义对不上。

2. 常用公开数据集盘点:从METR-LA到PEMS系列

2.1 绕不开的三个基准数据集

在交通流预测领域,有三个公开数据集几乎在所有论文里都会出现。我把它们的核心信息列出来:

数据集路网区域传感器数量时间跨度时间粒度变量
METR-LA洛杉矶县高速路2072012.03-2012.06(约4个月)5分钟平均速度
PEMS-BAY湾区高速路3252017.01-2017.05(约6个月)5分钟平均速度
PEMS-SF旧金山湾区4402009-2010(部分年份切片)15分钟占有率/流量

METR-LA和PEMS-BAY源于DCRNN那篇工作,目前几乎所有时空预测论文都在这两个数据集上做效果对比。它们的特点是:传感器分布在真实高速路网的不同位置,文件里还提供了传感器经纬度坐标,可以构建路段距离图。METR-LA的缺失率大概在8%左右,PEMS-BAY缺失率低一些,但也不是干干净净。PEMS-SF则来自加州PeMS系统,在LSTM、GCN早期论文里很常见,粒度是15分钟,一天只有96步,做短时预测偏粗。

很多论文还会用 PEMS03、PEMS04、PEMS07、PEMS08 这一组流量数据集。这四个数据集的传感器数量分别是358、307、883、170左右,时间多为2018年某几个月,5分钟粒度,预测目标是车流量。它们的公开程度稍低,很多版本是论文作者自己从PeMS系统抓出来再二次处理的,读入时要特别留意文件里的shape和单位。

2.2 更细颗粒度的轨迹数据集

除了断面检测器数据,还有一类被用来做车辆级行为预测的数据集,比如NGSIM和HighD。NGSIM提供的是美国高速公路某路段的高精度车辆轨迹,采样精度0.1秒,包含了每辆车的坐标、速度、加速度、车道编号。它做微观驾驶行为分析、轨迹预测很好用,但它的采样区域很短(只有几百米),而且采样时段不是全天,不适合直接用于宏观短时交通流预测。

HighD是德国研究机构用无人机拍摄的高速路大规模轨迹数据集,数据质量比NGSIM干净不少,位置是德国高速,车辆靠右行驶,方向盘位置也和国内不同。如果要做跟车模型或换道行为研究,HighD是不错的替代选择。

我的建议很简单:做网络级短时交通流预测,老老实实用METR-LA、PEMS-BAY或自己从PeMS处理的数据;做驾驶行为、轨迹预测,才选NGSIM、HighD。两者研究的尺度完全不同,数据集选错了,后面所有工作都会跑偏。

2.3 下载与读入踩坑记录

关于这些数据集的下载与读入,我实打实踩过几次坑,写下来供参考。

  • 链接失效问题:很多论文作者把数据放在个人网盘或服务器上,过了几年链接就失效了。DCRNN官方仓库里给的METR-LA下载链接我亲测中间断了很久。解决办法是去GitHub上搜别人fork的分支,或者直接看有没有好心人二次打包。国内一些学术社区也有人长期维护镜像,但注意核对文件指纹或校验和,避免下载到被人改过的版本。

  • HDF5文件读入:METR-LA和PEMS-BAY最常见的存储格式是.h5。用Python的h5py读入后,数据shape通常是[传感器数, 时间步数],但有的版本会存成[时间步数, 传感器数]。如果你不先打印shape直接喂模型,报错会让人找半天。

import h5py import numpy as np file_path = "metr-la.h5" with h5py.File(file_path, "r") as f: print("keys:", list(f.keys())) data = f["data"][:] # 具体key要打印确认 print("shape:", data.shape)
  • 坐标映射:METR-LA的.h5里除了数据,还有一个sensor_ids列表。要用来构建图结构时,必须再加载一份sensor_info或单独的csv文件,把传感器ID和经纬度对应上。很多人在这一步漏了坐标而直接用随机图,效果当然差。

  • 时间戳语义:PeMS原始数据用的是当地时区,但存储时往往不带时区信息。如果你把时间戳直接转成字符串或者用别的时区处理,后续跟天气、节假日数据对齐时会差出几个小时,这种错误最难排查。我现在的习惯是拿到数据后第一时间把时间统一转成UTC时间戳,再按需展示本地时间。

3. 原始数据的真实面目:缺数、异常与脏数据

3.1 缺失值是怎么来的

公开数据集已经是清洗过一轮的,但它的“清洗”只是把明显的坏值替换成标记,不代表完整。METR-LA的原始数据缺失率约为8%,落实到具体传感器,有的传感器一天会连续缺好几个小时。

缺失值的主要来源有几种。一种是检测器故障,线圈被重车压坏、线路进水、供电异常都会让数据中断;一种是通信传输丢包,数据采集到传输的过程中网络不稳定;还有一种是道路施工封闭,施工期间传感器检测到的是施工车辆甚至没有车,数据要么归零要么出现异常模式。

关键提醒:缺失值在原始记录里可能是NaN、-1、255这类哨兵值,也可能直接就是0。所以在清洗前,一定要打印数据的取值范围和缺失分布,别想当然认为“NaN才叫缺失”。我遇到过一份数据,缺失标记是-1,但我按0处理了,结果模型学出一个虚假的“零流量”特征,非常坑。

3.2 异常值的几种典型形态

除了缺失,原始数据里最让人头疼的是看起来“合理”实则离谱的异常值。我总结几种典型形态:

  • 瞬时突刺:速度在某一时刻从80km/h突然跳到0,下一个时刻又恢复正常。这不是真实停车,而是检测器误触或通信干扰。
  • 超物理范围:限速120的高速公路上出现180km/h的连续数据;流量超过了单车道每小时2400辆的通行能力上限;占有率超过100%。这类值可以直接判死。
  • 连续零值:晚间低峰期流量为0、速度为0很正常,但白天高峰期出现连续的0就不正常。尤其是高速路,白天不可能整体流量为零。
  • 阶梯跳变:速度曲线呈“台阶状”跳升或跳降,往往是设备校准参数被修改或数据聚合逻辑变化导致,不是交通状态的真实变化。

对待异常值,我的原则是“先定规则,再处理”。规则必须基于物理常识:流量非负、速度有上限、占有率在0到100之间。凡是突破物理边界的,直接标记为缺失;凡是统计意义上的离群点,再结合前后时间窗口判断。

3.3 容易被忽略的隐藏陷阱

还有一个很容易被忽略的问题是“传感器名对应错位”。公开数据集里的传感器ID和实际路网位置是按列表顺序存储的,但不同来源的数据文件可能是按不同顺序排列的ID。如果你把A文件里的速度数据配到B文件里的坐标上,图结构就是错的,模型预测自然全乱。

另一个陷阱是时间步对齐。文件里的每一行未必严格按照时间递增,可能存在跳秒或重复时间戳。我建议在预处理的第一步就校验时间索引的完整性:

import pandas as pd def check_time_index(df, freq="5min"): t = pd.to_datetime(df["time"]) expected = pd.date_range(start=t.min(), end=t.max(), freq=freq) missing = expected.difference(t) dup = t[t.duplicated()] print("缺失时间步:", len(missing), "重复时间步:", len(dup)) return missing, dup

另外要注意昼夜与节假日模式。交通流有非常强的周期性,工作日早晚高峰、周末午高峰、节假日出行模式差异巨大。如果数据集里只包含周一到周五,你却拿它去预测周末,效果一定打折扣。做实验前先画一张“按星期几分组的平均流量曲线”,能帮你在前期就发现数据覆盖是否均衡。

4. 数据清洗与预处理实操:一套能直接抄的打法

4.1 拿到原始数据后的标准检查流程

每次拿到新数据,我都会按照固定流程走一遍,这样不容易漏问题:

  1. 看shape与样本:确认数据维度、字段含义、时间范围,打印前几行看清楚每个字段的物理单位。
  2. 算缺失率:按传感器逐一计算缺失比例,画出缺失分布热力图,找出问题传感器。
  3. 画时间序列曲线:随机挑几个传感器,画一周的速度曲线,肉眼看是否有毛刺、零值段、突变。
  4. 画空间分布图:把传感器经纬度投影到地图底图上,确认点位分布合理,有没有坐标漂移的离群点。
  5. 检查数值范围:对每一列计算min、max、mean、std,结合物理约束判断是否越界。

这套流程看起来繁琐,但能省下后面积累的无数麻烦。尤其是第3步,我强烈建议至少手动看两三个传感器的周曲线,因为很多藏在统计量之外的问题,只有图上才看得出。

4.2 缺失值补全方案的选择

缺失值补全没有万能的方案,我按缺口大小和数据类型给建议:

缺失情况推荐方法注意点
单点或小于3步的短缺口线性插值简单、稳定,适合缓变的速度数据
中等缺口(10分钟内)上一有效值填充或分段线性插值避免引入过高频噪声
长缺口(超过30分钟)按历史同期均值填充或KNN补全长缺口本质不可精确还原,别硬补
整段传感数据长期异常直接删除该传感器保留反而给图模型带来噪声边

这里要特别强调:补缺失值时不要偷看未来。如果你在训练阶段就使用整段时间轴上的全局统计量或未来窗口的数据做插值,相当于让模型在预测时“作弊”,测试集的指标会失真。安全的做法是只利用历史数据和长期统计先验。如果你用的是矩阵分解类补全方法,务必在训练集内部拟合,再应用到验证集和测试集。

4.3 归一化、数据集划分与滑窗构造

数据干净之后,下一步是归一化、切分和构造样本。

归一化常用两种方式:z-score标准化(x - mean) / std和min-max归一化(x - min) / (max - min)。速度数据用z-score更稳,流量数据用min-max更直观。无论用哪种,统计量都只能从训练集计算,然后应用到验证集和测试集。这是最基本的数据泄漏红线,但我在很多初学者的代码里都见过错误写法——用全局min/max归一化后再切分,等于验证集的信息泄漏进了训练过程。

数据集划分必须按时间顺序,不能随机打乱。常见比例是训练集70%、验证集10%、测试集20%。随机打乱会把未来数据混进训练,模型在时间序列任务上就会“偷看”。我建议按如下方式切分:

def temporal_split(data, train_ratio=0.7, val_ratio=0.1): n = len(data) train_end = int(n * train_ratio) val_end = int(n * (train_ratio + val_ratio)) train, val, test = data[:train_end], data[train_end:val_end], data[val_end:] return train, val, test

滑窗构造是预测模型的关键一步。假设输入过去12个时间步,预测未来12个时间步,那么对于每个时间点t,输入是X[t-12:t],标签是Y[t:t+12]。窗口滑动的步长通常为1,这样能充分利用数据。构造时要注意相邻窗口之间存在重叠,训练时没问题,但如果你自己写数据加载器,别把重叠样本当成相互独立的数据点来计算有效样本量。

4.4 从原始数据到图结构:为图模型铺路

现在交通流预测的主流模型都基于图神经网络,因此原始数据还得变成一张图。图的节点就是传感器,边表示传感器之间的空间关系。

最常用的构图方式是“以距离定边”:根据传感器经纬度计算两两距离,小于阈值的连接,再给每条边赋权重。权重可以用高斯核函数计算:

import numpy as np from scipy.spatial.distance import cdist coords = np.array([[lon1, lat1], [lon2, lat2], ...]) dist = cdist(coords, coords, metric="euclidean") sigma = 500.0 threshold = 1000.0 adj = np.exp(-dist**2 / sigma**2) adj[dist > threshold] = 0.0 np.fill_diagonal(adj, 0.0)

这里的sigma和threshold不是拍脑袋定的,要根据路网实际间距来调。如果传感器平均间距是800米,阈值设成500米就几乎连不上边;设成3000米又会把不相邻的高速路段连在一起,引入错误的空间关系。我一般会把传感器距离分布画出来,取80%分位数作为阈值参考。

另一个细节是:流量预测的图不一定等于地理距离图。有些情况下,上游和下游的关联方向很重要,可以构建有向图;如果只有速度数据而缺少流向信息,常用的做法还是用无向图,因为PeMS这类数据不直接提供车道级流向。做实验时,先跑无向图基线,再尝试加方向权重,能更清楚模型到底从图结构里学到了什么。

5. 常见问题与排查技巧实录

5.1 问题速查表

我在处理原始数据时遇到过的典型问题,整理成一张速查表,供大家对照排查:

现象可能原因处理思路
数据里有大量-1或255原始系统用哨兵值表示缺失先识别哨兵值,统一转为NaN再清洗
某传感器连续7天全零检测器故障或路段封闭查看零值时间段是否有施工公告,否则删除该传感器
速度出现负值数据解析错误或设备异常物理校验后标记缺失,不要保留负值参与归一化
预测误差在凌晨特别大夜间数据方差大、样本少分时段评估误差,或用分位数损失
验证集效果比训练集还好缺失插值泄漏了未来信息重新检查插值和归一化是否只用历史信息
换一个传感器子集后模型性能骤降传感器编号与坐标错配核对文件中的ID顺序和坐标是否一一对应
图很稀疏,GCN收敛很慢边的阈值设得太小增大阈值或改用k近邻构图

关于最后一行,我再多说一句:图网络在过图数据上收敛慢,有时不是模型问题,而是邻接矩阵太稀疏,信息传不出去。可以用“自适应图”或“k近邻图”来缓解,但对原始数据的构图参数敏感性要心里有数,不同的图结构在同一模型上的差距,经常比换模型还大。

5.2 给我一次重来会先做的事

如果让我现在重新开始一个交通流预测项目,我会先花两到三天时间把数据侧彻底做扎实,再动模型。具体就是这么几件事:

第一,把一份数据从原始格式到模型输入的全流程写成可重放的脚本,每一步都保留中间结果和日志。这样一旦实验结果异常,我能快速判断是数据问题还是模型问题。第二,固定一份数据版本,不要一边调模型一边改数据清洗逻辑,否则效果波动根本没法归因。第三,始终保留一份“脏数据”备份。

第四,我会尽早建立一套可视化看板,每天定时刷新所有传感器的缺失率、均值、方差和最近一周曲线。数据漂移很多时候不是一次性的,而是缓慢发生的,比如某台检测器老化,速度均值逐渐偏低。这种漂移光靠统计量很难发现,曲线图里却一眼能看出来。

这类经验,常规的数据集说明书里不会写,但实际做项目时几乎每天都会遇到。交通流预测这份工作,模型结构决定下限,数据质量决定上限。很多论文效果“不可复现”,我怀疑相当一部分原因不是模型代码有问题,而是数据处理流程对不上。

下一篇文章在这个系列里,我准备拆一拆“从清洗后的数据到模型训练”那段路——包括滑窗的工程实现、batch构造、多步预测的标签组织,以及几种“看似合理实则错误”的训练代码写法。等填完了数据这个大坑,我们再坐下来好好聊模型。

在那之前,如果你正被一份莫名其妙的原始数据折磨,记住:先把每条记录的物理意义搞明白,把缺失和异常当成一等公民认真处理,模型的事可以往后放放。数据不好,模型再花哨也救不回来。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询