本文使用的数据集来自 kaggle:M5 Forecasting — Accuracy。该数据集包含有 California、Texas、Wisconsin 三个州的产品类别、部门、仓储信息等。基于这些数据,需要预测接下来 28 天的每日销售量。
本文代码 github见最后部分
涉及到的方法有:
- 单指数平滑法
- 双指数平滑法
- 三指数平滑法
- ARIMA
- SARIMA
- SARIMAX
- Light Gradient Boosting
- Random Forest
- Linear Regression
为了使用上述方法,首先导入相应的包/库:
import time import warnings import numpy as np import pandas as pd import seaborn as sns import lightgbm as lgb from itertools import cycle from sklearn.svm import SVR import statsmodels.api as sm from pmdarima import auto_arima import matplotlib.pyplot as plt from datetime import datetime, timedelta from sklearn.metrics import mean_squared_error from sklearn.linear_model import LinearRegression from sklearn.ensemble import RandomForestRegressor from statsmodels.graphics.tsaplots import plot_acf from statsmodels.tsa.holtwinters import SimpleExpSmoothing, ExponentialSmoothing %matplotlib inline plt.style.use('bmh') sns.set_style("whitegrid") plt.rc('xtick', labelsize=15) plt.rc('ytick', labelsize=15) warnings.filterwarnings("ignore") pd.set_option('max_colwidth', 100) pd.set_option('display.max_rows', 500) pd.set_option('display.max_columns', 500) color_pal = plt.rcParams['axes.prop_cycle'].by_key()['color'] color_cycle = cycle(plt.rcParams['axes.prop_cycle'].by_key()['color'])
然后导入数据集:
data = pd.read_csv('data_for_tsa.csv') data['date'] = pd.to_datetime(data['date']) data.head()
数据集前五行数据
数据集包含了 2011-01-29 到 2016-05-22 期间的 1941 天的数据。其中最后 28 天作为测试集。
预测目标是 demand
,即:当日的产品销售量。
接下来进行数据集划分
测试集包含了 2016-03-27 到 2016-04-24 期间的 28 天的数据。2016-03-27 之前的其他数据则作为训练数据。
train = data[data['date'] <= '2016-03-27'] test = data[(data['date'] > '2016-03-27') & (data['date'] <= '2016-04-24')] fig, ax = plt.subplots(figsize=(25,5)) train.plot(x='date',y='demand',label='Train',ax=ax) test.plot(x='date',y='demand',label='Test',ax=ax);
时间序列数据
为了便于对比所有方法的准确性,建立一个命名为 predictions
的 dataframe,将每个方法设为其中的一行。建立一个命名为stats
的 dataframe,用于存储每个方法的性能表现和计算时间。
predictions = pd.DataFrame() predictions['date'] = test['date'] stats = pd.DataFrame(columns=['Model Name','Execution Time','RMSE'])
训练及评价模型
单指数平滑方法
通过调用 SimpleExpSmoothing
包,可以使用 EWMA, Exponentially Weighted Moving Average方法——一种单指数平滑方法。
使用 EWMA 方法,我们首先需要定义 span
变量——数据集的季节周期。
fig, ax = plt.subplots(figsize=(15, 3)) plot_acf(data['demand'].tolist(), lags=60, ax=ax);
自相关图
查看数据的自相关图可知,每隔七个数据,达到一个峰值,也就意味着任一数据与之前的第七个时间数据具有较高的相关性。所以这里将 span
设为 7。
具体地,通过以下代码实现单指数平滑方法预测:
t0 = time.time() model_name='Simple Exponential Smoothing' span = 7 alpha = 2/(span+1) #train simpleExpSmooth_model = SimpleExpSmoothing(train['demand']).fit(smoothing_level=alpha,optimized=False) t1 = time.time()-t0 #predict predictions[model_name] = simpleExpSmooth_model.forecast(28).values #visualize fig, ax = plt.subplots(figsize=(25,4)) train[-28:].plot(x='date',y='demand',label='Train',ax=ax) test.plot(x='date',y='demand',label='Test',ax=ax); predictions.plot(x='date',y=model_name,label=model_name,ax=ax); #evaluate score = np.sqrt(mean_squared_error(predictions[model_name].values, test['demand'])) print('RMSE for {}: {:.4f}'.format(model_name,score)) stats = stats.append({'Model Name':model_name, 'Execution Time':t1, 'RMSE':score},ignore_index=True)
单指数平滑方法预测结果
上述代码实现了对于数据的学习,通过 forcast(x),x=28
,预测了接下来 28 天的数据。并且通过均方根误差衡量误差。