ARIMA新能源汽车销量预测实战:从平稳性到滚动回测

发布时间:2026/10/11 20:12:30
ARIMA新能源汽车销量预测实战:从平稳性到滚动回测 简介一份基于ARIMA模型的新能源汽车销量预测学术论文PDF内容选自《企业科技与发展》2020年第10期。论文以ARIMA时间序列模型为核心选取2014年1月至2019年5月新能源汽车月度销量数据依次完成差分平稳化、ACF与PACF分析、模型识别定阶和SPSS参数估计最终建立ARIMA(1,0,0)(1,1,0)模型并对2019年3至5月销量进行预测验证结果显示相对误差在6%至9%之间能较好反映销量趋势。内容还讨论了新能源汽车的市场销量实际情况及我国厂商研究起步较晚等背景适合车辆工程、统计及数据分析方向的学生与研究者作为建模参考也可用于课程论文或销量预测课题的方法借鉴。资料共1个PDF文件压缩包大小1.11MB图表和公式完整便于阅读与引用已有479人学习浏览。阅读后可以快速掌握ARIMA模型从数据预处理、平稳化、建模到短期预测的完整流程并了解新能源汽车市场的销量波动规律。1. 先看懂这张表新能源汽车销量预测为什么绕不开 ARIMA年底的排产会上计划员问这款车下个月产能到底扩多少销售说市场还在涨供应链说库存压不起谁都拿不出一个带置信区间的数。基于 ARIMA 模型的新能源汽车销量预测解决的就是这个真实痛点。它不需要深度学习的算力环境也不需要外部特征工程只用销量自身的历史轨迹就能给出未来几个周期的点预测和区间预测。对生产排产、库存管理、销售目标拆解来说ARIMA 是性价比最高的起点也是任何前沿模型都绕不过去的对比基线。这份方案通常以一份包含数据预处理、定阶、回测与结论的 PDF 报告交付而这篇笔记会把背后的完整链路拆开从平稳性一路讲到滚动回测和残差诊断全程用新能源月度销量数据走一遍新手能跟得上熟手也能看到参数边界。2. 把 ARIMA 拆到能上手平稳性、差分与 p d q 三个参数的直觉2.1 从工程师视角看平稳性为什么非平稳序列会让模型失效ARIMA 的全称是 Auto Regressive Integrated Moving Average自回归、差分、移动平均三件套。自回归项描述的是惯性上个月的销量会通过订单结转、口碑扩散影响这个月。移动平均项描述的是冲击的衰减一次补贴政策、一次降价促销造成的销量扰动会在之后几个月逐步消化。这两个机制都假设序列围绕一个相对稳定的均值在波动。问题在于新能源汽车月销量从 2020 年的十几万台级别涨到 2023 年的八十万台级别均值一直在抬升根本不满足这个假设。如果直接拿原始序列去拟合自回归项模型会把上升趋势当作“常态”学进去。一旦趋势斜率变化比如补贴退坡导致增速放缓模型的下一个预测就会大幅跑偏。平稳性因此成了 ARIMA 能不能成立的前提。判断平稳性最常见的量化指标是 ADF 检验。它的原假设是序列存在单位根也就是不平稳p 值小于 0.05 时拒绝原假设认为序列平稳。statsmodels 里一行就能调用。但这里有一个常见误用很多同学看到 p 值是 0.04 就欢呼“平稳了”而销量序列往往是“趋势明显但恰好通过检验”的边界情况。我一般会把 ADF 结果和折线图合在一起看两条都站得住脚再往下走毕竟统计检验不是免死金牌。另外单看均值还不够方差也要稳。年末冲量月份的销量波动明显放大这种异方差性 ARIMA 不能直接处理通常先做对数变换或 Box-Cox 变换把波动压一压再进入平稳性检验流程。这一步能显著降低后面残差诊断时出现“尖峰厚尾”的概率。2.2 差分到底在消除什么d 的取值逻辑与过度差分的代价差分的直觉很简单今天的值减昨天的值把上升趋势变成围绕某个常数的波动。一阶差分y_t - y_{t-1}消除线性趋势如果趋势带加速度也就是增长率本身在变化可能需要二阶差分。对新能源汽车月销量来说一阶差分通常就够因为绝对值虽然在涨环比的波动相对稳定。过度差分是新手最容易踩的坑。差分两次之后序列方差被放大原本干净的自相关结构被破坏拟合出来的参数极不稳定。经验法则d 能取 1 就不取 2取 2 之前先看一阶差分后的自相关图如果自相关系数在零附近小幅波动说明趋势已经被清干净了没必要再差一次。用代码做差分没有专门的“差分函数”pandas 的.diff()一步完成import pandas as pd x_diff df[sales].diff().dropna()差分之后重新画图、重跑 ADF。我习惯的做法是把 d0、1、2 三种情况各算一遍 ADF选一个 p 值最小且方差膨胀最小的 d而不是只盯着 p 值看。统计量过了还要看差分后的序列在业务上有没有意义——比如差分后出现大量负值说明销量在环比下滑这本身就是管理要看的信息。2.3 ACF 与 PACF 看图定 p 和 q不靠玄学靠两个判据差分完成后要回答的问题是自回归用几阶移动平均用几阶。这里靠两张图ACF 画的是序列与自身滞后值的相关性如何随阶数衰减PACF 画的是剔除中间滞后项干扰后某阶滞后的净贡献。判读规则很经典做成表就是下面这样图形表现模型选择PACF 在 k 阶后截尾ACF 拖尾AR(k)p 取 kACF 在 k 阶后截尾PACF 拖尾MA(k)q 取 kACF 与 PACF 都拖尾ARMA需要网格搜索两者都快速截尾序列接近白噪声不该硬套 ARIMA注意图上的“截尾”在真实数据里很少干净利落。月度销量受节假日、政策、新车型影响ACF 和 PACF 往往不是教科书形态。所以看图只用来初筛方向最终定阶交给 AIC 网格搜索。statsmodels 的plot_acf和plot_pacf可以直接画这两张图看的时候记得把显著相关的阈值线标出来不要被几个恰好超过阈值的点带偏。阶数也不是越大越好。pq 一般控制在 5 以内月度数据样本量通常只有几十个月阶数一高参数估计的方差立刻变大出现“训练集拟合很好、验证集一塌糊涂”的情况。记住这个边界后面网格搜索才不会把范围拉得离谱。3. 用 Python 跑通最小预测链路从新能源汽车月度销量到 ARIMA 拟合3.1 数据准备拿到销量序列后先做的三件事拿到一张“年月 销量”的表不要急着 fit。先做三件事格式转换、缺失值检查、频率对齐。这三件事做不对后面的滞后阶数全是错的。import pandas as pd df pd.read_csv(nev_sales_monthly.csv) df[month] pd.to_datetime(df[month]) df df.set_index(month).sort_index() # 检查 index 是否连续生成完整月度序列差集就是缺失月份 full_range pd.date_range(startdf.index.min(), enddf.index.max(), freqMS) print(缺失月份数量:, len(full_range.difference(df.index))) # 缺失值用上月值填充注意不要引入未来信息 df df.reindex(full_range).ffill() print(df.tail())逻辑说明to_datetime把字符串统一成时间类型set_index加sort_index保证时间轴有序。freqMS表示月度起点用它生成完整日历范围再做差集就能精确知道缺了哪些月份。reindex把缺失月份补成 NaNffill用上个月的值回填这样模型在计算滞后阶数时不会因为索引跳变而错位。参数说明里最容易忽略的是freq的写法。“MS”是 Month Start旧版本里“M”表示日历月末但已经被标记废弃新版本建议直接写“ME”。月度销量数据用“MS”最直观既能对齐自然月又能避免月末那一天的时区问题。3.2 平稳性检验与差分ADF 检验的代码与判读from statsmodels.tsa.stattools import adfuller x df[sales] adf_result adfuller(x.dropna()) print(fADF 统计量: {adf_result[0]:.4f}) print(fp 值: {adf_result[1]:.4f}) if adf_result[1] 0.05: print(原始序列近似平稳d 可以取 0) else: x_diff x.diff().dropna() adf_diff adfuller(x_diff) print(f一阶差分后 p 值: {adf_diff[1]:.4f})逻辑说明adfuller返回的元组里第 0 个是检验统计量第 1 个是 p 值。小于 0.05 拒绝单位根原假设。这段代码先测原始序列不平稳再做一阶差分而不是一上来就无脑 d1。很多入门教程直接默认差分遇到本身平稳的序列反而引入了多余的移动平均项属于帮倒忙。这里的边界情况要特别注意如果原始序列 p 值是 0.06一阶差分后 p 值是 0.001那显然选 d1。如果原始序列 p 值是 0.04 但折线图趋势明显我倾向于也做一次差分再看 ACF因为差分后的模型通常更稳健。统计检验是参考不是决策本身。3.3 模型定阶与拟合用 AIC 在网格搜索里选 (p, d, q)import warnings import itertools from statsmodels.tsa.arima.model import ARIMA p_range range(0, 4) q_range range(0, 4) d_range range(0, 2) best_aic float(inf) best_order None best_model None warnings.filterwarnings(ignore) for p, d, q in itertools.product(p_range, q_range, d_range): try: model ARIMA(x, order(p, d, q)) res model.fit() if res.aic best_aic: best_aic res.aic best_order (p, d, q) best_model res except Exception: continue print(f最优阶数: {best_order}, AIC: {best_aic:.2f})逻辑说明itertools.product把 p、d、q 的所有组合遍历一遍每组都拟合一次记录最小 AIC 的阶数。try/except是因为部分阶数组合在数值上会收敛失败直接跳过。参数说明里p_range 和 q_range 设成 0 到 3 是有意的。月度销量数据的滞后相关性一般两三个月就衰减完了阶数再高只会增加过拟合风险。d_range 设 0 和 1是因为前面 ADF 判定大概率只需要一阶差分。如果数据有强季度周期比如 12 个月一个完整峰谷纯 ARIMA 不够用要考虑 SARIMA 的季节项(P,D,Q,12)。网格搜索的范围先小后大基线 AIC 出来后再往邻近阶数微调性价比最高。3.4 训练测试切分与滚动预测评估import numpy as np from sklearn.metrics import mean_absolute_error, mean_squared_error train x.iloc[:-6] # 留最后 6 个月做验证 test x.iloc[-6:] model ARIMA(train, orderbest_order).fit() forecast model.forecast(stepslen(test)) mae mean_absolute_error(test, forecast) rmse mean_squared_error(test, forecast, squaredFalse) mape np.mean(np.abs((test - forecast) / test)) * 100 print(fMAE: {mae:.0f} 辆, RMSE: {rmse:.0f} 辆, MAPE: {mape:.2f}%)这段代码把最后 6 个月作为验证段前面的数据参与训练用forecast生成未来 6 步的预测再和真实值对比。MAPE 是百分比误差给业务方汇报时最直观但当某个月销量因疫情停工等原因跌到几百台时MAPE 会瞬间爆炸成几千这种情况改用 MAE 或 RMSE 更稳。forecast和predict的区别在这里很关键forecast(steps6)是纯样本外预测predict(start, end)可以指定起点起点落在训练集内时输出的是拟合值。做评估一定用forecast不要用predict把训练集内的拟合值混进误差计算那会严重低估真实误差让你误以为模型精度很高。4. 销量预测里的 5 个必调参数从季节分解到置信区间4.1 季节分解月度销量的周期到底藏在哪里新能源汽车销量有两个明显的周期性来源一是 12 月厂商冲量带来的年末高峰二是春节所在月份的低谷。这两个周期叠加在长期增长趋势上让原始序列看起来“有规律但不规则”。ARIMA 本身不感知周期所以先分解、看清周期存在的证据再决定要不要升级为 SARIMA。from statsmodels.tsa.seasonal import seasonal_decompose result seasonal_decompose(x, modelmultiplicative, period12) result.trend.plot() result.seasonal.plot() result.resid.plot()逻辑说明seasonal_decompose把序列拆成趋势、季节、残差三项。modelmultiplicative适合乘性季节效应也就是旺季波动幅度和销量绝对值成正比新能源汽车月度数据就是这种形态如果波动幅度不随水平变化改用additive。period12表示以 12 个月为完整周期。如果分解出的季节分量在最近两年明显变形比如新车型放量把季节性节奏打乱了说明季节模式不稳定用 SARIMA 的固定周期假设反而危险。这种情况下直接用差分加 ARIMA让模型自己去捕捉残留下来的短期相关性比强行上 SARIMA 更稳。4.2 训练窗口长度不是数据越多越好很多拿到手的新能源销量序列只有三四年因为 2015 年前后才有规模。这时候把全部历史都塞进训练集早期“补贴驱动”的数据反而会污染模型。我一般先看趋势图选销量进入稳定增长期的起点再确定训练窗口通常 24 到 36 个月就够 ARIMA 估计参数了。这个参数没有硬性公式但有一个验证方法把窗口从 12 个月逐步加到 48 个月每个窗口都做一次滚动回测画出“窗口长度对回测 RMSE”的曲线取最低点。这就是超参数选择的基本功用验证误差说话而不是凭直觉拍脑袋。4.3 预测步长与置信区间汇报时用 80% 还是 95%forecast_res best_model.get_forecast(steps6) mean forecast_res.predicted_mean conf_80 forecast_res.conf_int(alpha0.2) conf_95 forecast_res.conf_int(alpha0.05)get_forecast返回一个PredictionResults对象predicted_mean是点预测conf_int(alpha)给出置信区间。alpha 是显著性水平0.2 对应 80% 置信区间0.05 对应 95%。向业务方汇报时80% 区间更实用因为区间窄能直接支撑排产上下限95% 区间宽到经常“等于没说”只用来做极端风险情景测试。这里有一个很多人会犯的错把置信区间当成业务承诺。ARIMA 的区间只反映模型不确定性不反映政策突变、芯片短缺这类结构性风险。所以不管选哪个 alpha汇报时都要补一句这是基于历史规律的外推外部冲击不在区间之内。4.4 残差诊断模型好不好先看残差是不是白噪声模型拟合完之后残差序列应该看起来像白噪声也就是没有任何可被利用的信息残留。检验方法有 Ljung-Box 检验和 QQ 图。from statsmodels.stats.diagnostic import acorr_ljungbox resid best_model.resid lb_test acorr_ljungbox(resid, lags[6, 12], return_dfTrue) print(lb_test)acorr_ljungbox的 p 值大于 0.05说明残差没有显著自相关性模型已经把信息榨干了p 值很小说明还有模式没抓到。看到 p 值小于 0.05先别急着换 LSTM很多情况下只是 p、q 阶数偏低。把网格搜索的范围扩大一点再跑一轮成本远低于换模型。残差诊断还有一个容易被忽略的点best_model.resid在训练集上计算拟合阶段的残差异常并不代表预测阶段的误差。所以残差诊断只能证明模型没有遗漏模式不能证明预测精度高精度评估还是要靠第 3 章里的验证集切分。4.5 差分阶数上限与模型复杂度控制ARIMA 的阶数不是越复杂越好。低频月度数据上pq 超过 5 之后参数估计方差会快速变大样本量只有 30 到 50 个月根本支撑不起复杂模型。网格搜索的小技巧是先跑一个小范围拿到基线 AIC再在基线附近逐个加阶数。如果增加一阶只让 AIC 降低了不到 2说明模型复杂度提升没有实质意义。AIC 差值 2 以下通常视作无显著改进这是信息准则的经验阈值。5. 避坑指南新能源汽车销量数据特有的 4 个翻车现场5.1 现象一政策补贴退坡让序列整体突变长期预测偏高现象2019 年补贴大幅退坡后下半年销量环比下滑模型基于上半年趋势外推预测值明显高估。这类翻车在每次补贴政策调整周期都会出现。原因ARIMA 没有外部变量通道不知道“政策”这个外生冲击。序列在某个时间点发生了水平位移但自回归项仍按旧均值外推模型自己调整不过来。解决把训练数据截断在政策变化之后重新建模或者升级为 ARIMAX把补贴系数作为外生回归变量。更务实的做法是政策密集期不做长期预测只做未来 1 到 2 个月的短期滚动预测让模型在滚动中逐步吸收新水平。排产计划本身就适合短周期滚动不需要强行预测半年。5.2 现象二季度末冲量与春节带来的“假周期”现象每年 3 月、6 月、9 月、12 月销量明显抬高季节分解跑出一个“4 个月周期”但真实原因其实是渠道压库和季度末冲量。ARIMA 把这个当固定周期学进去下一年淡季会被预测成旺季。原因季节分解只能识别周期性识别不了周期的成因。促销、冲量、节假日错位形成的周期在年份之间不是严格等间隔的。春节每年日期不同低谷月未必永远是 2 月固定周期假设自然失效。解决把春节按农历对齐到同一个月或者用节假日哑变量做回归项。对季度末冲量要判断这种冲量是不是年年存在如果只是个别年份的渠道策略造成的宁可当异常值修掉也不要让模型去学一个不稳定的周期。这个判断需要业务侧确认不能只看统计图表。5.3 现象三新车型上市导致结构突变训练集和测试集不是同一个分布现象某品牌 2023 年上市一款爆款车型月销量从 2 万台跳到 6 万台。旧数据训练的 ARIMA 在新水平上预测误差动辄 30% 以上模型基本报废。原因ARIMA 建模的前提是序列统计性质相对稳定。新车型是一个典型的 regime shift均值、方差、自相关结构全变了旧历史对新未来没有信息量模型自然失效。解决以车型迭代为界截断训练集。如果不想丢失早期信息用分段建模把突变前和突变后各建一个模型或者用 ARIMAX 把车型数量、上市时间作为外生变量。但最踏实的做法是承认模型失效缩短预测步长等突变后积累 3 到 5 个月新数据再重建基准。硬撑着用旧模型不如直接告诉管理层“这个节点预测不可靠”。5.4 现象四差分两次后拟合极好但预测泛化差现象网格搜索跑出 d2、AIC 极低训练集拟合误差很小验证集预测一塌糊涂。这是典型的“训练场上的表演”。原因过度差分放大了高频噪声模型把噪声的短期相关性也学了进去。AIC 在二阶差分序列上偏低不等于真实预测表现好因为它衡量的是拟合优度不是验证集误差。解决用前向验证作为最终评估准则而不是只看 AIC。把 d1 和 d2 的模型各跑一次滚动回测比较验证集 RMSE选验证集上更好的那一个。这是整个 ARIMA 调参过程里最值得记住的一条模型选择看测试误差不看过拟合出来的好看曲线。6. 让预测真正进排产计划滚动回测与基线对比的验证方法一套模型定下来之前我会先做两件笨事跑一个滚动回测再和两个简单基线对比。滚动回测比一次性切分更接近生产环境因为生产里你每个月都要用最新数据重新拟合再预测未来几个月。def rolling_backtest(data, order, step6, train_min24): errors [] for start in range(train_min, len(data) - step 1): train data.iloc[:start] test data.iloc[start:start step] model ARIMA(train, orderorder).fit() pred model.forecast(step) errors.append(np.mean(np.abs(test.values - pred))) return np.mean(errors)这段代码每次用起点之前的所有数据训练预测接下来固定长度的窗口然后逐步推进。train_min24保证最早几轮也有足够样本。把所有窗口的平均绝对误差汇总才是一个可靠的精度估计。基线对比也是必须做的朴素预测直接用最近一个月的值外推季节朴素预测用去年同期的值移动平均用最近 3 个月均值。如果 ARIMA 在这些基线面前没有明显优势就不要上生产。我过去花三天调 SARIMA 的季节参数回测一看只比“去年同期乘一个系数”好 0.3%果断放弃。后来把精力转到数据清洗和异常值修正上预测精度反而提升了 8%。这件事让我养成了习惯任何时间序列项目先做两个笨基线再让 ARIMA 去拼拼过了才继续深挖。滚动回测还有个额外价值它能把不同窗口下的误差分布画出来让管理层看到“误差不是固定的而是随市场波动变化”。排产会上一张误差分布图比单点预测值更有说服力。希望这套从定阶到回测的流程能帮你在排产会上拿出有依据的数字而不是靠感觉拍板希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

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

尧图内容编辑团队

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

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

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

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

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

网站改版的5个关键决策

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

获取专属建站方案

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

立即免费咨询