What are trend, seasonality, and residual in time series decomposition, and how do you extract them?
Decomposition separates a series into a trend component (long-run direction), a seasonal component (periodic, fixed-period pattern), and a residual (everything left over). Additive decomposition sums the three; multiplicative decomposition multiplies them, which is appropriate when seasonal swings grow with the level.
How to think about it
Define each component clearly, explain additive vs multiplicative, then show the statsmodels call. A common follow-up is “how would you decide which model to use?” — have an answer ready.
The three components
Trend captures the overall direction over the full series — growth, decline, or a curve. It varies slowly and is usually estimated with a centred moving average.
Seasonality is a pattern that repeats at a known, fixed period — weekly, monthly, quarterly. It captures day-of-week effects in web traffic or a December spike in retail.
Residual (or remainder/noise) is what’s left after removing trend and seasonality. Ideally it looks like white noise; persistent structure in the residual means the decomposition is incomplete.
Additive vs multiplicative
- Additive: Yt = Tt + St + Rt — use when the size of seasonal swings is roughly constant regardless of the trend level.
- Multiplicative: Yt = Tt × St × Rt — use when seasonal swings grow proportionally with the trend (common in retail sales, stock volumes).
A log transform converts multiplicative to additive: log(Yt) = log(Tt) + log(St) + log(Rt).
Code
from statsmodels.tsa.seasonal import seasonal_decompose
import pandas as pd
df = pd.read_csv("monthly_sales.csv", parse_dates=["date"], index_col="date")
df = df.asfreq("MS") # set monthly start frequency
result = seasonal_decompose(df["sales"], model="multiplicative", period=12)
result.plot()
STL decomposition — a more robust alternative
seasonal_decompose uses a simple moving average, which handles outliers poorly. STL (Seasonal and Trend decomposition using Loess) is more robust and allows the seasonal component to change over time.
from statsmodels.tsa.seasonal import STL
stl = STL(df["sales"], period=12, robust=True)
res = stl.fit()
res.plot()