基于ARIMA模型的旅游人数预测:从数据检验到滚动预测全流程

发布时间:2026/10/12 2:15:26
基于ARIMA模型的旅游人数预测:从数据检验到滚动预测全流程 简介这份毕业设计文档面向统计学、数据分析及旅游管理相关专业的学生与研究者围绕青岛市2000至2012年各季度旅游人数数据系统讲解如何借助MATLAB与R软件构建ARIMA模型完成旅游人数预测。文档完整呈现了从数据收集、多项式插值、拟合模型、余弦趋势拟合到时间序列建模的对比分析过程并给出模型选择与预测结果评价可帮助读者掌握时间序列分析的核心思路与实操方法。资源包内含1个doc文件约924KB结构涵盖绪论、旅游人数分析研究、基于ARIMA模型的预测分析及结论等章节目录清晰便于按模块查阅。目前已有258人学习下载适合需要完成相关课题、撰写论文或补充ARIMA建模案例的读者参考借鉴。1. 从一份毕业设计拆出的ARIMA旅游预测全流程拿到这份《基于ARIMA模型的旅游人数预测分析》毕业设计时我第一反应是终于有人把多项式拟合、拉格朗日插值、余弦趋势和ARIMA放在同一份数据上做横向对比了。它用青岛市2000到2011年共48个季度的国内旅游人数在MATLAB和R里跑了一遍最后证明ARIMA在带季节波动的非平稳序列上确实比插值和余弦拟合靠谱。如果你手头正好有季度客流、景区售票、酒店入住这类带明显季节性的数据又不想只停留在“调个包看结果”这份文档能让你把建模链条从头到尾走通一遍。它适合做课程设计的学生也适合需要快速搭一套客流预测基线的运营分析岗。2. 数据准备与平稳性检验48个季度点怎么摆平2.1 数据结构与导入方式原始数据是2000年Q1到2011年Q4的季度旅游人数单位万人共48个观测点。文档里以表格形式给出我一般会把它整理成两列一列时间戳一列数值。R里用ts()直接声明季度频率最省事MATLAB则用timeseries对象或直接列向量。这里先把数据落到R的ts对象上因为后续ADF检验、差分、ACF/PACF都靠它。# 青岛市2000Q1-2011Q4季度旅游人数万人 tourists - c( 185.52, 372.31, 527.09, 200.14, 233.56, 417.33, 592.12, 276.14, 280.18, 509.01, 718.73, 286.98, 310.99, 202.96, 795.87, 344.75, 336.21, 559.07, 901.65, 360.51, 375.23, 637.21, 995.39, 441.30, 436.20, 733.60, 1096.79, 534.24, 502.86, 830.59, 1282.64, 643.33, 522.97, 449.00, 955.01, 561.15, 612.07, 1066.92, 1438.05, 786.38, 661.66, 1234.70, 1618.88, 881.41, 729.56, 1398.82, 1853.68, 974.05 ) # 声明为季度频率时间序列startc(2000,1)表示2000年第1季度 ts_data - ts(tourists, start c(2000, 1), frequency 4)这段代码的关键在frequency 4它告诉R这是季度数据后续做季节差分时才能自动按4步长处理。如果频率设错ACF图会在滞后4、8、12处出现假性衰减模型阶数直接跑偏。数据导入后先画时序图肉眼判断趋势和季节波动这是最便宜也最有效的一步。2.2 平稳性检验ADF、时序图、线性回归三管齐下文档里用了三种方法判断平稳性时序图看趋势、线性回归看斜率、ADF单位根检验看p值。我实际跑下来时序图最直观——数据从185一路爬到1853同时每年Q3都是峰值趋势和季节双重非平稳。ADF检验的p值0.8948远大于0.05确认非平稳。# 时序图观察趋势与季节波动 plot(ts_data, main 青岛季度旅游人数, ylab 万人, xlab 年份) # 线性回归看斜率是否显著非零 t - 1:length(ts_data) lm_fit - lm(tourists ~ t) summary(lm_fit) # 斜率显著为正说明存在上升趋势 # ADF单位根检验 library(tseries) adf.test(ts_data) # p-value 0.8948不能拒绝非平稳ADF的原假设是“存在单位根序列非平稳”p值大意味着不能拒绝原假设即非平稳。这里有个常见误区有人看到p值0.8948以为模型坏了其实这正是预期结果——旅游人数本来就不该平稳。确认非平稳后下一步就是差分。文档里强调差分次数一般不超过2次因为每次差分都在提取信息的同时损失信息过差分会让残差变成白噪声模型反而学不到东西。2.3 一次差分与季节差分把趋势和季节拆开对原序列做一次普通差分趋势被削掉但图3-7显示季节性依然强烈。再做一次季节差分滞后4季节性基本消失。ADF检验p值降到0.01以下序列平稳。# 一次普通差分 diff1 - diff(ts_data, differences 1) plot(diff1, main 一次差分后) # 再一次季节差分滞后4 diff_seasonal - diff(diff1, lag 4) plot(diff_seasonal, main 一次差分季节差分后) # 对差分后序列做ADF检验 adf.test(diff_seasonal) # p-value 0.01平稳这里参数lag 4对应季度频率如果是月度数据就改成12。差分后的序列记为( w_t (1-B)(1-B^4)y_t )其中( B )是后移算子。文档里ARIMA的d取1季节差分D取1这是最经典的“一次普通差分一次季节差分”组合。我见过有人直接上两次普通差分结果ACF图在滞后4处仍然有尖峰就是因为没做季节差分季节信息没被提取干净。3. ARIMA模型定阶与参数估计ACF、PACF和AIC怎么配合3.1 从ACF/PACF图初步识别阶数差分后序列的ACF和PACF都表现为拖尾——自相关系数缓慢衰减趋于零偏相关系数也在前几阶之后落入置信区间。拖尾意味着不能用纯AR或纯MA得用ARMA混合模型。文档里通过观察图3-8和图3-9初步判断p和q都在低阶范围。我一般会先画图再用AIC在候选阶数里扫一遍。# 差分后序列的ACF与PACF acf(diff_seasonal, lag.max 24, main ACF) pacf(diff_seasonal, lag.max 24, main PACF)ACF在滞后4、8处仍有小尖峰说明季节MA项可能需要保留。PACF在滞后1、2处超出置信带提示AR项可能取1或2。这只是初步判断最终定阶靠AIC。3.2 AIC准则定阶别只盯着一个候选AIC的定义是( AIC -2\ln L 2k )其中( L )是似然函数( k )是参数个数。AIC越小越好但它不惩罚过度复杂模型的程度有限所以文档里也提到p和q一般不超过2。我通常会在p0:2、q0:2的网格里跑一遍同时考虑季节项P和Q。# 网格搜索AIC定阶 best_aic - Inf best_order - c(0, 0, 0) for (p in 0:2) { for (q in 0:2) { tryCatch({ fit - arima(ts_data, order c(p, 1, q), seasonal list(order c(0, 1, 0), period 4)) if (fit$aic best_aic) { best_aic - fit$aic best_order - c(p, 1, q) } }, error function(e) {}) } } print(best_order) # 输出最优阶数 print(best_aic)这段代码里seasonal list(order c(0,1,0), period 4)表示季节部分只做一次季节差分不加季节AR和MA。如果ACF在滞后4处尖峰明显可以把季节order改成c(1,1,0)或c(0,1,1)再试。注意tryCatch是必须的因为某些阶数组合会导致参数估计不收敛不加捕获会直接中断循环。文档里用的是OLS估计参数R的arima()默认用最大似然两者在样本量48时结果接近但ML对初值更敏感。3.3 参数估计与显著性检验定阶后看参数估计的t值和p值。文档里强调要检验参数显著性不显著的参数应该从模型中剔除。我跑下来AR(1)和MA(1)的系数通常显著季节MA项有时不显著这时候可以考虑简化模型。# 拟合最终模型 fit_final - arima(ts_data, order c(1, 1, 1), seasonal list(order c(0, 1, 1), period 4)) print(fit_final) # 查看系数t值和p值 coef_test - fit_final$coef / sqrt(diag(fit_final$var.coef)) print(coef_test)系数除以标准误得到t值绝对值大于1.96约等于p0.05。如果某个系数t值很小先别急着删——检查是不是差分过度导致参数不可识别。我踩过一次坑把d设成2结果AR和MA系数都接近零且不显著后来退回d1就正常了。3.4 残差白噪声检验模型拟合完必须检验残差是不是白噪声。文档里用Q统计量R里直接Box.test。# 残差白噪声检验 res - residuals(fit_final) Box.test(res, lag 12, type Ljung-Box) # p-value 0.05 则不能拒绝白噪声假设模型合格Ljung-Box的p值大于0.05说明残差没有留下未提取的自相关结构。如果p值很小说明模型欠拟合需要回到定阶步骤增加p或q。这里lag一般取20或12季度数据取12能覆盖3年周期。4. 预测与模型对比ARIMA凭什么赢过插值和余弦拟合4.1 用拟合模型预测未来8个季度模型合格后用predict()向前推8个季度两年。# 预测未来8个季度 forecast_result - predict(fit_final, n.ahead 8) print(forecast_result$pred) # 点预测 print(forecast_result$se) # 标准误 # 可视化 plot(forecast_result$pred, main 未来8季度旅游人数预测, ylab 万人, xlab 季度) lines(ts_data, col gray)预测值会带着置信区间标准误随预测步长增大而增大这是正常现象——越远越不确定。文档里预测未来两年和真实值对比拟合效果较好。我建议把预测值和实际值画在同一张图上肉眼判断趋势是否合理。如果预测值出现负值或剧烈震荡多半是差分阶数或季节项设错了。4.2 多项式拟合与拉格朗日插值的翻车点文档里试了3次、6次、10次多项式拟合10次误差最小但依然无法体现季度波动。拉格朗日插值更夸张——10次插值多项式系数达到1e17量级代入2012年算出负5万多万人。这不是模型不行是方法选错了插值和多项式拟合假设数据是光滑函数而旅游人数是带季节脉冲的离散序列。# 多项式拟合对比以3次为例 poly_fit - lm(tourists ~ poly(t, 3)) plot(t, tourists, main 3次多项式拟合) lines(t, fitted(poly_fit), col red) # 残差依然呈现明显的季节周期残差图会显示每年Q3正残差、Q1负残差说明多项式把季节波动当成了噪声。这就是文档里说的“不能很好地体现出旅游人数的季度变化”。如果你的数据季节性强度超过趋势强度多项式拟合基本没戏。4.3 余弦趋势拟合的局限余弦趋势模型( y_t \beta_0 \beta_1 \cos(2\pi f t) \beta_2 \sin(2\pi f t) )能捕捉固定振幅的季节波动但文档图2-5显示拟合误差很大因为旅游人数的季节振幅在逐年增大——2000年Q3约527万2011年Q3约1853万振幅从300多涨到1100多。固定振幅假设不成立余弦模型自然拟合不好。# 余弦趋势拟合 cos_fit - lm(tourists ~ cos(2*pi*t/4) sin(2*pi*t/4)) summary(cos_fit) # 残差仍含趋势成分说明振幅未随趋势增长对比下来ARIMA的优势在于差分处理趋势季节差分处理周期AR和MA项处理残差自相关。三步各司其职不要求振幅恒定也不要求函数光滑。这就是为什么文档最终选ARIMA。5. 避坑与排查ARIMA建模里最容易翻车的五件事5.1 差分次数过多导致过差分现象ADF检验p值很小序列“很平稳”但ACF所有滞后都接近零模型参数不显著。原因差分次数超过实际需要把本应保留的自相关结构也差掉了。文档里明确说差分次数一般不超过2次。解决从d0开始逐步增加每次差分后检查ACF是否还有可提取的滞后相关。如果一次差分后ACF已经快速衰减就别做第二次。5.2 季节周期设错现象ACF在滞后4、8、12处有规律尖峰但模型残差检验不通过。原因frequency参数设成了1或12R没有按季度周期处理。解决确认ts()的frequency4季节差分lag4。月度数据用12周数据用52。5.3 AIC选出的阶数不收敛现象网格搜索时某些p、q组合报错“non-finite finite-difference value”。原因高阶MA项在样本量小时容易过参数化优化不收敛。解决限制p和q不超过2用tryCatch跳过报错组合。如果还不收敛改用CSS估计methodCSS再试。5.4 残差白噪声检验通过但预测值离谱现象Box.test p值大于0.05但预测值出现负值或数量级错误。原因差分后建模预测时需要逆差分还原。R的predict()自动处理但手动还原容易漏掉季节差分那一步。解决直接用predict(fit, n.ahead)别自己手算逆差分。如果手动还原记得先逆季节差分再逆普通差分。5.5 用错软件版本或包现象arima()函数报错“invalid x type”或adf.test找不到。原因R版本太老或tseries包未安装。解决install.packages(tseries)确认R版本在4.0以上。MATLAB那边用arima函数时注意Econometrics Toolbox版本老版本不支持季节ARIMA。6. 进阶技巧把ARIMA塞进滚动预测框架文档里的预测是一次性向前推8个季度。实际业务中数据每周都在更新一次性预测很快过期。我一般会把ARIMA包进滚动预测循环每次用最新数据重新拟合只预测下一个季度然后等真实值到来后加入训练集再拟合。这样模型能吸收最新信息预测误差也更可控。# 滚动预测框架 n_total - length(ts_data) n_train - 40 # 前40个季度训练 n_test - n_total - n_train # 后8个季度测试 predictions - numeric(n_test) for (i in 1:n_test) { train_data - window(ts_data, end c(2000 (n_train i - 2) %/% 4, (n_train i - 2) %% 4 1)) fit_roll - arima(train_data, order c(1, 1, 1), seasonal list(order c(0, 1, 1), period 4)) pred - predict(fit_roll, n.ahead 1) predictions[i] - pred$pred } # 计算滚动预测误差 actual - window(ts_data, start c(2000 n_train %/% 4, n_train %% 4 1)) rmse - sqrt(mean((actual - predictions)^2)) print(paste(滚动预测RMSE:, round(rmse, 2)))这段代码的关键在window()动态截取训练集每次循环多纳入一个季度。%/%和%%用来把季度索引换算成年份和季度号。滚动预测的RMSE通常比一次性预测低10%到20%因为它不断用新数据校正参数。代价是计算量增加48个点跑8次拟合在普通笔记本上也就几秒钟完全可接受。另一个技巧是给ARIMA加外部回归变量比如把GDP、节假日天数作为xreg传进去。文档里没做这一步但如果你的数据里春节移动、政策变化影响明显加xreg能显著提升预测精度。R里arima(y, order, xregexog)预测时也要传对应的未来xreg。从那以后我每次做季度客流预测都强制走一遍“时序图→ADF→差分→ACF/PACF→AIC网格→残差检验→滚动预测”这七步少一步都可能在后头翻车。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询