早晚高峰堵在环路上的时候,很多人都会想:导航软件是怎么知道前面三公里要堵二十分钟的?这背后是城市计算里一个经典问题——交通流量预测。它的输入是遍布城市的线圈、卡口、网约车 GPS 产生的时空数据,输出是未来几十分钟到几小时内每个路段的车速、流量和拥堵概率。看似只是"猜车多不多",做起来却牵扯到时空建模、图结构学习和大量工程妥协。
交通流量预测难在哪
交通数据有三个让常规时序模型头疼的特性。
第一是空间依赖。上游路段堵车会在十几分钟后传导到下游,而路网不是规则的网格,是一个带方向的图。欧氏距离近的两个点,在路网里可能隔着一条河,完全不相干。第二是时间上的多周期性:工作日有早晚高峰,周末曲线完全不同,节假日又会整体漂移,再加一场暴雨或一场演唱会,规律立刻被打乱。第三是数据质量问题。线圈检测器常年有一定比例的故障率,缺失值不是随机分布的,往往集中在暴雨、严寒这些恰恰最需要准确预测的场景里。
理解这三点,就理解了为什么单纯的 ARIMA 或 LSTM 在实际路网里表现平平:它们把每个路段当成孤立序列,丢掉了图结构这一半信息。
主流模型路线对比
这些年交通预测的模型演进,大致是从统计方法到深度时序,再到时空图网络。下面是一个简化的对比:
| 模型路线 | 代表方法 | 空间建模 | 优点 | 局限 | | --- | --- | --- | --- | --- | | 统计方法 | ARIMA、Kalman Filter | 无 | 可解释、无需训练数据量大 | 无法处理非线性和路网传导 | | 纯时序深度模型 | LSTM、TCN、Informer | 无 | 拟合非线性周期强 | 忽略空间依赖,跨路段泛化差 | | 时空图网络 | DCRNN、ST-GCN、Graph WaveNet | 图卷积/扩散卷积 | 显式建模路网拓扑,精度领先 | 训练成本高,图结构需人工先验 | | 大模型/基座路线 | 时序基础模型微调 | 隐式 | 迁移能力强、冷启动友好 | 可解释性弱,落地案例尚少 |
目前工业界落地最多的还是时空图网络。思路很直接:把路段或检测器看作节点,道路连接关系看作边,用图卷积聚合邻居信息,再叠一层 GRU 或 TCN 捕捉时间演化。DCRNN 用扩散卷积模拟车流的上下游传播,Graph WaveNet 则进一步让模型自己学习邻接矩阵,避免人工定义图结构带来的偏差。
一个最小可跑的时空模型示例
下面用 PyTorch 写一个简化版图卷积 + GRU 的预测单元,帮助理解数据流动的形状。真实项目里可以直接用 DCRNN、STSGCN 等开源实现,但核心结构就是这两块的组合:
import torch import torch.nn as nn class GraphConv(nn.Module): """简化的图卷积:AXW,A 为归一化邻接矩阵""" def __init__(self, in_dim, out_dim): super().__init__() self.linear = nn.Linear(in_dim, out_dim) def forward(self, x, adj): # x: (batch, num_nodes, in_dim), adj: (num_nodes, num_nodes) support = torch.einsum('ij,bjd->bid', adj, x) return self.linear(support) class STBlock(nn.Module): def __init__(self, hidden_dim): super().__init__() self.gconv = GraphConv(hidden_dim, hidden_dim) self.gru = nn.GRU(hidden_dim, hidden_dim, batch_first=True) def forward(self, x, adj): # x: (batch, seq_len, num_nodes, hidden_dim) b, t, n, d = x.shape out = [] for step in range(t): out.append(torch.relu(self.gconv(x[:, step], adj))) g = torch.stack(out, dim=1) # (b, t, n, d) g = g.permute(0, 2, 1, 3).reshape(b * n, t, d) h, _ = self.gru(g) # 时间维建模 return h[:, -1].reshape(b, n, d) # 取最后时刻隐状态这里的要点不在代码本身,而在于数据组织方式:输入永远是四维的(批次 × 时间 × 节点 × 特征),任何一步 reshape 出错都会静默地产出一个"能跑但全错"的模型。调试时空模型的第一课,就是打印每一步的张量形状。
工程落地绕不开的几个坑
模型精度只是入场券,真正上线时会碰到一堆论文里不提的问题。
缺失值处理要前置。检测器掉线是常态,简单的线性插值在早高峰会引入严重偏差。实践里常用"历史同时段均值 + 相邻路段回归"双层填补,并把缺失掩码作为特征喂给模型,让它自己学会"这条数据不可靠"。
节假日和事件要单独建模。春节、国庆的流量模式与平日完全不同,硬塞进一个模型只会互相拖累。常见做法是日历特征外加上下文门控,让模型在不同" regime"间切换;大型活动则靠人工维护的事件日历做显式修正。
评估指标别只看 MAPE。交通流里低流量时段(凌晨)的 MAPE 会爆表,把整体指标拉得很难看。行业里更常用 MAE + RMSE 分段看:高峰段单独评估,因为那才是调度决策真正关心的区间。
冷启动比精度更重要。新开通的路段没有历史数据,图网络的迁移能力有限。一个务