03 — Foundations

Decomposition#

FoundationsStatistical 1 min read
◆ The PatternSeparating signal from noise, season from trend

Decomposition splits a time series into three components: trend (long-term direction), seasonality (repeating patterns), and residual (noise). This reveals the structure hidden in raw data and guides model choice.

yt = Tt + St + Rt   (additive)   |   yt = Tt × St × Rt   (multiplicative)
Additive when seasonal amplitude is constant. Multiplicative when it grows with the level.
// Interactive — STL decomposition
Seasonal Period12
Trend Strength50
Pattern bridge: Decomposition mirrors eigendecomposition in linear algebra — both break a complex object into orthogonal components. In markets, separating trend from noise is the trader’s version of the same problem.
Worked example

Ten years of monthly data: a trend, a seasonal wave of amplitude 10, and noise with standard deviation 3. Classical decomposition — a centred 2×12 moving average for the trend, then the average deviation for each month — recovers a seasonal amplitude of 9.18 and leaves residuals with a standard deviation of 2.67, close to the noise that was put in.

Where it misleads
  • Classical decomposition assumes the seasonal pattern never changes; STL lets it evolve.
  • The centred moving average leaves no trend estimate for the first and last six months — exactly the most recent data you care about.
  • Additive and multiplicative seasonality give different pictures; if the swings grow with the level, take logs first.
In code
rng = np.random.default_rng(2)
t = np.arange(120)                                # ten years, monthly
season = 10 * np.sin(2 * np.pi * t / 12)
y = pd.Series(0.5 * t + season + rng.normal(0, 3, 120))
trend = y.rolling(12, center=True).mean().rolling(2, center=True).mean()   # centred 2x12 moving average
detr = y - trend
seasonal = detr.groupby(t % 12).transform('mean')
resid = y - trend - seasonal
amp = (seasonal.max() - seasonal.min()) / 2       # true amplitude is 10
Python, in your browser — edit the code and run it again

Assumes import numpy as np and import pandas as pd. Each snippet simulates or makes up its own series, as the comments say.

The same idea with a library
# Python — STL decomposition
from statsmodels.tsa.seasonal import STL

stl = STL(series, period=12, robust=True)
result = stl.fit()
result.plot()
# result.trend, result.seasonal, result.resid
Sources
  • R. B. Cleveland, W. S. Cleveland, J. E. McRae & I. Terpenning, “STL: A Seasonal-Trend Decomposition Procedure Based on Loess”, Journal of Official Statistics 6(1), 1990
  • Forecasting: Principles and Practice (3rd ed.), R. J. Hyndman & G. Athanasopoulos, OTexts, 2021

Last reviewed October 2026 · How this site checks its content · Report a mistake

Linked from 2
← Previous
Autocorrelation (ACF/PACF)
Open in the full reader, with the topic sidebar