简介:这份资源面向交通工程、智能交通与数据分析方向的学习者与研究者,聚焦短时交通流量预测这一城市交通管理中的核心问题,提供一份可直接运行的MATLAB实现范例。压缩包内共1个文件,为m脚本类型,包体约1KB,体量轻巧,便于快速阅读与二次修改。脚本围绕历史流量数据展开,涵盖数据预处理与归一化、滞后值与高峰时段等特征提取、预测模型构建、参数训练优化、预测结果评估以及实际值与预测值对比可视化等环节,完整呈现从数据到预测的建模链路。目前已有340人学习,适合希望理解短时预测建模流程、掌握MATLAB脚本写法,或以此为起点开展交通流量预测实验的读者参考借鉴。
1. 短时交通流量预测的 yc.m 脚本:一个 MATLAB 老兵的拆包记录
城市快速路上每 5 分钟更新一次的流量数据,看着像一条平滑曲线,实际全是毛刺。做短时交通预测的人最怕两件事:一是模型跑得比数据更新还慢,二是预测值在高峰期直接躺平。我手里这个yc.rar压缩包,解出来就一个yc.m,MATLAB 脚本,没有花哨的工程结构,也没有 README。它干的事很明确——拿历史流量序列,预测未来几个时间片的流量。适合谁?手头有线圈或卡口数据、想快速验证 ARIMA 或类似时序模型、又不愿意从零搭框架的交通工程从业者。它不解决数据采集,也不做实时流处理,但把「数据进来、预测出去」这条最短路径跑通了。下面按我实际复现的顺序拆。
2. 从 yc.m 看短时预测的骨架:数据预处理与特征工程怎么落
2.1 脚本入口与数据格式的硬约定
yc.m是脚本不是函数,意味着它依赖工作区变量。我拿到手第一件事是看它读什么。常见做法是load一个.mat文件,里面存着单列流量序列,时间间隔固定。脚本里通常会有类似这样的段落:
% 假设数据文件为 traffic_data.mat,变量名为 flow load('traffic_data.mat'); raw = flow(:); % 强制列向量,防止行向量导致维度错位 dt = 5; % 采样间隔,单位分钟,常见有 5/15/30逻辑说明:flow(:)这个操作看着多余,但血泪经验是,很多传感器导出的数据是行向量,后面做差分或构造滞后项时,MATLAB 的lagmatrix或手动索引会直接报维度不匹配。参数dt不参与计算,但决定了你预测步长对应的真实时间——预测 3 步就是未来 15 分钟。如果脚本里没有显式定义dt,你得自己加,否则评估时没法把误差映射回时间维度。
2.2 异常值清洗与平滑:别让一个坏点毁掉整段预测
原始流量序列里,线圈故障会导致连续几个时间片为 0 或突增到离谱值。yc.m里我看到的处理方式比较朴素,常见做法是 3σ 原则加中值滤波:
mu = mean(raw); sigma = std(raw); outlier_idx = abs(raw - mu) > 3 * sigma; raw(outlier_idx) = median(raw); % 用全局中位数替换,简单但有效 smooth_flow = movmedian(raw, 3); % 窗口 3 的中值滤波,抑制脉冲噪声逻辑说明:3σ筛出来的点未必都是故障,高峰期尾部也可能被误判,所以替换值用中位数而不是均值,避免被极端值拉偏。movmedian窗口选 3 是因为短时预测里超过 3 个时间片的平滑会引入相位滞后,预测值会系统性晚于实际峰值。参数怎么改?如果数据噪声大,窗口可以到 5,但要做滞后补偿;如果数据干净,这步可以跳过,直接进特征工程。
2.3 特征工程:滞后项与时间哑变量
短时流量预测的核心特征是滞后流量。yc.m里构造滞后矩阵的代码通常长这样:
max_lag = 12; % 滞后 12 步,对应 1 小时历史 X = lagmatrix(smooth_flow, 1:max_lag); X = X(max_lag+1:end, :); % 去掉前 max_lag 行 NaN Y = smooth_flow(max_lag+1:end); % 对齐目标值逻辑说明:max_lag=12不是拍脑袋,5 分钟采样下 12 步刚好覆盖一个完整小时的周期特征。如果dt=15,滞后 4 步就够一小时,但脚本里写死 12 的话,你会引入过多冗余特征,训练变慢且容易过拟合。我一般会改成max_lag = round(60/dt)。另外,yc.m可能还加了时间哑变量,比如早晚高峰标记:
hour_idx = mod((0:length(Y)-1)' * dt / 60, 24); is_peak = (hour_idx >= 7 & hour_idx <= 9) | (hour_idx >= 17 & hour_idx <= 19); X = [X, double(is_peak)];这个特征对短时预测提升明显,尤其是早晚高峰流量突变时段。但注意,如果训练数据里高峰时段样本少,这个哑变量系数会不稳定,常见做法是至少保证每个类别有 200 个以上样本。
3. 模型训练与预测:ARIMA 和神经网络在 yc.m 里的取舍
3.1 ARIMA 建模:定阶、估计与残差诊断
yc.m如果走统计模型路线,大概率是 ARIMA。MATLAB 里用arima函数:
model = arima(2,1,2); % AR=2, 差分=1, MA=2 fit = estimate(model, smooth_flow); [forecast, ~] = forecast(fit, 3, 'Y0', smooth_flow);逻辑说明:(2,1,2)这个阶数不是随便写的。短时流量序列一般一阶差分后平稳,AR 和 MA 阶数看 ACF/PACF 截尾拖尾。我见过yc.m里用autocorr和parcorr画图后手动定阶,也有用aicbic循环搜的。参数怎么改?如果预测步长超过 3,MA 阶数要适当加大,否则预测值会快速衰减到均值。残差诊断别跳过:
res = infer(fit, smooth_flow); lbqtest(res, 'Lags', 10); % Ljung-Box 检验,p 值小于 0.05 说明残差还有自相关如果残差没通过白噪声检验,说明模型没榨干信息,得加阶或换模型。
3.2 神经网络方案:输入输出维度与训练参数
如果yc.m用的是 BP 神经网络或 ELM,代码结构会变成:
net = feedforwardnet(10); % 单隐层 10 个神经元 net.trainParam.epochs = 1000; net.trainParam.lr = 0.01; net.divideParam.trainRatio = 0.7; net.divideParam.valRatio = 0.15; net.divideParam.testRatio = 0.15; [net, tr] = train(net, X', Y'); Y_pred = net(X_test');逻辑说明:X'转置是因为 MATLAB 神经网络工具箱默认列是样本、行是特征。隐层 10 个神经元对几百到几千条短时流量数据够用,再多容易过拟合。学习率 0.01 是保守值,如果训练误差震荡不降,降到 0.001;如果收敛太慢,升到 0.05 但别超过。数据划分比例 70/15/15 是常见做法,但时间序列不能随机打乱,divideParam默认随机划分会引入未来信息泄露,我一般手动按时间顺序切:
n = size(X,1); train_idx = 1:floor(0.7*n); val_idx = floor(0.7*n)+1:floor(0.85*n); test_idx = floor(0.85*n)+1:n;这个坑很隐蔽,随机划分下验证集误差会虚低,上线后直接翻车。
3.3 评估指标:MSE、MAE 和 MAPE 的适用边界
yc.m里评估部分通常算三个指标:
mse = mean((Y_test - Y_pred).^2); mae = mean(abs(Y_test - Y_pred)); mape = mean(abs((Y_test - Y_pred) ./ Y_test)) * 100;逻辑说明:MSE 对大误差敏感,适合关注峰值预测;MAE 更稳健,反映平均偏差;MAPE 有量纲无关的优点,但流量接近 0 时会爆炸——凌晨时段流量个位数,MAPE 可能几百。我一般主看 MAE,辅以 MSE 看峰值捕捉能力。如果yc.m只输出 MSE,建议自己补上 MAE,否则没法判断模型在低流量时段的实际表现。
4. 避坑与排查:yc.m 复现时最容易翻车的五个点
4.1 现象:预测曲线整体平移,峰值对不上
原因:平滑窗口过大或差分阶数不对,导致相位滞后。movmedian窗口 5 以上、或者 ARIMA 差分阶数设为 2 都会这样。 解决:平滑窗口降到 3,差分阶数用ndiffs函数确认,别手动拍。
4.2 现象:训练误差很低,测试集一塌糊涂
原因:时间序列随机划分导致未来信息泄露,或者滞后特征里混入了目标值当期的信息。 解决:按时间顺序切分训练/验证/测试集,检查lagmatrix的滞后起点是否从 1 开始,别把t时刻的值放进t时刻的特征里。
4.3 现象:MAPE 出现 Inf 或 NaN
原因:测试集里有流量为 0 的时间片,除零导致。 解决:加一个极小值eps或者改用 SMAPE:
smape = mean(2*abs(Y_pred - Y_test) ./ (abs(Y_pred) + abs(Y_test) + eps)) * 100;4.4 现象:神经网络训练结果每次都不一样
原因:权重随机初始化,且数据未归一化。 解决:固定随机种子rng(42),并对输入输出做归一化:
[Xn, ps] = mapminmax(X', 0, 1); [Yn, ps_y] = mapminmax(Y', 0, 1); % 预测后反归一化 Y_pred = mapminmax('reverse', Y_pred_n, ps_y);4.5 现象:脚本跑完不报错但预测值全是常数
原因:ARIMA 模型 MA 阶数过大导致预测快速回归均值,或者神经网络隐层神经元太少欠拟合。 解决:检查 ARIMA 的forecast输出是否在几步后持平,是的话降 MA 阶数;神经网络隐层加到 15 再试。
5. 进阶技巧:把 yc.m 改成滚动预测并验证真实误差
yc.m默认是一次性划分训练测试,但短时预测的真实场景是滚动更新。我习惯把它改成滚动窗口验证,每预测一步就把真实值并入历史,重新训练或至少更新输入。这样得到的误差才是上线后的误差。核心改动如下:
window_size = 500; % 滚动窗口长度,约 1.7 天 5 分钟数据 n_steps = 50; % 滚动预测 50 步 errors = zeros(n_steps, 1); for i = 1:n_steps train_data = smooth_flow(i : i+window_size-1); test_point = smooth_flow(i+window_size); % 重新定阶或沿用固定阶数 model = arima(2,1,2); fit = estimate(model, train_data, 'Display', 'off'); yhat = forecast(fit, 1, 'Y0', train_data); errors(i) = abs(yhat - test_point); end mae_rolling = mean(errors);逻辑说明:window_size=500是经验值,太短模型不稳,太长跟不上流量模式变化。n_steps=50对应 250 分钟,覆盖一个早高峰。每步重新estimate计算量大,实际部署可以固定模型参数只更新输入,但验证阶段建议全量重估,否则低估误差。跑完这个循环,你会得到一个比单次划分更诚实的 MAE。如果滚动 MAE 比单次测试 MAE 高 30% 以上,说明模型对数据分布变化敏感,得加自适应机制,比如检测到误差连续 5 步超标就重新定阶。
从那以后我每次拿到这种单文件 MATLAB 脚本,都强制走一遍滚动验证,不再信单次划分的指标。希望帮到你。
本文还有配套的精品资源,点击获取