Data setup: mexretail
mexretail was first introduced in Module 1 — Time Series Decomposition and has been our running dataset throughout Module 2.
Module 2 has added two new model families to our toolkit. Together with decomposition_model(), they give us far more combinations than it might initially seem:
| Approach | Decomposition | Trend-cycle | Seasonal |
|---|---|---|---|
| M1 baseline | STL | Drift | SNAIVE |
| STL + ETS | STL | ETS | SNAIVE |
| STL + ARIMA | STL | ARIMA | SNAIVE |
| STL + ETS + ARIMA | STL | ETS | ARIMA |
| STL + ARIMA + ETS | STL | ARIMA | ETS |
| ETS | — | ETS | ETS |
| SARIMA | — | ARIMA | ARIMA(P,D,Q)m |
decomposition_model() is more flexible than it looked
In the previous sections, we always let STL handle the seasonal component implicitly — which defaults to SNAIVE. But decomposition_model() lets you specify a model for each component separately. This opens up the mixed combinations in the middle of the table, and that is exactly what we explore here.
decomposition_model()Recall the structure of decomposition_model():
Each component has its own characteristics, and we can choose the best model for each one independently:
The constraint logic
| Component | What it contains | What to suppress |
|---|---|---|
season_adjust |
trend + cycle + remainder | seasonality → season("N") / PDQ(0,0,0) |
season_year |
seasonal pattern only | trend → trend("N") |
Rather than embedding the full decomposition_model() calls inside the mable, we define them as named objects first. This keeps the model comparison code clean and makes each specification easy to inspect and reuse.
season("N") suppresses seasonality — STL already removed it from season_adjust.
PDQ(0,0,0) suppresses seasonal ARIMA terms — not needed on the seasonally adjusted series.
ETS models the trend-cycle; ARIMA models the seasonal pattern:
ARIMA models the trend-cycle; ETS models the seasonal pattern:
PDQ(0,0,0) on the trend-cycle — no seasonal ARIMA terms needed.
trend("N") on the seasonal component — the seasonal pattern has no trend.
mexretailWith the specs defined, the mable is straightforward to read — each row is a named approach:
Reading the table
A MASE below 1 means the model beats the SNAIVE benchmark. Check where baseline lands — that is the floor set in Module 1. Everything above it in this ranking is a genuine improvement.
To check whether the rankings hold on a different series, we apply the same workflow to quarterly Australian beer production from fpp3:
Beer to y — the same convention used for mexretail. This is what allows the specs defined above to be reused directly.
Reusing model specs across series
Because both mexretail and beer use log(y) as the response variable, the specs defined above apply to both series without any modification. The mable for beer will look identical to the one for mexretail — the only difference is the tsibble being piped in.
This is the payoff of two conventions working together: naming your response variable y, and defining specs outside the mable.
Does the winner change?
Compare the ranking here against mexretail. Does the same approach win on both series? What does that tell you about when mixed decomposition models add value — and when they don’t?
| Approach | Seasonal pattern | Outlier robustness | Best when… |
|---|---|---|---|
| STL + ETS | Flexible, can evolve | High | Trend smooth; seasonality stable |
| STL + ARIMA | Flexible, can evolve | High | Trend has autocorrelation structure |
| STL + ETS + ARIMA | Flexible, can evolve | High | Trend smooth; seasonal has autocorrelation |
| STL + ARIMA + ETS | Flexible, can evolve | High | Trend autocorrelated; seasonal is level-shifting |
| ETS | Fixed structure | Moderate | Short series; no explicit decomposition needed |
| SARIMA | Fixed structure | Lower | Compact model preferred; longer series |
The guiding principle
No approach dominates universally. Always compare on a held-out test set. The mixed combinations (stl_ets_arima, stl_arima_ets) are not automatically better — they add flexibility but also complexity. Let the accuracy metrics decide.
We started Module 2 with a single question: can we do better than Drift and SNAIVE?
We replaced Drift with ETS — adaptive smoothing that weights recent observations more heavily and handles a wide range of trend and seasonal patterns. (Exponential Smoothing)
We formalized stationarity, and learned to use Box-Cox transformations, differencing, and unit root tests to prepare a series for ARIMA modeling. (Stationarity & Differencing)
We built ARIMA models — combining differencing, AR, and MA terms into a unified framework, applied both inside STL and as a standalone seasonal model. (ARIMA Models)
Today, we discovered that decomposition_model() lets us mix ETS and ARIMA freely across components — and saw that naming specs separately keeps model comparison code clean and reusable across series.
What’s still missing?
All models in Module 2 are univariate — they only look at the history of the series itself, with no knowledge of the world outside: promotions, holidays, economic conditions, competitor behavior.
In Module 3, we give our models that external context by introducing regression with time series errors.

Time Series Forecasting