news 2026/9/27 5:08:29

ARIMA旅游人数预测实战:从平稳性检验到差分定阶全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ARIMA旅游人数预测实战:从平稳性检验到差分定阶全流程

简介:一份面向旅游管理、数据统计与本科毕业设计的论文资源,以青岛市2000—2012年各季度旅游人数为样本,完整演示借助MATLAB与R软件完成多项式插值、拟合模型、余弦趋势拟合及ARIMA时间序列建模与预测的流程,通过比较不同方法得出未来两年旅游人数变化趋势。正文按照绪论、数据收集与来源、传统预测方法、时间序列模型、ARIMA建模步骤、季节模型预测、结论与参考文献组织,既解释了季节性波动与自相关数据对建模的影响,也呈现了模型定阶、拟合、检验与对比的完整科研路径,适合作为旅游人数预测课题的开题参考或论文框架。资源共1个doc文件,压缩包约924KB,篇幅适中;目前已有258人浏览学习,适合需要快速上手的本科生、统计预测入门者及备战毕业设计答辩的学生查阅。

1. 基于ARIMA模型的旅游人数预测分析:这份毕业设计文档到底值不值得拆

如果你手里正攥着一份旅游人数、客流量或者任何带明显季节波动的业务数据,想找个能落地的时间序列预测方案,这份《基于ARIMA模型的旅游人数预测分析》毕业设计文档就是典型的现成作业。它把青岛市2000年到2011年共48个季度的国内旅游人数当样本,用MATLAB和R两条技术线各跑了一遍多项式拟合、拉格朗日插值、余弦趋势拟合和ARIMA模型,最后用ADF检验、ACF/PACF图和AIC准则一步步把ARIMA选成了最优方案。整套分析流程不是拿数据硬套公式,而是从“序列不平稳→差分平稳化→定阶→参数估计→残差白噪声检验”走完的完整闭环。适合正在做课程设计、毕设或者刚接触时间序列分析的人直接复现,也适合想快速上手R语言tseries、forecast包的从业者当参考骨架。

2. 数据底子和三种传统预测方法的翻车现场:搞清楚它们为什么输

2.1 数据从哪里来,48个样本点够不够用

文档用的数据源头是青岛统计信息网,覆盖2000年第一季度到2011年第四季度,每个季度一条国内旅游人数记录,单位是万人。注意原文表格里写的是“2000至2011年各季度”,摘要里又提到2000年至2012年,以正文表格为准,实际是12年×4季度=48个观测点。先看这份数据的基本形态:

年份Q1Q2Q3Q4
2000185.52372.31527.09200.14
2001233.56417.33592.10276.14
2002280.18509.01718.73286.98
2003310.99202.96795.87344.75
2004336.21559.07901.65360.51
2005375.23637.21995.39441.30
2006436.27733.611096.79534.24
2007502.86830.591282.00643.33
2008522.97495.501155.21756.33
2009612.071066.921438.05786.38
2010661.661234.711618.88881.41
2011729.561398.821853.68974.05

从数据形态能直接看出两个特征:一是逐年上升的长趋势,2000年Q1的185.52万人到2011年Q4的974.05万人,翻了5倍多;二是明显的季节性,每年Q3是绝对峰值,Q1是低谷。这两点决定了后面所有模型的命运——凡是不能同时处理趋势和季节性的方法,都会被这份数据淘汰。

48个样本做时间序列建模确实偏少,但在毕业设计和课程设计层面够用。R里的ts()函数按月或季度构建时间序列对象时,frequency设为4即可。样本量小带来的直接后果是定阶时AIC比BIC更适用,因为AIC对复杂模型的惩罚更温和,在小样本下不容易漏掉有效阶数。

2.2 多项式拟合:趋势抓得住,季度波动抓不住

文档里多项式拟合用的是最小二乘原理,即寻找多项式函数使得残差平方和最小:

p3 = polyfit(t, y, 3); p6 = polyfit(t, y, 6); p10 = polyfit(t, y, 10); y3 = polyval(p3, t); y6 = polyval(p6, t); y10 = polyval(p10, t); error10 = sum((y - y10).^2);

这段MATLAB代码的逻辑很简单:polyfit(t, y, n)返回n次多项式系数,polyval代入原时间点计算拟合值。文档实测下来,10次多项式的拟合误差最小,达到2.0568e+003。但问题恰恰在这里——误差最小不代表预测能力最强。拟合误差小只是说明多项式在已知样本点上“穿得准”,对季度性波动这种周期性成分,多项式天然无能为力。看数据就知道了,48个点有48种波动形态,多项式次数再高也只是一个连续函数,它可以用高频振荡去逼近已知点,但外推到2012年时就会跑出不可控的形态。

这里有个常见的误用场景:如果只看整体上升趋势,3次多项式就够了;如果看局部拟合效果,10次多项式误差最小。但这两者都不能用来预测下一年的季度值,因为旅游人数序列是“趋势+季节+随机扰动”的混合体,多项式只能捕捉其中连续平滑的部分。

2.3 拉格朗日插值:高阶插值的龙格现象直接把预测值干成负数

文档对拉格朗日插值的处理比较有意思:一开始用全部48个节点做插值,MATLAB直接画不出准确的函数图像,因为插值节点太密、时间轴间隔太小,导致数值稳定性崩塌。后面改成只用2009年Q2到2011年Q3的数据做10次插值,得到的多项式是:

y = 42050070325701.25 + (-35753439798658.24)*x^1 + 13501523503749.38*x^2 ... + (-2972085789066.978)*x^3 + 420292654814.4023*x^4 + ...; x_2012 = 2012; pred_2012 = polyval(p, x_2012);

把这组系数代进去,x=2012时预测值约-5.208×10^4,旅游人数是负数,这在业务上完全说不通。根因是10次插值多项式在端点附近的龙格振荡——插值节点越多、多项式次数越高,端点附近的误差越大,而且系数达到10^13量级,时间轴上极小的变动都会被放大到不可接受的程度。这里的教训是:拉格朗日插值只适合节点少、区间短、函数本身平滑的场景。文档里用它算2009到2011年区间内的插值点还比较准,一外推就翻车,典型的插值法“内插可用、外推必死”特征。

如果你在别的项目里遇到类似问题,一个可替代的做法是用spline(三次样条插值),它在节点间分段构造低次多项式,避免全局高次振荡,但也同样不适合外推。任何插值法本质都是在拟合已知点之间的形态,而不是发现数据背后的生成规律。

2.4 余弦趋势拟合:振幅固定,跟不上逐年抬升的峰值

余弦趋势模型的思路是用周期函数拟合季度波动,公式是:

fit_cos <- lm(y ~ cos(2 * pi * t) + sin(2 * pi * t))

R的输出系数为:截距699.28,cos(2*pi*t)项系数-324.52,sin(2*pi*t)项系数101.33。其中cos项通过了显著性检验(p<2e-16),sin项没通过(p=0.126)。这个结果说明序列确实存在以年为周期的波动成分,但问题在于余弦模型的振幅是固定的,而青岛旅游人数是逐年增长且峰值不断抬升的——2000年Q3只有527.09万人,2011年Q3已经到1853.68万人,固定振幅不可能跟上这种变化。拟合图像里能明显看到早期的峰值被低估,后期的峰值也被低估,整体拟合线像一条上下摆动的直线通道,数据点在通道里“越走越宽”。

这个模型的定位是:当序列只有周期性、没有长趋势时可以尝试;一旦发现趋势项显著,必须对原始序列做趋势分离或者差分,直接把原始序列丢给余弦模型等于让一个不会长高的模型去预测一个越长越高的对象。

3. ARIMA模型完整建模流程:从平稳性检验到预测的每一步操作

3.1 为什么ARIMA能赢:差分消趋势,ARMA处理残差相关

再看ARIMA模型的数学结构。AR(p)是p阶自回归,用过去p期的值预测当期;MA(q)是q阶移动平均,用过去q期的预测误差修正当期;ARMA(p,q)是两者组合,但只适用于平稳序列。ARIMA(p,d,q)多出来的d是差分阶数,作用是先把非平稳序列中的趋势成分通过差分消除掉,再对差分后的平稳序列建立ARMA模型。写成公式就是:

(1 - φ1*B - ... - φp*B^p) * (1-B)^d * y_t = (1 + θ1*B + ... + θq*B^q) * ε_t

B是滞后算子,(1-B)^d表示d阶差分。青岛旅游人数序列的问题是“非平稳趋势+季节性”双重叠加,ARIMA的优势在于:差分把长趋势消掉,模型变成对差分序列的平稳建模,而AR项和MA项能分别捕捉序列的自相关性和随机扰动的记忆效应。这就是它比多项式拟合、余弦拟合强的地方——后两者是在原始序列上硬套确定函数,ARIMA是在差分后的平稳序列上做随机过程建模。

3.2 平稳性检验:画图线性回归和ADF三种手段一起上

文档对原始序列做了三个层面的平稳性判断。第一是画时间序列图:48个点呈明显上升趋势,伴随Q3尖峰、Q1低谷的季节波动,直接判定非平稳。第二是做线性回归:回归线斜率显著为正,说明存在确定性趋势成分。第三是R语言的ADF单位根检验:

library(tseries) dat1 <- ts(qingdao_data$travelers, start = c(2000, 1), frequency = 4) adf.test(dat1)

输出结果为Dickey-Fuller=-1.197,Lag order=3,p-value=0.8948。p值远大于0.05,不能拒绝“存在单位根”的原假设,即序列非平稳。这三个证据指同一个方向:必须做差分处理。

接着文档对原始序列做一阶差分:

diff_dat1 <- diff(dat1) adf.test(diff_dat1)

一阶差分后的ADF检验结果Dickey-Fuller=-6.3784,p-value=0.01,R还给了个警告“p-value smaller than printed p-value”,说明p值实际小于0.01,序列平稳了。但需要注意一个细节:一阶差分后的时间序列图(原文图3-7)显示上升趋势已消除,但季节性依然强烈。这说明只有普通差分是不够的——季度间隔(周期4)上的强相关还没被处理掉。所以在实际建模时不能只做一阶差分就收工,要结合ACF图判断是否还需要季节差分。

3.3 定阶:ACF/PACF拖尾截尾加上AIC准则双重确认

定阶是ARIMA建模里最像“玄学”的一步。规范做法是看差分后序列的ACF和PACF图:如果ACF拖尾、PACF截尾,适合AR模型;如果ACF截尾、PACF拖尾,适合MA模型;两者都拖尾,用ARMA模型。

acf(diff_dat1, lag.max = 12) pacf(diff_dat1, lag.max = 12)

文档里一阶差分后的ACF图呈现出衰减趋于零的拖尾形态,PACF图也是衰减趋于零的拖尾形态,因此初步判定p和q都不是0,需要建立ARMA(p,q)模型。定阶具体选几,文档采用AIC准则:在候选范围内从低阶到高阶逐个计算AIC值,选最小的组合。AIC的定义是:

AIC = 2k - 2ln(L)

k是模型参数个数,L是似然函数值。AIC平衡了拟合优度和模型复杂度,参数越多AIC惩罚越大,防止盲目堆阶数。常用做法是用auto.arima()函数自动搜索,但手动定阶的价值在于理解p和q的物理含义:p对应“过去第几个季度的旅游人数对当前影响最大”,q对应“过去几个季度的预测误差还在影响当前”。青岛旅游人数的强季节性决定了光靠低阶AR项很难完全吸收,这也是为什么文档里最终要考虑季节差分后的ARIMA结构。

3.4 参数估计与模型检验:残差必须是白噪声

定了阶就要估计参数。文档用最小二乘法(OLS)进行参数估计,R里用arima()函数即可:

fit_arima <- arima(dat1, order = c(p, d, q))

参数估计完成后进入模型检验阶段,核心是做残差的白噪声检验。残差如果是白噪声,说明模型已经把数据里的有效信息提取干净了;残差如果还有自相关,说明模型没建到位,需要调整p或q。文档用的是Q检验(Ljung-Box):

Box.test(fit_arima$residuals, lag = 12, type = "Ljung-Box")

Q统计量近似服从卡方分布,自由度是k-p-q。如果Q值对应的p值大于0.05,接受“残差是白噪声”的原假设,模型通过检验。这里有个实操细节:自由度计算容易出错,有的软件会自动修正,手动计算时要注意减去估计的参数个数,否则检验临界值会偏大,导致该拒绝的时候没拒绝。

3.5 季节模型的必要性:普通差分加季节差分双管齐下

文档里有个关键转折:一次差分后的序列虽然通过了ADF平稳性检验,但季节性还在。遇到这种“趋势消了但季节犹存”的序列,常规做法是再做一次季节差分。对季度数据来说,季节差分就是滞后4期的差分:

diff_seasonal <- diff(diff_dat1, lag = 4)

对应的R建模方式是arima()里指定seasonal参数:

fit_sarima <- arima(dat1, order = c(p, d, q), seasonal = list(order = c(P, D, Q), period = 4))

用普通一阶差分加季节差分组合,实际上是建立SARIMA模型(季节性ARIMA),数学表达就是同时做(1-B)差分和(1-B^4)差分。这样处理后的序列上升趋势和季节性都被消除,剩下的是一段围绕零均值波动的平稳序列,才能进入平稳ARMA建模。

实际操作中,d和D的选取顺序是先定D(做季节差分观察ACF是否在lag=4,8,12处显著回落),再定d(观察趋势是否消除),最后统一检验。文档里从一阶差分到季节差分的递进路径是典型的“先处理趋势、再处理季节”两步走,这套思路可以原样迁移到其他月度或季度数据上。

4. 避坑指南:旅游人数预测里的5个典型翻车现场

4.1 拉格朗日插值外推直接得到负值

现象:把2009-2011年数据做10次拉格朗日插值,代入x=2012,预测结果是-5.208×10^4万人。

原因:高阶插值多项式在端点附近产生龙格振荡,系数高达10^13量级,时间轴坐标微小变化被放大了十几个数量级。

解决:插值法只用于区间内插值,不做外推;需要预测时改用差分模型或回归模型;如果确实要用插值思路做短外推,把时间轴做中心化处理(比如把年份转成0,1,2,...而不是2010,2011,2012)能缓解数值不稳定,但治标不治本。

4.2 差分阶数越多越好

现象:对序列连续做3次或4次差分,直到“看起来”完全平稳,但预测结果反而比少差分的模型更差。

原因:每次差分都会损失信息、放大噪声。文档里特别提到“差分运算的阶数并不是越多越好”,“应当避免过度差分”。差分到后面,剩下的序列方差越来越大,信噪比急剧下降。

解决:差分次数不超过2次。判断差分是否到位的标准不是ACF绝对干净,而是ADF检验p值显著小于0.05且差分后的序列具备业务上的可解释性。季度数据通常d=1或2就够。

4.3 ADF检验p值显示平稳但ACF图仍然诡异

现象:一阶差分后ADF检验通过(p=0.01),但ACF图在lag=4、lag=8处还有明显峰值,偏相关图也没完全截尾。

原因:ADF检验验证的是“是否存在单位根”,验证不了“是否完全无季节性”。青岛旅游人数峰值集中在Q3,这种固定周期的相关性在一阶差分后依然残留。

解决:做季节差分。在arima()里加seasonal参数,或者先diff(diff(data), lag=4)再重新检查ACF/PACF,看到lag=4处峰值消失才算处理干净。

4.4 模型残差白噪声检验的自由度算错

现象:Box.test()输出的p值很小,但模型看起来没问题,调高阶数后仍然显著。

原因:Ljung-Box检验的自由度需要减去模型参数个数(p+q),有些情况下还要减去季节参数(P+Q)。自由度算小了,临界值就偏大,会把合格的模型误判为残差非白噪声。

解决:手动计算自由度修正,Box.test(residuals, lag = 12, type = "Ljung-Box", fitdf = p + q)。R里面fitdf参数就是干这个的,不设的话相当于在用错误的标准卡自己。

4.5 把AIC当唯一标准,忽略模型可解释性

现象:auto.arima()选出一个AIC最小的模型是ARIMA(4,1,4),参数多、拟合好,但缺乏业务解释,预测曲线出现极端震荡。

原因:AIC越小说明模型在“拟合-复杂度”的平衡上更优,但纯数据驱动选出的高阶模型往往没有业务逻辑支撑。旅游人数的季节性本质上只需要一个季节项就能解释大部分波动,AR(4)+MA(4)的大部分参数估计值可能都不显著。

解决:先用ACF/PACF图人工粗定阶范围,再在这个范围内用AIC精调。auto.arima()的搜索范围也建议限制一下,max.p=3, max.q=3, max.order=6,结合stepwise=TRUE,不要让模型复杂度失控。

5. 预测可信度验证:训练集拟合、滚动预测与置信区间解读

ARIMA建模完成后,很多人直接看预测曲线就算交差,这是最危险的。文档里提到“与真实值进行比较,ARIMA模型的预测值有较好的拟合效果”,但没有展开这个比较怎么做。我的习惯是强制自己走一遍训练集-测试集滚动验证,这套流程比任何事后拟合优度指标都更能说明问题。

library(forecast) # 用2000-2010年数据建模 train <- window(dat1, end = c(2010, 4)) test <- window(dat1, start = c(2011, 1)) fit_train <- auto.arima(train, seasonal = TRUE, stepwise = TRUE) # 做4步预测,对应2011年四个季度 fc <- forecast(fit_train, h = 4) # 计算预测误差 accuracy(fc, test)

这段代码的逻辑:把2000-2010年共44个季度的数据作为训练集,2011年4个季度作为测试集,用训练集拟合ARIMA后向前预测4步,再用accuracy()计算RMSE、MAE、MAPE等误差指标。MAPE在旅游人数预测里最直观,比如结果如果显示MAPE=5.3%,意思是平均每个季度预测值与真实值的相对偏差在5.3%左右。如果MAPE超过15%,这个模型的实际业务参考价值就存疑了。

滚动预测还有个进阶变体:每次只预测一步,然后把这个真实值加入训练集再预测下一步,四步走完得到4个一步预测。这种做法的好处是避免多步预测误差累积——ARIMA在预测第1步之后,第2步的预测是基于第1步的预测值继续往前推的,误差会指数级放大。如果你是拿模型做季度滚动预测(比如每个季度更新一次预测),一步预测滚动方案更贴近真实业务节奏。

# 滚动一步预测 history <- train preds <- c() for (i in 1:4) { fit_refit <- Arima(history, model = fit_train) next_pred <- forecast(fit_refit, h = 1)$mean[1] preds <- c(preds, next_pred) history <- ts(c(history, test[i]), start = start(history), frequency = 4) }

这段代码的Arima(history, model=fit_train)是R里面“沿用原模型阶数但用更新数据重新估计参数”的写法,比每次跑一遍auto.arima更高效也更稳定。注意history要不断把真实值拼接回去,模拟真实场景中“每月/每季度拿到新数据就更新一次预测”的状态。

最后是置信区间的解读。forecast()默认输出80%和95%置信区间,很多人只取$mean拿点预测,丢了区间信息。实际业务里区间比均值更有用——如果2011年Q3的95%置信区间是[1450, 2250]万人,告诉你的是“有95%的把握真实值落在这个范围内”,这个区间宽度本身就是不确定性的量化。如果区间过宽(比如宽度超过均值的50%),说明模型或数据的稳定性不够,对外汇报时要警惕把点预测说得太绝对。我从那以后做任何时间序列项目,都会在交付预测结果时附带置信区间,哪怕对方没要求——一个只有均值没有区间的预测,等于只说了答案没给误差范围,是谈不上可信度的。希望这些细节能帮你在自己的数据上少踩几个坑。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/27 5:06:20

CLLC谐振变换器设计:基波分析、参数优化与MATLAB仿真

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 5:06:14

RK3588平台RTMPose模型部署与推理优化实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 5:05:12

Python基于录屏的LOLM关键数据与优劣势转折点自动分析

基于录屏的LOLM关键数据与优劣势转折点自动分析系统架构整个系统的处理管线可以概括为&#xff1a;录屏视频 → 帧提取 → 屏幕区域裁剪 → OCR/目标检测识别 → 数据序列化 → 转折点检测 → 报告输出核心思路是&#xff1a;在每一帧&#xff08;或按固定间隔抽帧&#xff09;…

作者头像 李华
网站建设 2026/9/27 4:59:03

小红书客服系统:React底层Event注入,表单毫秒级填充

小红书客服系统&#xff1a;React底层Event注入&#xff0c;表单毫秒级填充 电商这行&#xff0c;谁的速度快谁吃肉。小红书的自动回复与客服&#xff0c;是店群运营中最耗人力也最容易出错的环节。 店群客服是纯人力消耗战。一个店日均50条咨询&#xff0c;20个店就是1000条。…

作者头像 李华
网站建设 2026/9/27 4:56:17

通信原理期末复习攻略:基于华工试卷PPT的考点解析与解题套路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华