Understanding the Seasonal Order of the SARIMA Model | by Angelica Lo Duca | Towards Data Science

Some months ago, I wrote an article, which described the full process to build a SARIMA model for time series forecasting. In that article, I explained how to tune the p, d and q order of a SARIMA model and I evaluated the performance of the trained model in terms of NRMSE.
One comment about that article was that the proposed model was basically an ARIMA model, since it did not consider the seasonal order. I thanked the comment’s author and I investigated this aspect.
And now I am here to explain you an interesting aspect that I discovered and that, unfortunately, it is not well explained in the articles that I found in the Web.
A SARIMA model can be tuned with two kinds of orders:
(p,d,q) order, which refers to the order of the time series. This order is also used in the ARIMA model (which does not consider seasonality);
(P,D,Q,M) seasonal order, which refers to the order of the seasonal component of the time series.
In this article, I focus on the importance of the seasonal order.
Firstly, I import the dataset related to tourists arrivals to Italy from 1990 to 2019 as as a pandas dataframe. Data are extracted from the European Statistics: Annual Data on Tourism Industries.
import pandas as pddf = pd.read_csv('source/tourist_arrivals.csv')df.head()
Now I convert the dataset into a time series. This can be done in three steps:
I convert the date column to the datetime type
I set the date column as index of the dataframe
I assign the value column of the dataframe to a new variable, called ts.
df['date'] = pd.to_datetime(df['date'])df.set_index('date', inplace=True)ts = df['value']
I explore the time series by plotting it. I exploit the matplotlib library.
from matplotlib import pyplot as pltplt.plot(ts, label='prediction seasonal')plt.grid()plt.xticks(rotation=90)plt.show()
I note that the time series presents a seasonality thus a SARIMA model is appropriate. In addition, the time series also presents an increasing trend.
Now I split the time series into two parts: train and test sets. Training set will be used to fit the model, while the test set will be use to evalute it.
ts_train = ts[:'2019-03-01']ts_test = ts['2019-04-01':]
Into another notebook, I have already explained how to calculate the (p,d,q) order of the SARIMA model, thus I set it manually to the discovered values:
d = 1p = 10q = 7
The (P,D,Q,M) Order refers to the seasonal component of the model for the Auto Regressive parameters, differences, Moving Average parameters, and periodicity:
D indicates the integration order of the seasonal process (the number of transformation needed to make stationary the time series)
P indicates the Auto Regressive order for the seasonal component
Q indicated the Moving Average order for the seasonal component
M indicates the periodicity, i.e. the number of periods in season, such as 12 for monthly data.
In order to evaluate the seasonal order, we must extract the seasonal component from the time series. For this reason, we exploit the seasonal_decompose() function provided by the statsmodels library. Among the input parameters, we can specify the decomposition model (additive or multiplicative) and if we want to extrapolate the trend or not. The function returns the trend, the seasonal and the resid components.
from statsmodels.tsa.seasonal import seasonal_decomposeresult = seasonal_decompose(ts, model='additive',extrapolate_trend='freq')result.plot()plt.show()
In order to extract D, we have to check whether the seasonal componenet is stationary or not. We define a function, which exploits the Adfuller test to check for stationarity.
from statsmodels.tsa.stattools import adfullerimport numpy as npdef check_stationarity(ts):    dftest = adfuller(ts)    adf = dftest[0]    pvalue = dftest[1]    critical_value = dftest[4]['5%']    if (pvalue < 0.05) and (adf < critical_value):        print('The series is stationary')    else:        print('The series is NOT stationary')
Then, we invoke the check_stationarity() function on the seasonal component of the time series:
seasonal = result.seasonalcheck_stationarity(seasonal)
The series is stationary, thus we do not need any additional transformation to make it stationary. We can set D = 0.
The value of P can be extracted by looking at the Partial Autocorrelation (PACF) graph of the seasonal component. PACF can be imagined as the correlation between the series and its lag, after excluding the contributions from the intermediate lags.
from statsmodels.graphics.tsaplots import plot_acf, plot_pacfplot_pacf(seasonal, lags =12)plt.show()
In the PACF graph the maximum lag with a value out the confidence intervals (in light blue) is 12, thus we can set P = 12.
The Q order can be calculated from the Autocorrelation (ACF) plot. Autocorrelation is the correlation of a single time series with a lagged copy of itself.
plot_acf(seasonal, lags =12)plt.show()
From the above graph, we note that the maximum lag with a value out the confidence intervals is 8, thus Q = 8.
In order to show the difference between a SARIMA model with and without the tuning of the (P,D,Q,M) order, we fit two models, the first without the seasonality order and second with it.
We exploit the SARIMAX() class of the statsmodels package and we configure it to work only with the (p,d,q) order.
from statsmodels.tools.eval_measures import rmsenrmse = rmse(ts_pred, ts_test)/(np.max(ts_test)-np.min(ts_test))nrmse
which gives the following output:
0.0602505102281063
We fit the model by also passing to it the seasonal_order parameter. This operation requires more than the previous one.
model_seasonal = SARIMAX(ts_train, order=(p,d,q), seasonal_order=(P,D,Q,12))model_fit_seasonal = model_seasonal.fit()
We calculate forecasts and NRMSE:
ts_pred_seasonal = model_fit_seasonal.forecast(steps=n_test)nrmse_seasonal = rmse(ts_pred_seasonal, ts_test)/(np.max(ts_test)-np.min(ts_test))nrmse_seasonal
which gives the following output:
0.08154124683514104
We note that the model without the seasonal order outperforms the other model, in terms of NRMSE.
Is the (P,D,Q,M) order useless? Indeed it is not. For short-term predictions, the two models behave almost in the same way. However, for long-term predictions, the model with the (P,D,Q,M) order is more realistic, since it reflects the increasing trend.
To explain this concept, we can calculate a long-term forecasting in both cases:
N = 300ts_pred = model_fit.forecast(steps=n_test+N)ts_pred_seasonal = model_fit_seasonal.forecast(steps=n_test+N)
and we can plot the results. We note that there is a big difference between the two models. While the model without the (P,D,Q,M) order tends to decrease over time, the other reflects the increasing trend.
plt.figure(figsize=(10,5))plt.plot(ts_pred_seasonal, label='prediction with P,D,Q')plt.plot(ts_pred, label='prediction without P,D,Q')#plt.plot(ts_test, label='actual')plt.title('Multi-step Forecasting (manual parameters)')plt.legend()plt.grid()plt.xticks(rotation=90)plt.show()
In this tutorial, I have explained the importance of the seasonal order in the SARIMA model for a long-term prediction.
All the code explained in this article can be downloaded from my Github repository as a Jupyter Notebook.
If you wanted to be updated on my research and other activities, you can follow me on Twitter, Youtube and and Github.