资讯详情

资讯详情

基于MATLAB的交通流量预测:AR、GM(1,1)与KNN实现对比

简介面向Matlab算法学习与交通流量预测场景这套仿真包分别基于AR、GM11与KNN三种模型实现预测对比内容覆盖数据读取、模型构建、结果可视化等完整流程适合本硕博及科研人员用于算法编程练习和课程设计。压缩包共19个文件整体约9MB其中8个M脚本为各模型及主运行程序1个xlsx提供交通流量样例数据9张jpg保存各模型预测结果图另有1段avi操作录像辅助上手结构按模型分区便于对照调试。资源提供Runme相关脚本作为统一启动入口并强调需在Matlab 2021a或更高版本中于工程根目录运行录像演示了具体执行步骤可有效降低复现门槛。目前已有611人学习下载适合希望系统掌握AR、GM11、KNN建模差异并进行交通数据预测实验的教研用户。1. 三个模型预测交通流量为什么选AR、GM11和KNN早上八点的城市快速路流量从每分钟80辆往上冲你手里有过去一周的断面检测数据今天要不要提前限流、诱导屏该显示什么内容需要在十几分钟内给出判断。这类问题落到建模上AR、GM(1,1)、KNN是三种思路完全不同的落点AR把流量看成自身历史的线性延伸GM(1,1)在小样本下用指数曲线逼近趋势KNN直接到历史库里找“长得像”的日子做加权平均。三者都不是为交通流量定制的方法但组合起来恰好覆盖了“有惯性、有趋势、有相似日模式”这几类典型路况。在MATLAB里把它们依次跑通并对比误差也是交通仿真课设、科研预实验和智能交通入门最常见的一步。难点从来不在模型本身而在数据怎么喂、参数怎么定、结果怎么判。2. AR、GM11、KNN的建模逻辑与适用边界2.1 AR自回归模型流量是它自己历史的函数AR模型的全称是Autoregressive Model核心假设是当前时刻的流量可以被过去若干个时刻的流量线性表示y(t) c φ₁y(t-1) φ₂y(t-2) … φ_p y(t-p) ε(t)这里p是模型阶数φ是自回归系数ε是白噪声。对交通流来说这个假设天然成立前15分钟的车流状态和现在的速度、密度高度相关尤其在城市快速路和高速断面流量序列有明显的短时记忆。用最小二乘估计φ时本质上是在拟合“历史流量到当前流量”的映射关系。使用AR模型前必须处理平稳性问题。交通流量带有明显的早晚高峰周期原始序列直接建模效果很差常见做法是先做一阶差分MATLAB里一行代码就行flow_diff diff(flow, 1)或者用h adftest(flow)做ADF单位根检验。注意adftest属于Econometrics Toolbox没装的话就观察autocorr(flow_diff)是否快速衰减到置信带内特征和差分序列基本等价。AR模型的计算量极小训练和预测都是毫秒级而且系数有明确含义——φ₁越大说明上一时刻的流量对当前影响越强。它的短板在于只能捕捉线性关系遇到事故、管制导致的突变预测值会明显滞后。2.2 GM(1,1)灰色预测小样本下的指数增长假设GM(1,1)是灰色系统理论里最常用的预测模型全称是单变量一阶灰色模型适用于数据量少、趋势明显、波动不大的场景。交通流量检测器刚部署、历史数据不足30个点时AR和KNN都凑不够有效样本GM(1,1)反而能用4到10个点建出模型来。它的建模逻辑分四步。第一步对原始序列做累加生成AGO把波动大的原始序列变成单调递增序列x₁(k) Σ x₀(i)i从1到k第二步用累加序列构造紧邻均值序列 z₁(k)0.5(x₁(k)x₁(k1))第三步建立一阶线性微分方程 dx₁/dt a·x₁ b其中a称为发展系数b称为灰作用量。通过最小二乘解出[a,b]得到时间响应式x₁_hat(t) (x₀(1) - b/a)·e^(−a(t−1)) b/a最后做累减还原IAGO即 x₀_hat(k) x₁_hat(k) − x₁_hat(k−1)得到原始量纲的预测值。整个过程不依赖概率统计的大样本假设这是灰色模型最大的优势。GM(1,1)的局限也很明显它假设数据近似指数增长交通流量在平峰期接近常数、高峰期类似S曲线直接套用会失真。所以实践中GM(1,1)通常只做短期预测预测步数一般不要超过训练数据长度的一半否则指数项e^(−a(t−1))会很快发散这也是检索里常见“仿真发散”的来源之一。2.3 KNN回归从相似历史里找答案KNN被大多数人熟悉的是分类用法但交通流量预测属于回归任务做法稍有不同给定当前时刻的特征向量在历史样本中找出K个欧氏距离最近的样本用它们的流量值做平均或加权平均作为预测值。KNN的核心在特征工程。我一般会构造这样一组特征当前时刻的小时数刻画早高峰晚高峰、星期几区分工作日和周末、前3到6个时段的流量值刻画短时惯性以及昨天同时段的流量刻画日周期。特征选得好KNN的效果往往比AR和灰色模型都稳。距离度量默认用欧氏距离但流量数值范围可能相差很大比如lag特征量级是60200hour是023直接把两者拼在一起算距离hour几乎不起作用。所以建模前必须对特征做标准化常见做法是z-score归一化。KNN没有显式的训练过程预测时要把测试样本逐一和历史样本比对历史库到几千条以上时计算量就开始明显上涨这时候用MATLAB自带的knnsearch代替手写循环会快得多。2.4 三个模型的选型对比对比项ARGM(1,1)KNN回归模型类型参数化线性灰色差分方程非参数邻近最小数据量通常30个点以上4个点即可建模取决于历史库规模平稳性要求高需差分/去趋势低累加生成降波动低特征需标准化多步预测误差累积建议滚动短步稳定长步发散每步重找邻相对稳对异常值敏感度敏感较敏感不敏感计算成本极低极低预测阶段较高选型没有绝对优劣关键看手头数据量、预测时长和算力。数据充足、要跑上百步预测AR和KNN优先数据只有十来个点、只预测未来几小时GM(1,1)是唯一能出结果的。下面把它们在MATLAB里逐一实现。3. MATLAB仿真实现从数据清洗到三模型出图3.1 数据准备清洗、补缺、划分训练测试集仿真第一步是拿到干净的时间序列。原始检测数据通常存在缺失和毛刺缺失值用线性插值补异常值用3σ准则剔除。下面这段代码可以直接跑通%% 读取检测器流量数据两列时间戳流量 data readmatrix(traffic_flow.csv); timestamps data(:,1); flow data(:,2); % 缺失值线性插值补全 flow fillmissing(flow, linear); % 3σ 准则剔除异常尖峰超过均值3倍标准差的点用邻域均值替代 mu mean(flow); sigma std(flow); outlier_idx abs(flow - mu) 3 * sigma; flow(outlier_idx) movmean(flow, 24, omitnan);代码先检查数据列格式fillmissing只对NaN起作用所以导入后要用ismissing(flow)确认缺失标记被读成了NaN而不是0。3σ准则对突发事故引起的真实流量激增会误删因此替换用的是滑动平均。划分数据集时有一个容易忽略的规矩交通流量是时间序列不能随机打乱再划分必须按时间顺序切。一般做法是前70%做训练、中间15%做验证调参、最后15%做测试对比。验证集和测试集长度至少覆盖一个完整日周期否则高峰和平峰样本不均衡误差指标会失真。3.2 AR模型平稳性检验、定阶、递推预测3.2.1 先检验平稳性再做差分%% ADF检验h1表示拒绝单位根假设序列平稳 h adftest(flow_train); %% 不平稳则做一阶差分并观察ACF是否快速衰减 if h 0 flow_train diff(flow_train); disp(序列非平稳已做一阶差分); end autocorr(flow_train); % 看相关函数是否拖尾衰减ADF检验需要Econometrics Toolbox没有这个工具箱时看autocorr的图形表现即可差分后若前两阶相关系数明显后面迅速落入置信带就认为序列可用。注意差分会损失一个样本点差分后的预测结果还原时要做累加。3.2.2 用最小二乘估计AR系数并AIC定阶不依赖任何工具箱的自写AR估计函数如下function [phi, ar_fit] ar_ols(y, p) % y: 训练序列列向量p: 自回归阶数 % 返回系数phi(第一项是常数项)和样本内拟合值 n length(y); X ones(n - p, p 1); % 第一列全1对应常数项 for k 1:p X(:, k1) y(p - k 1 : n - k); % 第k个滞后项下标对齐 end Y y(p1 : n); phi X \ Y; % 最小二乘求解\ 比 inv 更稳 ar_fit X * phi; end这段的关键在滞后项下标第i个训练样本对应预测 y(pi)其滞后k项是 y(pi−k)所以整体切片是y(p−k1 : n−k)这个下标关系写错会导致系数估计全部偏离。阶数p不靠拍脑袋用AIC准则网格搜索max_p 12; aic zeros(max_p, 1); for p 1:max_p [~, ar_fit] ar_ols(flow_train, p); resid flow_train(p1:end) - ar_fit; n_resid length(resid); sigma2 sum(resid.^2) / n_resid; aic(p) n_resid * log(sigma2) 2 * (p1); % 惩罚项随阶数增大 end [~, best_p] min(aic);AIC在拟合精度和模型复杂度之间取平衡交通流量数据上p取3到8比较常见p过大容易把噪声也拟合进去多步递推时误差呈指数放大。3.2.3 递推预测未来m步function y_future ar_predict(y, phi, p, m) % 用最近p个观测递推预测未来m步 y_hist y(end - p 1 : end); % 取训练集末尾p个点 y_future zeros(m, 1); for t 1:m y_future(t) phi(1) sum(phi(2:end) .* y_hist(end:-1:end-p1)); y_hist [y_hist(2:end); y_future(t)]; % 用预测值滚动更新窗口 end end递推的本质是把上一步的预测值当作已知历史继续往后推所以步数越多误差累积越严重。这个函数后面做滚动预测时还会复用。3.3 GM(1,1)模型累加生成、参数估计、累减还原自包含的GM(1,1)预测函数输入原始序列和预测步数输出未来预测值以及发展系数a、灰作用量bfunction [forecast, a, b] gm11_forecast(y, n_predict) % y: 原始观测序列(至少4个点)n_predict: 未来预测步数 x0 y(:); n length(x0); % 1. 一次累加生成(AGO)降低随机波动 x1 cumsum(x0); % 2. 紧邻均值序列 z1 z1 (x1(1:end-1) x1(2:end)) / 2; % 3. 最小二乘估计参数 [a, b] B [-z1(:), ones(n-1, 1)]; Yn x0(2:end); ab B \ Yn; a ab(1); b ab(2); % 4. 累加序列的时间响应式 t 1 : n n_predict; x1_pred (x0(1) - b/a) .* exp(-a .* (t - 1)) b/a; % 5. 累减还原(IAGO)取未来n_predict个值 x0_pred [x0(1), diff(x1_pred)]; forecast x0_pred(n1 : nn_predict); end参数a的符号决定了预测轨迹的走向a为负数时时间响应式里的指数项随t增大而爆炸对应“仿真发散”这一常见问题。调用方式和结果检查%% 用最近6个点训练预测未来3个点 train_gm flow_train(end-5:end); [forecast_gm, a, b] gm11_forecast(train_gm, 3); fprintf(发展系数 a%.4f, 灰作用量 b%.4f\n, a, b);训练数据长度不是越多越好GM(1,1)对近期的敏感性高于远期数据窗口拖太长反而让模型被旧趋势牵制。常见做法是取最近5到10个点。后验差检验可以量化模型效果C值等于残差标准差除以原始序列标准差resid_gm train_gm(2:end) - ... % 样本内残差 (x0_pred_fitted(2:end)); % 用同样的还原逻辑算拟合值 C std(resid_gm) / std(train_gm);C值越小说明残差波动相对原始序列越小判别标准是C 0.35 优0.35~0.5 合格0.5~0.65 勉强大于0.65 不合格。我一般会把这个检验写进建模脚本开头不合格直接停止不进入后续对比。3.4 KNN回归特征矩阵、标准化、最近邻搜索3.4.1 特征构造KNN的特征设计决定模型上限。交通流量预测常用下面这组特征特征列含义说明hour当前时刻小时数(0-23)刻画日内早晚高峰周期dow星期几(1-7)区分工作日与周末模式lag1~lagL前L个时段的流量L取3到6对应15到30分钟惯性prev_day昨天同时段流量刻画日周期强周期场景加分项特征矩阵构造代码L 4; % 滞后阶数 X []; Y []; for i L1 : length(flow) x_row [hour_of_day(i), day_of_week(i), ... % 时间特征 flow(i-L:i-1), ... % 前L个时刻流量 flow(i-96)]; % 昨天同时段(假设15分钟粒度) X [X; x_row]; Y [Y; flow(i)]; end滞后阶数L和时间粒度强相关15分钟粒度取4到65分钟粒度取6到12。昨天同时段那一列的下标要根据数据间隔换算96对应15分钟×24小时。3.4.2 标准化与KNN回归主函数特征标准化必须只在训练集上计算均值和标准差再用同一组参数变换验证集和测试集否则会引入未来信息这个错误在KNN场景下尤其致命[mu_X, sigma_X] mean_and_std_of_train(X_train); % 训练集的统计量 X_train_std (X_train - mu_X) ./ sigma_X; X_test_std (X_test - mu_X) ./ sigma_X;KNN回归主函数用欧氏距离找近邻返回平均流量function y_pred knn_forecast(X_train, y_train, X_test, K) n_test size(X_test, 1); y_pred zeros(n_test, 1); for i 1:n_test dist sqrt(sum((X_train - X_test(i,:)).^2, 2)); % 欧氏距离 [~, idx] sort(dist); % 前K个近邻的流量平均可选距离加权 weights 1 ./ (dist(idx(1:K)) eps); y_pred(i) sum(weights .* y_train(idx(1:K))) / sum(weights); end end用距离倒数加权代替简单平均能提升精度近邻越近权重越大。历史库超过2000条时把循环里的距离计算换成[idx, dist] knnsearch(X_train, X_test(i,:), K, K)速度会快一个量级。4. 预测效果评估误差指标、参数整定与典型坑4.1 MAE、RMSE、MAPE三个指标怎么算三个模型的预测结果放一起对比先定义统一的误差评估函数function [mae, rmse, mape] eval_metrics(y_true, y_pred) e y_true - y_pred; mae mean(abs(e)); rmse sqrt(mean(e.^2)); valid y_true 0; % MAPE防除零 mape mean(abs(e(valid) ./ y_true(valid))) * 100; end指标数学含义特点MAE平均绝对误差单位与流量一致直观不受正负抵消影响RMSE均方根误差对大偏差敏感能放大极端误差MAPE平均绝对百分比误差无量纲适合跨场景比较MAPE在流量接近于零的夜间时段会极度失真哪怕只差1辆车也是百分之百的误差所以计算前要做掩码过滤。报告中一般三者都给侧重看RMSE和MAPE如果RMSE明显大于MAE说明模型在大流量尖峰处错得离谱。4.2 三个模型的关键参数怎么定AR模型的阶数上限不要设置太高对15分钟粒度数据12阶以内足够跨度超过3小时的历史影响已经微弱。AIC选择的阶数如果恰好等于上限值说明搜索范围不够要加大上限重跑。GM(1,1)的训练窗口长度是最值得调的参数。窗口短则拟合残差小但趋势捕捉不稳窗口长则模型迟钝。常见做法是用最近6到10个点做训练用倒数第二个点做单步验证把窗口长度做成参数循环扫描选验证误差最小的。KNN的K值用验证集网格搜索写成一个循环就能跑K_list 1:2:21; val_rmse zeros(length(K_list), 1); for i 1:length(K_list) pred_val knn_forecast(X_train_std, y_train, X_val_std, K_list(i)); val_rmse(i) sqrt(mean((y_val - pred_val).^2)); end [~, best_idx] min(val_rmse); best_K K_list(best_idx);K过小1到3模型方差大K过大超过30会把差异很大的历史样本拉进来预测曲线趋于平坦。交通流量数据上K取5到15是常见区间。4.3 不同路况下三个模型谁更准同样是误差对比分场景看更有工程意义。工作日早晚高峰流量曲线陡峭AR凭借短时记忆优势往往误差最小节假日和历史模式高度相似的日子KNN的相似日匹配效果突出数据量少、趋势相对平稳的夜间时段GM(1,1)能给出比AR更平滑的预测。突发场景下三个模型各有各的坑。AR对突变的响应天然滞后因为回归结构只吃历史值KNN在历史库中找不到包含类似事故的样本会把事故时段预测成正常水平GM(1,1)完全依赖趋势外推遇到流量跳变几乎无能为力。这也是为什么工程上很少拿单一模型硬扛而是做多模型对比后取加权。“仿真发散”在GM(1,1)里通常表现为预测曲线在几步后指数飙升检查顺序是a是否为负且绝对值偏大、训练数据是否混入异常点、预测步数是否超过了训练长度一半。在AR里发散则对应阶数过高或数据未做差分。4.4 对照操作视频复现时的三个检查点如果你在跟代码操作视频一步步复现建议重点核对三个位置。视频里第一个该出现的就是数据加载后的plot(flow)一眼确认导入的数据没有错位第二个是AR建模前统计量的打印确认差分前后的mean/std变化第三个是KNN训练集和测试集标准化参数的打印确认测试集没有偷用自己算的均值。复制代码报“矩阵维度不一致”九成出在滞后项切片那里GM(1,1)输出NaN看看训练序列里是否含零或负数KNN历史库大时卡顿把手写循环换成knnsearch。视频里把每个函数运行后打印输出尺寸和前三行数值出错时对照起来会快很多。5. 预测精度还能再往上顶的三个技巧5.1 滚动预测代替一次性递推一次性预测未来24步AR的误差会随步数累积KNN和GM(1,1)也会偏离真实轨迹。滚动预测的思路是每走一步就把新观测到的真实值补进窗口、丢掉最旧的点再重新建模或重新找近邻horizon 12; y_roll zeros(horizon, 1); window flow_train(end - best_p 1 : end); for h 1:horizon phi ar_ols(flow_train, best_p); % 用最新窗口重新估计 y_roll(h) ar_predict(window, phi, best_p, 1); window [window(2:end); y_test(h)]; % 注入真实观测 end滚动预测牺牲了一定的实时性换来误差不随步数膨胀实际工程里比纯递推实用得多。5.2 按MAPE倒数做加权融合三个模型各有强弱加权组合往往比挑一个最优模型更稳。权重按验证集MAPE的倒数分配误差小的模型拿更大的权重w_ar 1/mape_ar; w_gm 1/mape_gm; w_knn 1/mape_knn; w_sum w_ar w_gm w_knn; y_ensemble (w_ar .* y_pred_ar w_gm .* y_pred_gm w_knn .* y_pred_knn) / w_sum;加权融合对三个模型的预测偏差有平均化作用RMSE通常能比最差模型明显下降但很难超过最优模型太多定位是“稳健兜底”。5.3 入口加级比检验提前拦截GM(1,1)失效GM(1,1)不是随便一串数据都能建模建模前要做级比检验。原始序列的级比定义为 λ(k) x₀(k−1) / x₀(k)只有当所有级比都落在可容覆盖区间 (e^(−2/(n1)), e^(2/(n1))) 内序列才适合灰色建模。把这个检验直接写进函数入口n length(x0); lambda x0(1:end-1) ./ x0(2:end); lb exp(-2/(n1)); ub exp(2/(n1)); if any(lambda lb | lambda ub) warning(级比检验不通过GM(1,1)预测不可靠); end代码控制在MATLAB里加warning会直接以黄色提示显示比跑到最后看MAPE才意识到模型失效要省事得多。这个15行的检查函数不挑工具箱放到任何GM(1,1)脚本里都能直接复用。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →