Skip to main content
Back to module
Data Analytics in Practice · Metrics

Simple forecasting

Reading31mLesson 3 of 3 in this module

Forecast a business metric from its trend and seasonality, and check the forecast against held-out data.

Why it matters

Planning needs numbers about the future: how many support agents to schedule next quarter, how much stock to order, what revenue target is realistic. Analysts are often asked for "a forecast" with little time. You do not need advanced machine learning for most of these requests. A simple, transparent model that captures trend and seasonality, plus an honest error range, beats a black box nobody can explain.

The building blocks of a time series

Most business series can be described as:

  • Trend: the long-run direction (sales growing about 5 units per quarter).
  • Seasonality: a pattern that repeats with a fixed period (every Q4 is higher because of holidays; Mondays are busier than Sundays).
  • Noise (residual): what is left: random variation and one-off events.

Additive decomposition assumes value = trend + seasonal + noise, where the seasonal effect is a fixed number of units. Multiplicative decomposition assumes value = trend × seasonal × noise, where the effect is a percentage (Q4 is 15% above trend). Use multiplicative when the seasonal swings grow as the series grows.

Start with baselines

Before building anything, compute simple baselines. Any model you present must beat them:

  • Naive: next value = last value.
  • Seasonal naive: next value = value one season ago (next Q1 = this Q1).
  • Average: next value = historical mean.

Seasonal naive is surprisingly hard to beat for strongly seasonal data.

Worked example: trend plus seasonal index

Quarterly sales for three years:

Year 1: 212 189 177 231
Year 2: 235 207 199 254
Year 3: 254 231 218 276

1. Fit a linear trend. With time index t = 0..11, least squares gives about trend(t) = 194.6 + 5.27 t. In Python:

import statistics
slope, intercept = statistics.linear_regression(range(12), sales)

2. Compute residuals y[t] - trend(t), then average them by quarter. Q4 residuals are large and positive, Q3 negative. Centre the four averages so they sum to zero; these are the seasonal indexes, roughly +18, -12, -28, +22 for Q1 to Q4. (You will compute the exact values in the activity.)

3. Forecast each future quarter as trend plus its seasonal index. For t = 12 (next Q1): 194.6 + 5.27 × 12 + 18.0 ≈ 276.

4. Check accuracy on held-out data. Fit on years 1 and 2 only, forecast year 3, and compare with what actually happened using the mean absolute error (MAE): the average of |actual − forecast|. Also report MAPE (mean absolute percentage error) if stakeholders think in percentages. Compare with the seasonal naive baseline's MAE. This is called a backtest.

Doing it with libraries

On your own machine you would usually use a library:

import pandas as pd
from statsmodels.tsa.seasonal import seasonal_decompose
from statsmodels.tsa.holtwinters import ExponentialSmoothing

s = pd.Series(sales, index=pd.period_range("2024Q1", periods=12, freq="Q"))
parts = seasonal_decompose(s, model="additive", period=4)   # trend, seasonal, resid
model = ExponentialSmoothing(s, trend="add", seasonal="add", seasonal_periods=4).fit()
print(model.forecast(4))

Holt-Winters exponential smoothing weights recent data more heavily, which helps when the trend changes. Other common tools are ARIMA models and Meta's Prophet library. Spreadsheet users have FORECAST.ETS in Excel. All of them build on the same trend-and-season ideas.

Communicate the uncertainty

A single forecast number will be wrong. Give a range. A simple, honest approach: use the backtest errors. If past quarterly errors were within about ±12 units, say "next Q1: about 276, likely between 264 and 288." Libraries can produce formal prediction intervals.

Also state the assumptions: "assumes no major price change and that the current growth continues."

Common mistakes

  • No baseline comparison. A complex model that loses to seasonal naive is not useful.
  • Testing on the training data. Always hold out the most recent periods.
  • Too little history. You need at least two full seasonal cycles to estimate seasonality, preferably more.
  • Ignoring known events. Promotions, price changes and outages distort the history; note or adjust them.
  • Extrapolating a straight line forever. Trends bend. Keep horizons short and refresh forecasts regularly.

Quick recap

  • Series = trend + seasonality + noise (additive or multiplicative).
  • Beat naive and seasonal-naive baselines.
  • Trend line + centred seasonal indexes gives a transparent forecast.
  • Backtest with MAE on held-out periods, and always give a range.

Try it

In the Do tab, fit a trend, compute seasonal indexes and forecast four quarters using only Python's standard library.

Also in this lesson: