smooth in Python: TBATS implementation

TBATS is a popular exponential smoothing model for data with complex seasonality: long seasonal periods, fractional ones (e.g. 52.18 weeks in a year, as I discussed in my previous post), and several of them at once. It models seasonality with harmonics and includes a Box-Cox transformation, ETS level and trend, and ARMA errors (De Livera, Hyndman & Snyder, 2011).

But the original formulation has an issue. Its ARMA part sits in the error term, which then updates all the other states, including the level. So, the level and the ARMA compete for the same dynamics, and as the AR parameter approaches one, the permanent effect of a shock on the level grows without limit.

Claude and I have now implemented TBATS in the smooth package for Python (and R), reusing the core of ADAM. Without ARMA, it is exactly the original model (to rounding error). But ARMA is now a separate component: the level keeps its share of every shock, and the effect of ARMA decays over time, as it should.

The ADAM framework also brings several features that other implementations don’t have:

  1. Explanatory variables, e.g. promotions or prices;
  2. Non-normal distributions, selected automatically;
  3. Treatment of missing values (e.g. weeks with stockouts);
  4. An occurrence model for intermittent demand.

These are not bells and whistles: real demand data has promotions, gaps and zeros, and a model that cannot handle them pushes you into pre-processing hacks.

Here is an example on weekly sales with two promotional campaigns:

from fcompdata import PromoData
from smooth import TBATS

model = TBATS(lags=[1, 52], h=13, holdout=True)
model.fit(PromoData.y, X=PromoData.xreg)
print(model)
fc = model.predict(h=13, interval="prediction", level=0.95)

The function selects the number of harmonics, the trend, the ARMA orders and the distribution automatically, and the effects of the promotions are estimated jointly with everything else.

Does it work? I compared it with forecast::tbats() in R and AutoTBATS from statsforecast for Python (paper), here are the main findings:

  • On 414 hourly series from M4, smooth was more accurate (mean RMSSE of 0.829 vs 0.909 and 1.063), its 95% prediction intervals had better coverage, and it was about 1.7 times faster than forecast::tbats().
  • On 370 hourly series of electricity demand, the accuracy was a tie (0.795 vs 0.799 and 0.795), but smooth had better coverage and was again faster.
  • Also, when I switched to the Normal distribution, the model became even faster, but its 95% intervals covered fewer values than they should, so the automatic selection of distribution seems to help.

The table in this post summarises the results. The details are here.

Try it: pip install smooth
Documentation

Leave a comment