Playground: Chapter 16

Time Series Forecasting

This page practises the ideas of Chapter 16 in four parts. Practise the chapter works through the book’s exercises, with starter code, hints, and solutions. Go further goes beyond the book, with new questions and real time series datasets. Check your understanding asks short questions whose answers open with a click. Do it yourself gives open tasks with an empty code space and no answers: you forecast and report yourself, as you will in your own thesis.

In the exercises below, replace each ______ with your own code and press Run Code.

Practise the chapter

These are the exercises at the end of Chapter 16, with the same numbers.

Exercise 1: Benchmarks for a series with a trend

Predict which of the three benchmarks (mean, naive, seasonal naive) would be best for a series with a trend but no seasonality. Then test your prediction on the chapter’s clinic series after adding a steady increase of one visit a day.

NoteHint

The seasonal naive method repeats the last full cycle: for daily data with weekly seasonality, that is the last seven days (indices 7 to 14 in 0-based Python slicing).

TipSolution
snaive_fc = clinic_trend[7:14]

For a series with a trend and no seasonality, the naive method is best of the three: the last value is closer to the future than the average of a rising series. Because this clinic series has strong weekly seasonality, seasonal naive achieves an MAE of 7.0 (vs 10.7 for naive and 11.0 for mean), but it misses the steady growth.

Exercise 2: The seasonally adjusted series

Decompose the counselling series, calculate the seasonally adjusted series (the series minus its seasonal component), and print its yearly averages.

NoteHint

The series is the sum of trend, season, and remainder; removing the seasonal component means subtracting it (-).

TipSolution
adjusted = visits['visits'] - stl_res.seasonal

Without the large seasonal swings, the gradual upward trend is clear: average demand rises steadily from 30.7 visits/week in 2020/21 up to 37.6 in 2024/25.

Exercise 3: Fewer or more waves

Refit the Fourier model with \(K = 2\), \(K = 6\), and \(K = 12\), and explain how and why the test accuracy changes.

NoteHint

The third model uses \(K = 12\) harmonic pairs.

TipSolution
for K_val in [2, 6, 12]:

With \(K = 2\), the waves are too smooth and broad. With \(K = 6\) and \(K = 12\), the model bends more to capture peaks, but each pair adds two parameters. In all cases, smooth sinusoidal waves struggle with the sudden step drop in summer.

Exercise 4: Three years of training

Train models on the first three academic years and test on the fourth (2023/24).

NoteHint

For Year 4, the seasonal naive forecast copies Year 3 (year_of(3)).

TipSolution
snaive_fc = year_of(3)

Seasonal naive reaches an MAE of 6.6 visits/week. Averaging Years 2 and 3 and adding 6% annual growth gives 6.0 visits/week, smoothing out single-year idiosyncrasies.

Exercise 5: Visits before the first exam period

Simulate 1,000 futures to estimate how many visits to expect in the four weeks before the first exam period of 2025/26 (weeks 12 to 15), with a 95% interval.

TipSolution

The simulated futures indicate a median expectation of ~193 visits across the 4 pre-exam weeks, with a 95% prediction interval spanning roughly 151 to 247 visits.

Exercise 6: Explaining a prediction interval

Write a short paragraph for the counselling service explaining what a 95% prediction interval means. Write your answer first, then open the model answer.

“For each week, the forecast gives a most likely number of visits and a range. The 95% prediction interval is the range within which we expect the actual number of visits to fall in 19 weeks out of 20, if the patterns of the past five years continue. It is wide because demand varies from week to week for reasons no forecast can know, such as an awareness campaign or a difficult exam. Plan for the middle of the range, and keep in mind that about one week in 20 will fall outside it.”

Exercise 7: Twice the noise

In the artificial series at the start of the chapter, double the standard deviation of the noise. Describe how the sum changes.

NoteHint

Double the original noise standard deviation of 3.0 to 6.0.

TipSolution
for noise_sd in [3.0, 6.0]:

With twice the noise, the weekly fluctuations are doubled, obscuring the seasonal wave and doubling the width of forecast prediction intervals.

Go further

These exercises go beyond the book.

Exercise 8: Build a series and forecast with growth

Build a weekly series of your own for four years from a trend (50 visits rising by 0.1 a week), a seasonal wave of 15, and noise with an SD of 4. Forecast the fourth year from the first three.

NoteHint

The trend adds 0.1 per week; over 52 weeks, the growth is 0.1 * 52 = 5.2.

TipSolution
growth_52 = 0.1 * 52

Seasonal naive with growth brings MAE down from 7.5 to 4.5, close to the irreducible random noise standard deviation.

Exercise 9: Autocorrelation by hand

Calculate the autocorrelation of the counselling series at lags 1 and 52 by hand using np.corrcoef(), and compare with acf().

NoteHint

For lag 52, pair elements starting from index 52 (x[52:]) with elements up to x[:-52].

TipSolution
r52 = np.corrcoef(x[52:], x[:-52])[0, 1]

At lag 1 both methods agree (0.69). At lag 52 the correlation is strong (~0.68 to 0.87), proving the pronounced annual seasonality.

Exercise 10: Airline passengers and growing swings

The flights.csv dataset contains monthly passenger numbers (in thousands) from 1949 to 1960. Compare seasonal swings on the raw scale and on the logarithmic scale.

TipSolution

On the raw scale, seasonal swings expand from 44 to 232 thousand passengers as the total volume grows. On the log scale, swings remain nearly constant (0.35 to 0.47), demonstrating why log transformations are required for multiplicative time series.

Exercise 11: Carbon dioxide and the missing trend

The co2.csv dataset contains monthly atmospheric CO₂ concentrations from 1959 to 1997. Forecast the final two years (24 months) using benchmarks.

NoteHint

Annual growth in monthly data is the difference across 12 months (tr_co2[-1] - tr_co2[-13]).

TipSolution
annual_growth = tr_co2[-1] - tr_co2[-13]

Accounting for annual growth reduces the forecasting error from 2.3 ppm down to ~0.4 ppm.

Check your understanding

Answer each question in your own words first, then click to see a model answer.

1. Why are the observations of a time series not independent?

Because each observation carries over much of what shaped the one before it: the same students, the same academic term, and ongoing circumstances. This serial correlation is what makes forecasting possible.

2. What is the difference between trend, season, and noise?

  • Trend: the long-term direction of the series (growth or decline over years).
  • Season: a periodic pattern that repeats over a fixed interval (e.g. 52 weeks or 12 months).
  • Noise: irregular, unpredictable variation that cannot be forecast.

3. Why must the test period come after the training period?

Because a real forecast can only use past data. Random splitting across time would allow future information to leak into past estimates.

4. What is a prediction interval?

A range within which a future observation is expected to fall with a given probability (e.g. 95%), reflecting both model estimation uncertainty and future random noise.

5. Why should every forecast be compared with benchmarks?

Benchmarks show what the simplest rules (like copying last year’s value) can achieve. A complex forecasting model is only justified if it beats these baselines.

Do it yourself

These tasks have no starter code and no answers. Write your own code, as you would for a thesis.

1. Using flights.csv or co2.csv, plot the series, fit an exponential smoothing or SARIMAX model, evaluate on a held-out test year, and report your forecasts with prediction intervals.

2. Write a short report for the counselling service summarising next year’s expected demand, identifying peak periods, and quantifying uncertainty.

3. Describe three real-world changes that could violate your model’s assumptions, and how an analyst would detect them early in the academic year.

Work on your own computer

NoteDownload the Chapter 16 project

The project contains the datasets and all four parts of this page as a Python script (exercises.py). Answers to the questions are in solutions.py, and the open tasks have space to write your code.