The most cost-effective forecasting method on Earth was invented in the 1950s for inventory planning, runs in microseconds, and still embarrasses neural networks on short business series. Exponential smoothing starts from one psychological truth about time: recent observations matter more. Formalize that with geometric decay, add components the same way the decomposition lesson took them apart, and you get the ETS family — this lesson, and one of the two classical pillars (ARIMA, next lesson, is the other).
Simple exponential smoothing: one number, updated
Forecast with a single adaptive level :
Unroll the recursion and the name explains itself: — a weighted average with weights decaying geometrically into the past. is the memory dial: reproduces the naive forecast (last value, no memory), the long-run average (all memory, no reactivity). Written as it is error-correction: move the estimate a fraction α toward each surprise — the same update-on-surprise shape as SGD and, exactly, the Kalman filter with a fixed gain (lesson 4 makes that identity precise).
Add trend, add season: Holt–Winters
The decomposition lesson’s components return, but now each is tracked online with its own smoothing constant. Level, trend , and seasonal (period ), additive form:
Each line is the SES pattern applied to one component: deseasonalized surprise updates the level, level changes update the trend, level-adjusted surprise updates that season’s slot. Three dials, each meaning “how fast does this component change” — and the right values depend on the series, which is why you should now go feel them:
Start by wrecking it, because the failure modes teach the parameters. Set α = 1: the fit hugs the data perfectly — and the MAE readout gets WORSE, because chasing every wiggle means forecasting last month’s noise (α=1, β=0, γ=0 is precisely the naive method — check its MAE as your baseline). Set α ≈ 0.05: serene fits that lag every level shift by months. Now β: at 0.4 the trend estimate whips around and the 24-month extrapolation swings wildly — which is why practitioners damp trends (multiply by φ≈0.98 per step; Gardner’s damped trend wins forecasting competitions with boring regularity). γ moves the seasonal pattern’s adaptability. And watch the band: √h widening means the 2-year forecast is honest about being mostly uncertainty — a model that extrapolates confidently at h = 24 from 8 years of data is lying to you.
From smoother to model: ETS state space
As presented so far, Holt–Winters is an algorithm with no error bars — the band in the widget was bolted on from one-step errors. The modern fix (Hyndman et al., 2002) rewrites each smoother as a state-space model:
with the recursions above as the state transitions driven by the same
. Now it is a likelihood: the smoothing constants are
estimated by MLE instead of hand-tuning, models are compared by AIC, and
prediction intervals come from the model rather than a heuristic. The
taxonomy ETS(Error, Trend, Seasonal) — each Additive/Multiplicative/None,
damped or not — gives ~30 family members, and the ets() automation that
searches them by AIC is the single most used forecasting routine in
industry. The lesson’s through-line, one more time: heuristic, made
probabilistic, gains uncertainty and principled selection — the same
promotion k-means got from mixtures.
Two honest boundaries. ETS forecasts one series from its own past — no covariates, no cross-series learning (the neural lesson’s opening). And its seasonal component is periodic-with-drift, so genuinely new patterns (a pandemic, a product launch) are structural breaks it must re-learn through the α/γ dials, slowly.
import numpy as np, pandas as pd
from statsmodels.tsa.holtwinters import ExponentialSmoothing
rng = np.random.default_rng(0)
t = np.arange(96)
y = pd.Series(10 + 0.08*t + 2*np.sin(2*np.pi*t/12) + 0.7*rng.standard_normal(96),
index=pd.date_range("2018-01-01", periods=96, freq="MS"))
fit = ExponentialSmoothing(y, trend="add", seasonal="add",
seasonal_periods=12, damped_trend=True).fit()
print(fit.params["smoothing_level"], fit.params["smoothing_trend"],
fit.params["smoothing_seasonal"]) # MLE found the dials for you
print(fit.forecast(24).head()) # the widget's blue line
Exercises
Work these before the next lesson
- Unroll SES to the weighted-average form and verify the weights sum to 1 as . What is the “effective memory length” (sum of j·weight) as a function of α?
Solution
Worked solutions are part of Premium — unlock all of them for £5/month →
- 5 more exercises — each with a worked solution — are part of Premium. Unlock everything for £5/month →
References
- R. Hyndman & G. Athanasopoulos, Forecasting: Principles and Practice, ch. 8 — ETS in full.
- C. Holt (1957) & P. Winters (1960) — the original papers, born from inventory control.
- R. Hyndman, A. Koehler, R. Snyder & S. Grose, “A state space framework for automatic forecasting using exponential smoothing methods”, 2002 — the promotion to a statistical model.
- E. Gardner, “Exponential smoothing: the state of the art — Part II”, 2006 — including why damping wins.