ARIMA(p,d,q) 模型实战:Python statsmodels 库实现销售预测,RMSE 降低 15%
ARIMA(p,d,q) 模型实战:Python statsmodels 库实现销售预测,RMSE 降低 15%
当销售总监问"下个季度能卖多少"时,时间序列预测就是数据分析师的魔法水晶球。在众多预测工具中,ARIMA模型以其数学严谨性和业务解释性,成为销售预测的经典选择。本文将手把手带你用Python的statsmodels库,从数据清洗到模型部署,完整实现一个可落地的销售预测方案。
1. 环境准备与数据探索
工欲善其事,必先利其器。我们先配置好Python环境:
# 基础库 import numpy as np import pandas as pd import matplotlib.pyplot as plt %matplotlib inline # 时间序列专用 from statsmodels.tsa.stattools import adfuller # ADF检验 from statsmodels.graphics.tsaplots import plot_acf, plot_pacf # ACF/PACF from statsmodels.tsa.arima.model import ARIMA # ARIMA模型 from sklearn.metrics import mean_squared_error # 评估指标假设我们有一份2018-2022年的月度销售数据sales.csv,字段包括:
- date: 日期(YYYY-MM-DD)
- sales: 销售额(万元)
先进行基础探索:
df = pd.read_csv('sales.csv', parse_dates=['date']) df.set_index('date', inplace=True) print(df.head()) # 绘制原始序列 plt.figure(figsize=(12,6)) plt.plot(df, label='Raw Data') plt.title('Monthly Sales Trend') plt.legend()常见的数据问题及处理方法:
| 问题类型 | 检测方法 | 解决方案 |
|---|---|---|
| 缺失值 | df.isnull().sum() | 线性插值或前向填充 |
| 异常值 | 箱线图观察 | Winsorize处理或中位数替换 |
| 周期性 | 分解季节成分 | 季节差分或外部变量 |
| 趋势性 | ADF检验 | 常规差分或对数变换 |
2. 平稳化处理与参数确定
ARIMA建模的前提是序列平稳。我们先用ADF检验验证:
def adf_test(series): result = adfuller(series) print('ADF Statistic:', result[0]) print('p-value:', result[1]) print('Critical Values:', result[4]) adf_test(df['sales']) # 假设输出p值=0.8 > 0.05,不平稳进行一阶差分并重新检验:
df['diff_1'] = df['sales'].diff(1).dropna() adf_test(df['diff_1']) # p值=0.02 < 0.05,平稳此时d=1。接下来通过ACF/PACF图确定p和q:
fig, (ax1, ax2) = plt.subplots(2,1, figsize=(12,8)) plot_acf(df['diff_1'], lags=20, ax=ax1) plot_pacf(df['diff_1'], lags=20, ax=ax2) plt.show()根据图形特征:
- PACF在lag=2后截尾 → p=2
- ACF在lag=1后截尾 → q=1
也可以使用网格搜索确定最优参数:
best_aic = np.inf best_order = None for p in range(0, 3): for d in range(0, 2): for q in range(0, 3): try: model = ARIMA(df['sales'], order=(p,d,q)) results = model.fit() if results.aic < best_aic: best_aic = results.aic best_order = (p,d,q) except: continue print(f'Best ARIMA{best_order} with AIC={best_aic:.2f}')3. 模型训练与验证
拆分训练集和测试集(保留最后12个月验证):
train = df[:-12] test = df[-12:] model = ARIMA(train['sales'], order=(2,1,1)) model_fit = model.fit() print(model_fit.summary())关键输出解读:
coef列:各参数权重及显著性(P>|z|应<0.05)Ljung-Box:残差自相关检验(p值应>0.05)Jarque-Bera:残差正态性检验
进行滚动预测验证:
history = train['sales'].tolist() predictions = [] for t in range(len(test)): model = ARIMA(history, order=(2,1,1)) model_fit = model.fit() yhat = model_fit.forecast()[0] predictions.append(yhat) history.append(test['sales'][t]) rmse = np.sqrt(mean_squared_error(test['sales'], predictions)) print(f'Test RMSE: {rmse:.2f}')4. 预测优化与业务应用
通过以下技巧可进一步提升效果:
技巧1:Box-Cox变换处理异方差
from scipy.stats import boxcox train['trans'], lam = boxcox(train['sales']) # 预测后需用inv_boxcox还原技巧2:引入外部变量
# 添加促销活动指标 model = ARIMA(train['sales'], exog=train['promo'], order=(2,1,1))技巧3:残差诊断可视化
residuals = pd.DataFrame(model_fit.resid) residuals.plot(kind='kde') # 应接近正态分布最终预测未来12个月销售:
final_model = ARIMA(df['sales'], order=(2,1,1)) final_fit = final_model.fit() forecast = final_fit.get_forecast(steps=12) # 获取置信区间 conf_int = forecast.conf_int() forecast_index = pd.date_range(df.index[-1], periods=13, freq='M')[1:] # 可视化 plt.figure(figsize=(12,6)) plt.plot(df.index, df['sales'], label='Historical') plt.plot(forecast_index, forecast.predicted_mean, color='r', label='Forecast') plt.fill_between(forecast_index, conf_int.iloc[:,0], conf_int.iloc[:,1], color='pink', alpha=0.3) plt.title('12-Month Sales Forecast with 95% CI') plt.legend()将预测结果转化为业务建议:
- 库存准备:根据预测下限确保基础库存
- 营销预算:参考预测中值分配资源
- 风险预案:对置信区间上界做产能准备
