十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

短时交通流量预测实战:从数据清洗到模型选型与避坑指南

短时交通流量预测实战:从数据清洗到模型选型与避坑指南 简介这份资源面向交通工程、智能交通与数据分析方向的学习者提供短时交通流量预测的MATLAB实现范例帮助理解如何由历史流量数据估算未来几分钟至数小时的交通量适用于课程设计、算法入门与交通调度研究等场景。压缩包内共1个文件为m脚本类型整体约1KB体量轻便便于直接阅读与二次修改。目前已有340人学习下载具备一定参考热度。代码围绕数据预处理、特征工程、模型构建、训练优化、预测评估与可视化等环节展开读者可据此掌握异常值清洗、归一化与平滑处理、滞后特征提取以及ARIMA、灰色模型、支持向量机或神经网络等方法的选型思路并借助误差指标对比预测效果。整体结构紧凑适合作为短时交通预测的入门模板与排错参考。1. 短时交通流量预测从 yc.rar 这个关键词说起城市路口每 5 分钟刷新一次的流量数据看起来只是几条曲线但背后决定了信号配时、潮汐车道和诱导屏到底听谁的。短时交通流量预测要解决的就是这件事用过去若干个时间片的车流推未来 15 到 60 分钟每个路段会有多少车。它和宏观的年度交通规划不是一回事时间粒度更细、对实时性更敏感误差容忍度也更低。很多做交通流量预测的团队最后卡住的不是模型结构而是数据对齐、缺失值处理和评价口径这三件“脏活”。这篇笔记围绕短时交通预测的完整落地路径展开从数据长什么样、特征怎么造到模型怎么选、参数怎么调再到上线后怎么验证尽量把能抄的步骤和踩过的坑都写清楚。适合已经拿到一份交通流量数据、想把它跑成可用预测结果的工程师也适合正在做流量预测选型、需要判断方案边界的人。2. 短时交通流量预测的数据底座时间片、缺失值和特征工程短时交通预测和普通回归任务最大的区别在于数据是按时间片组织的而且天然带空间关联。常见的数据来源是线圈、地磁、卡口和浮动车采样周期从 30 秒到 15 分钟不等。做流量预测之前第一件事不是选模型而是把数据整理成「时间 × 路段」的二维矩阵并确认每个格子的含义一致。2.1 时间片对齐与缺失值处理真实数据里缺失几乎是必然的。设备掉线、通信中断、整点丢包都会造成空洞。直接删掉缺失行会让时间序列断裂直接填 0 又会把“没有数据”误当成“没有车流”这是短时交通预测里最常见的翻车点之一。我一般会按下面的顺序处理import pandas as pd import numpy as np # df: 原始数据列包含 timestamp, road_id, flow df[timestamp] pd.to_datetime(df[timestamp]) df df.sort_values([road_id, timestamp]) # 1. 重采样到统一时间片比如 5 分钟 df (df.set_index(timestamp) .groupby(road_id)[flow] .resample(5min) .mean() .reset_index()) # 2. 标记缺失重采样后为 NaN 的即为缺失 df[is_missing] df[flow].isna().astype(int) # 3. 短缺口用线性插值长缺口用同日同时段均值兜底 df[flow] (df.groupby(road_id)[flow] .transform(lambda s: s.interpolate(methodlinear, limit3))) # 4. 剩余长缺口用“同路段、同星期、同时刻”的历史均值填充 df[weekday] df[timestamp].dt.weekday df[slot] df[timestamp].dt.hour * 12 df[timestamp].dt.minute // 5 hist_mean (df.dropna(subset[flow]) .groupby([road_id, weekday, slot])[flow] .mean() .rename(hist_mean)) df df.merge(hist_mean, on[road_id, weekday, slot], howleft) df[flow] df[flow].fillna(df[hist_mean]) df[flow] df[flow].fillna(0)这段代码的逻辑是先统一时间粒度再区分“短缺口”和“长缺口”。limit3表示连续缺失不超过 3 个时间片才做线性插值超过就交给历史均值。参数上5min是最常用的短时预测粒度如果原始数据是 1 分钟也可以先聚到 5 分钟降低噪声。is_missing这个标记列不要丢后面做特征和评估时能帮你判断模型是不是在缺失段上虚高。提示填充后的流量值不要直接当成真实值参与误差统计评估时应把缺失段单独排除或加权否则指标会失真。2.2 短时交通预测的特征构造滞后、滑动窗口和时间编码短时交通流量预测的预测能力很大一部分来自特征而不是模型。交通流有强周期性和短时惯性滞后特征和滑动统计量是最稳的两类。# 滞后特征过去 1、2、3、6、12 个时间片的流量 for lag in [1, 2, 3, 6, 12]: df[flag_{lag}] df.groupby(road_id)[flow].shift(lag) # 滑动窗口统计过去 6 个时间片的均值和标准差 df[roll_mean_6] (df.groupby(road_id)[flow] .transform(lambda s: s.shift(1).rolling(6).mean())) df[roll_std_6] (df.groupby(road_id)[flow] .transform(lambda s: s.shift(1).rolling(6).std())) # 时间编码小时和星期几做周期编码 df[hour] df[timestamp].dt.hour df[sin_hour] np.sin(2 * np.pi * df[hour] / 24) df[cos_hour] np.cos(2 * np.pi * df[hour] / 24) df[sin_week] np.sin(2 * np.pi * df[weekday] / 7) df[cos_week] np.cos(2 * np.pi * df[weekday] / 7)shift(1)是关键它保证滑动统计量只用预测时刻之前的数据避免把未来信息泄漏进特征。lag_1到lag_12覆盖了过去 1 小时内的惯性roll_mean_6和roll_std_6分别刻画近期水平和波动。周期编码用 sin/cos 而不是直接塞 0 到 23是为了让 23 点和 0 点在特征空间里相邻这一点在短时交通预测里对早晚高峰的衔接很关键。2.3 空间关联特征相邻路段怎么进模型交通流量预测如果只按单路段建模会丢掉上游路口的汇入影响。常见做法有两种一是把相邻路段的同期流量作为额外特征拼进来二是用图结构建模把路段当节点、连接关系当边。# 假设有邻接表 adj: {road_id: [neighbor_id, ...]} neighbor_flow [] for _, row in df.iterrows(): neighbors adj.get(row[road_id], []) vals df[(df[road_id].isin(neighbors)) (df[timestamp] row[timestamp])][flow] neighbor_flow.append(vals.mean() if len(vals) 0 else np.nan) df[neighbor_flow_mean] neighbor_flow df[neighbor_flow_mean] df[neighbor_flow_mean].fillna(df[flow])这段是简化版的空间特征拼接适合路段数量不大、邻接关系明确的场景。如果路段上千逐行遍历会很慢应该改成按时间片做 merge。参数上邻接表的质量直接决定空间特征有没有用如果邻接关系是拍脑袋定的宁可不加否则会引入噪声。3. 短时交通流量预测的模型选型从 LightGBM 到时空图网络数据整理好之后模型选型是第二个分水岭。短时交通预测的模型大致分三代统计模型、树模型、深度学习时空模型。不是越新越好而是要看数据量、路段数和上线延迟要求。3.1 基线模型历史均值和 ARIMA 到底还能不能用历史均值同星期同时刻均值是最容易被低估的基线。很多论文里的复杂模型如果没跑赢历史均值基本可以判定特征或评估有问题。ARIMA 适合单路段、平稳性较好的序列但短时交通流在早晚高峰切换时非平稳明显ARIMA 的差分阶数很难固定。我一般会先跑两个基线# 基线1同星期同时刻历史均值 baseline_ha df.groupby([road_id, weekday, slot])[flow].transform(mean) # 基线2上一时间片流量persistence baseline_persist df.groupby(road_id)[flow].shift(1) # 评估 from sklearn.metrics import mean_absolute_error mask df[flow].notna() baseline_persist.notna() print(HA MAE:, mean_absolute_error(df.loc[mask, flow], baseline_ha[mask])) print(Persistence MAE:, mean_absolute_error(df.loc[mask, flow], baseline_persist[mask]))persistence基线在短时预测里往往强得离谱因为 5 分钟粒度下流量变化有限。如果你的模型连 persistence 都赢不了先别急着换网络结构回去查特征泄漏和评估口径。参数上MAE 比 RMSE 更抗极端值短时交通预测里建议两个都看但以 MAE 为主。3.2 LightGBM 做短时交通预测参数怎么设、特征怎么排在路段数量中等、特征工程到位的情况下LightGBM 是性价比最高的选择。它训练快、对缺失不敏感、特征重要性可解释适合快速迭代。import lightgbm as lgb from sklearn.model_selection import TimeSeriesSplit features [lag_1, lag_2, lag_3, lag_6, lag_12, roll_mean_6, roll_std_6, sin_hour, cos_hour, sin_week, cos_week, neighbor_flow_mean] target flow # 按时间切分不能随机切 tscv TimeSeriesSplit(n_splits5) params { objective: regression, metric: mae, learning_rate: 0.05, num_leaves: 63, min_data_in_leaf: 50, feature_fraction: 0.8, bagging_fraction: 0.8, bagging_freq: 1, verbose: -1 } for train_idx, val_idx in tscv.split(df): train df.iloc[train_idx] val df.iloc[val_idx] dtrain lgb.Dataset(train[features], train[target]) dval lgb.Dataset(val[features], val[target]) model lgb.train(params, dtrain, num_boost_round1000, valid_sets[dval], callbacks[lgb.early_stopping(50)])TimeSeriesSplit是硬性要求短时交通预测绝不能随机划分训练验证集否则滞后特征会把未来信息带进来指标好看但上线就崩。num_leaves控制在 63 左右再大容易过拟合到个别路段的异常流量。min_data_in_leaf50是为了防止模型记住某个路段某天的偶发拥堵。early_stopping(50)配合learning_rate0.05一般 300 到 600 轮收敛。特征重要性排出来之后通常lag_1、roll_mean_6、sin_hour排前三。如果neighbor_flow_mean重要性极低说明邻接表质量不行可以考虑去掉。3.3 时空图网络什么时候值得上深度学习当路段数量超过几百、且空间关联明显比如城市主干路网时空图网络如 STGCN、Graph WaveNet 这类结构会比 LightGBM 有明显提升。代价是训练成本高、调参复杂、上线推理延迟大。常见做法是先用 LightGBM 跑出基线确认特征和评估没问题再上时空图模型做对比。如果提升不到 5%不建议为了“用深度学习”而换。参数上图网络的邻接矩阵构造方式距离阈值、相关性阈值、连通性比网络层数更影响结果。输入窗口一般取 12 个时间片1 小时输出 1 到 12 个时间片取决于你要预测未来多长。注意时空图模型对缺失值比树模型敏感输入前必须把缺失处理干净否则图卷积会把缺失当成真实低流量传播到邻居。4. 短时交通流量预测的避坑与排查那些指标好看上线就崩的原因这一章集中写短时交通预测里最常见的几类问题每条按现象、原因、解决来写。这些问题在离线评估阶段往往看不出来上线后才暴露。4.1 现象离线 MAE 很低上线后误差翻倍原因通常有三个一是训练验证集随机划分导致滞后特征泄漏二是上线时输入特征的计算逻辑和训练时不一致比如训练用shift(1)上线却用了当前时刻三是数据分布漂移比如训练集是疫情前上线是疫情后。解决强制用时间切分把特征计算封装成同一个函数训练和推理共用上线后持续监控输入特征的分布一旦偏移超过阈值就触发重训。4.2 现象模型在早晚高峰误差特别大原因是高峰时段流量变化剧烈滞后特征的惯性假设失效而模型在平峰样本上占多数优化时被平峰主导。解决对高峰样本加权或者单独训练高峰模型引入更多实时特征比如上游路段的当前流量评估时按平峰/高峰分组看 MAE而不是只看总体。4.3 现象某些路段预测值长期偏低或偏高原因是这些路段的流量量级和其他路段差异大模型在统一损失下偏向大流量路段。解决对流量做 per-road 标准化或者用相对误差检查这些路段是否有特殊事件学校、医院、施工没进特征。4.4 现象缺失段填充后模型在缺失段预测异常原因是填充值被当成真实值训练模型学到了填充模式的伪规律。解决把is_missing作为特征输入对缺失段样本降权或排除填充方法在训练和推理时保持一致。4.5 现象模型上线后推理延迟高赶不上 5 分钟刷新原因是时空图模型参数量大或者特征计算里有逐行遍历。解决把特征计算改成向量化模型做量化或蒸馏如果延迟实在压不下来退回 LightGBM短时交通预测里 5 分钟粒度下树模型通常够用。5. 短时交通流量预测的验证与迭代怎么判断一个方案值不值得继续投入模型跑通只是开始真正决定这个方向值不值得做的是验证和迭代闭环。短时交通预测的验证不能只看一个 MAE要分场景、分时段、分路段看还要和业务指标挂钩。5.1 分层评估按时段、路段、流量量级拆开看def stratified_eval(df, y_true, y_pred): df df.copy() df[err] np.abs(y_true - y_pred) # 按时段 df[period] pd.cut(df[hour], bins[-1, 6, 9, 16, 19, 23], labels[夜间, 早高峰, 平峰, 晚高峰, 夜间2]) print(df.groupby(period)[err].mean()) # 按流量量级 df[level] pd.qcut(df[flow], q4, labels[低, 中低, 中高, 高]) print(df.groupby(level)[err].mean())这段代码把误差拆成时段和流量量级两个维度。如果早高峰误差是平峰的 2 倍以上说明模型对突变场景覆盖不足如果高流量段误差绝对值大但相对误差小属于正常。参数上q4是四分位也可以按业务阈值分。5.2 滚动重训与在线更新多久重训一次短时交通预测的数据分布会随季节、事件、路网变化漂移。常见做法是每天用最近 30 天数据重训一次或者每周全量重训加每日增量更新。如果路段有施工、新开通要触发即时重训。判断是否需要重训的一个简单信号连续 3 天验证集 MAE 比基线高 10% 以上。不要等业务方投诉才动手。5.3 一个具体技巧用残差修正补高峰如果主模型在高峰段系统性偏低可以训练一个残差模型专门修正。做法是把主模型在高峰段的残差作为目标用同样的特征再训一个 LightGBM预测时把两个结果相加。# 主模型预测 df[pred_main] model.predict(df[features]) # 残差 df[residual] df[flow] - df[pred_main] # 只在高峰段训练残差模型 peak_mask df[hour].between(7, 9) | df[hour].between(17, 19) res_model lgb.train(params, lgb.Dataset(df.loc[peak_mask, features], df.loc[peak_mask, residual]), num_boost_round300) # 最终预测 df[pred_final] df[pred_main] res_model.predict(df[features])这个技巧在多个短时交通预测项目里都能把高峰 MAE 压下来 5% 到 10%。注意残差模型只在高峰段训练平峰段不要用否则会把平峰的噪声也修正进去。我自己的习惯是任何短时交通预测方案先跑通 persistence 和历史均值两个基线再上 LightGBM最后才考虑时空图网络。上线后第一周每天看分层误差连续三天不达标就回滚重训。这套流程不新鲜但能避开大部分“离线好看上线崩”的坑。希望帮到你。本文还有配套的精品资源点击获取
返回列表