Seasonal ARIMA (SARIMA)

Python · R · time-series forecasting

Model

A seasonal ARIMA (SARIMA) extends Box–Jenkins ARIMA with seasonal terms, written SARIMA(p, d, q)(P, D, Q)[s]: regular and seasonal AR/MA orders, regular differencing dd to remove trend, and seasonal differencing DD to remove seasonality, at season length ss. The canonical case is the "airline model" SARIMA(0,1,1)(0,1,1)[12] — the one Box & Jenkins fit to the airline series — with one regular difference, one seasonal difference, and an MA(1) × seasonal-MA(1), no AR terms.

ϕp(B)ΦP(Bs)(1B)d(1Bs)Dyt=θq(B)ΘQ(Bs)εt\phi_p(B)\,\Phi_P(B^s)\,(1-B)^d(1-B^s)^D\,y_t = \theta_q(B)\,\Theta_Q(B^s)\,\varepsilon_t
SymbolPartMeaning
p/Pp\,/\,PAR / seasonal ARdependence on the last pp lags / last PP seasonal lags
d/Dd\,/\,Ddifferencing / seasonaldd removes trend; DD removes the seasonal pattern
q/Qq\,/\,QMA / seasonal MAdependence on the last qq shocks / last QQ seasonal shocks
ssseason length12 for monthly data

The airline model is (1B)(1B12)yt=(1+θB)(1+ΘB12)εt(1-B)(1-B^{12})\,y_t = (1+\theta B)(1+\Theta B^{12})\,\varepsilon_t.

Frequentist Box–Jenkins vs Bayesian structural

Two routes are compared. The frequentist Box–Jenkins workflow (identify → estimate by maximum likelihood via the Kalman filter → diagnose residuals) is run in statsmodels and R's forecast, with automatic order selection (auto_arima / auto.arima, the Hyndman–Khandakar stepwise AIC search). The Bayesian route is an interpretable structural regression — a linear trend + monthly seasonal dummies + AR(1) errors — fit by NUTS, giving full posterior-predictive forecast distributions. The two differ in how they handle seasonality: SARIMA uses seasonal differencing (1Bs1-B^s, stochastic seasonality that can drift), the structural model uses fixed monthly effects (deterministic seasonality) — both legitimate, and they forecast similarly when the seasonal shape is stable.

Notebooks

Five examples span the range of ARIMA behaviour — fixed-period seasonality, variable-period cyclicality, a near-deterministic trend-plus-season, a barely-forecastable business cycle, and a structural break — building the ARIMA → changepoint → regime-switching ladder. Example 1 — AirPassengers (multiplicative seasonality). Monthly airline passengers, 1949–1960 (Box & Jenkins): a clear upward trend and multiplicative seasonality (swings grow with the level), the textbook case for SARIMA on the log scale. Stationarity tests (ADF / KPSS, opposite nulls) call for a regular and a seasonal difference; both selectors pick the airline model SARIMA(0,1,1)(0,1,1)[12], residuals pass Ljung–Box, and the held-out 2 years forecast to MAPE ≈ 8–9%. A judgement caveat surfaces: left to choose dd itself, auto_arima picks d=0d=0, leaving the trend in and degrading the forecast — automated selectors still need the differencing pinned by the unit-root tests. Example 2 — Sunspots (cyclicality, not seasonality). Annual sunspot counts, 1700–2008: the famous ~11-year solar cycle is cyclicality — a variable, unknown period (~9–13 yr, wandering), not a fixed seasonal one. There is no seasonal differencing; the series is stationary (d=0d=0) and a plain AR(p) generates the pseudo-cycle through complex-conjugate roots whose angle sets the period. The ACF is a damped sine wave (vs. sharp seasonal spikes), all three engines select ~AR(9) and recover a ~10–11-year cycle (Yule's 1927 AR(2) on this very series was the original demonstration), and the forecast damps toward the mean within a cycle or two — a stochastic cycle is only predictable a short way out. The Bayesian AR adds a genuine posterior distribution over the cycle length, read from the complex roots of each draw. Example 3 — Mauna Loa CO₂ (near-deterministic trend + season). Monthly atmospheric CO₂, 1958–2001 (the Keeling curve): an accelerating upward trend plus a very regular additive annual cycle (~7 ppm, constant amplitude — so no log transform). STL splits it into a smooth trend, an almost perfectly repeating cycle, and a tiny remainder; auto_arima picks a parsimonious SARIMA, and the held-out 5 years forecast to MAPE ≈ 0.2% — among the most forecastable series anywhere, the opposite extreme from the damping sunspot cycle. Example 4 — US GNP growth (the business cycle). Quarterly real GNP growth, 1951–1984 (Hamilton 1989): the macroeconomic business cycle is cyclicality with no fixed period — recessions arrive irregularly. Growth is already stationary (a difference of log GNP, so d=0d=0) with only weak autocorrelation, so it is close to unforecastable: the ARMA's out-of-sample RMSE essentially ties predicting the mean and the forecast reverts within ~2 quarters — the honest empirical basis for "nobody forecasts GDP growth," the opposite extreme from CO₂. The Bayesian AR(1) puts ϕ0.3\phi \approx 0.3 (a growth-shock half-life under a quarter). Crucially, a linear ARMA is symmetric, but real recessions are sharper than expansions — which is exactly what the Markov-switching AR adds on this very series; ARMA is the linear benchmark it improves on. Example 5 — Nile river flow (structural break / intervention). Annual Nile flow at Aswan, 1871–1970, which drops abruptly around 1899 (the old Aswan dam). The lesson: an ignored level shift masquerades as non-stationarity — differencing "fixes" it mechanically, but the right model adds a step-dummy regressor (Box–Tiao intervention analysis: regression with ARIMA errors), giving a parsimonious stationary AR(1) with a clean estimate of the break (250\approx -250 units) and a lower AIC than a differenced ARIMA. The Bayesian version goes further — a changepoint model that estimates the break year itself as a parameter τ\tau, whose posterior concentrates tightly on 1899 without being told. A changepoint is "Markov-switching with a single, absorbing switch" — completing the ARIMA → changepoint → Markov-switching ladder. Together they bridge from seasonality/cyclicality through structural breaks toward the regime-switching and GARCH / stochastic-volatility work, where the variance (or the regime) itself becomes the moving part. Each example is cross-checked across statsmodels / pmdarima, PyMC, and R forecast.

Python AirPassengers — Box–Jenkins SARIMA: statsmodels SARIMAX + pmdarima auto_arima, out-of-sample forecast (Python) Open → Python AirPassengers — Bayesian structural: trend + seasonal + AR(1) errors via PyMC / NUTS, posterior-predictive (Python) Open → R AirPassengers — R forecast::auto.arima (Hyndman–Khandakar), Box–Cox log transform (R) Open → Python Sunspots — cyclicality via AR complex roots, damped forecast: statsmodels (Python) Open → Python Sunspots — Bayesian AR with a posterior over the ~11-year cycle period, PyMC / NUTS (Python) Open → R Sunspots — R ar() Yule-Walker + forecast, cycle from the AR roots (R) Open → Python CO₂ Mauna Loa — additive trend + seasonal SARIMA, STL, near-perfect 5-year forecast: statsmodels (Python) Open → Python CO₂ Mauna Loa — Bayesian structural: quadratic trend + seasonal + AR errors via PyMC / NUTS (Python) Open → R CO₂ Mauna Loa — R forecast::auto.arima, out-of-sample 5 years (R) Open → Python US GNP growth — business-cycle ARMA, weak persistence & mean-reverting forecast: statsmodels (Python) Open → Python US GNP growth — Bayesian AR(1), shock half-life from the posterior of φ, PyMC / NUTS (Python) Open → R US GNP growth — R forecast::auto.arima with NBER recessions shaded (R) Open → Python Nile flow — structural break / intervention (AR(1) + 1899 step dummy), Box–Tiao: statsmodels (Python) Open → Python Nile flow — Bayesian changepoint estimating the break year τ, PyMC / NUTS (Python) Open → R Nile flow — R break detection + Arima with step-dummy xreg (R) Open →

References

Downloads