Lesson 10 — Time Series for Business/Economics
(trend, forecasting baselines, and honest evaluation)
Time series mindset: time is not just another variable¶
In time series data, order matters.
Observations close in time are often related. Therefore:
we do not randomly shuffle time series data,
we split train/test by time,
and we avoid using future information to forecast the past.
Examples of time series data:
weekly sales,
monthly inflation,
daily stock prices,
quarterly GDP,
annual population,
daily website visits.
Unit of observation¶
Always ask:
What does one row represent?
Examples:
store-week,
country-year,
customer-month,
product-day.
The unit of observation affects what kind of patterns we can analyze.
Describing time series: trend, seasonality, and noise¶
A useful conceptual decomposition is:
Trend¶
Trend is the long-run movement of the series.
Examples:
sales gradually increasing,
population declining,
GDP per capita growing over time.
Seasonality¶
Seasonality is a regular pattern that repeats over time.
Examples:
higher sales in December,
lower restaurant traffic on Mondays,
quarterly production cycles.
Noise¶
Noise is irregular movement.
Examples:
one-off events,
measurement error,
weather shocks,
temporary demand changes.
People often interpret noise as signal, especially when they zoom in too much.
Smoothing can help reveal patterns, but smoothing can also hide real changes.
Forecasting as a benchmark game¶
Before using advanced forecasting models, always compare against simple baselines.
If a complicated model cannot beat a simple baseline, it may not be useful.
Today we focus on two simple forecasting methods:
Naïve forecast
Moving average forecast
Baseline 1: naïve forecast¶
The naïve forecast says:
The forecast for the next period equals the actual value from the previous period.
In notation:
For example, if sales in Week 4 were 45, then the naïve forecast for Week 5 is 45.
The naïve forecast is simple, but often surprisingly strong.
It is especially useful as a benchmark.
Baseline 2: moving average forecast¶
A moving average forecast uses the average of recent observations.
For a 3-period moving average:
For example, the forecast for Week 5 uses the average of Weeks 2, 3, and 4.
A moving average smooths short-run noise by averaging recent values.
A moving average may work well when the series fluctuates around a relatively stable level.
It may work less well when there is a strong trend or sudden structural break.
In-class Excel exercise: sales forecasting¶
We start with a small weekly sales dataset.
| Week | Sales |
|---|---|
| 1 | 39 |
| 2 | 44 |
| 3 | 40 |
| 4 | 45 |
| 5 | 38 |
| 6 | 43 |
| 7 | 39 |
We will forecast sales for Weeks 5, 6, and 7 using:
Naïve forecast
MA(3), a 3-week moving average forecast
Forecasting Weeks 5–7 manually¶
Naïve forecast¶
The naïve forecast uses the previous week’s actual sales.
| Week | Actual Sales | Naïve Forecast |
|---|---|---|
| 5 | 38 | 45 |
| 6 | 43 | 38 |
| 7 | 39 | 43 |
MA(3) forecast¶
The MA(3) forecast uses the average of the previous three actual values.
For Week 5:
For Week 6:
For Week 7:
| Week | Actual Sales | Naïve Forecast | MA(3) Forecast |
|---|---|---|---|
| 5 | 38 | 45 | 43 |
| 6 | 43 | 38 | 41 |
| 7 | 39 | 43 | 42 |
Forecast errors¶
Forecast error is:
A positive error means the forecast was too low.
A negative error means the forecast was too high.
| Week | Actual | Naïve | Naïve Error | MA(3) | MA(3) Error |
|---|---|---|---|---|---|
| 5 | 38 | 45 | -7 | 43 | -5 |
| 6 | 43 | 38 | 5 | 41 | 2 |
| 7 | 39 | 43 | -4 | 42 | -3 |
Forecast evaluation metrics¶
Mean Absolute Error¶
MAE is the average absolute forecast error.
It is easy to explain:
On average, the forecast misses by about ___ units.
Root Mean Squared Error¶
RMSE is the square root of the average squared forecast error.
RMSE penalizes large errors more heavily than MAE.
MAE is often easier to explain to non-technical audiences.
RMSE is useful when large errors are especially costly.
Excel task¶
In Excel, create columns:
WeekSalesNaiveMA_3Naive_ErrorMA3_ErrorNaive_Abs_ErrorMA3_Abs_ErrorNaive_Squared_ErrorMA3_Squared_Error
Then calculate:
MAE for naïve forecast,
MAE for MA(3),
RMSE for naïve forecast,
RMSE for MA(3).
Which method performs better for Weeks 5–7?
Does this mean it will always perform better?
How to evaluate forecasts¶
Forecast evaluation should be done on observations that were not used to construct the forecast.
For this small exercise:
Weeks 1–4 provide the history.
Weeks 5–7 are the forecast evaluation period.
For larger datasets:
train on earlier periods,
test on later periods.
Do not evaluate forecasts using future information that would not have been available at the time of forecasting.
Visual communication for time series¶
Useful plots include:
Line plot of actual values
Actual vs forecast plot
Forecast error plot
Rolling average plot, if the series is longer
For today’s small dataset, the most useful chart is:
actual sales vs naïve forecast vs MA(3) forecast.
Mini-lab: Google Colab¶
Use the Lesson 10 notebook here:
Python workflow¶
Step 1 — Create the data¶
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
df = pd.DataFrame({
"Week": [1, 2, 3, 4, 5, 6, 7],
"Sales": [39, 44, 40, 45, 38, 43, 39]
})
dfStep 2 — Create forecasts¶
# Naive forecast: this week's forecast = last week's actual sales
df["Naive"] = df["Sales"].shift(1)
# MA(3): average of previous 3 actual sales
df["MA_3"] = df["Sales"].rolling(window=3).mean().shift(1)
dfStep 3 — Focus on Weeks 5–7¶
forecast_df = df[df["Week"].isin([5, 6, 7])].copy()
forecast_dfExpected result:
| Week | Sales | Naive | MA_3 |
|---|---|---|---|
| 5 | 38 | 45.0 | 43.0 |
| 6 | 43 | 38.0 | 41.0 |
| 7 | 39 | 43.0 | 42.0 |
Plot actual sales and forecasts¶
plt.figure(figsize=(8, 5))
plt.plot(df["Week"], df["Sales"], marker="o", label="Actual Sales")
plt.plot(df["Week"], df["Naive"], marker="o", linestyle="--", label="Naive Forecast")
plt.plot(df["Week"], df["MA_3"], marker="o", linestyle="--", label="MA(3) Forecast")
plt.title("Actual Sales and Forecasts")
plt.xlabel("Week")
plt.ylabel("Sales")
plt.xticks(df["Week"])
plt.legend()
plt.show()Calculate forecast errors¶
forecast_df["Naive_Error"] = forecast_df["Sales"] - forecast_df["Naive"]
forecast_df["MA3_Error"] = forecast_df["Sales"] - forecast_df["MA_3"]
forecast_df["Naive_Abs_Error"] = forecast_df["Naive_Error"].abs()
forecast_df["MA3_Abs_Error"] = forecast_df["MA3_Error"].abs()
forecast_df["Naive_Squared_Error"] = forecast_df["Naive_Error"] ** 2
forecast_df["MA3_Squared_Error"] = forecast_df["MA3_Error"] ** 2
forecast_dfCalculate MAE¶
naive_mae = forecast_df["Naive_Abs_Error"].mean()
ma3_mae = forecast_df["MA3_Abs_Error"].mean()
print("Naive MAE:", round(naive_mae, 3))
print("MA(3) MAE:", round(ma3_mae, 3))Calculate RMSE¶
naive_rmse = np.sqrt(forecast_df["Naive_Squared_Error"].mean())
ma3_rmse = np.sqrt(forecast_df["MA3_Squared_Error"].mean())
print("Naive RMSE:", round(naive_rmse, 3))
print("MA(3) RMSE:", round(ma3_rmse, 3))Create a metric comparison table¶
metrics = pd.DataFrame({
"Method": ["Naive", "MA(3)"],
"MAE": [naive_mae, ma3_mae],
"RMSE": [naive_rmse, ma3_rmse]
})
metrics.round(3)Interpreting the results¶
For this small example:
The naïve forecast has MAE of about 5.0.
The MA(3) forecast has MAE of about 3.33.
The MA(3) forecast also has a lower RMSE.
Therefore, MA(3) performs better for forecasting Weeks 5–7 in this toy dataset.
This does not mean MA(3) will always be better.
The result depends on the data, the forecast period, and the pattern in the series.
Forecast memo template¶
Write a short memo using this structure:
Headline Which forecast performed better?
Evidence Compare MAE and/or RMSE.
Interpretation Why might this method work better for this series?
Caveat What could make the forecast fail?
Example:
For Weeks 5–7, the MA(3) forecast performed better than the naïve forecast. Its MAE was lower, meaning that on average it missed actual sales by fewer units. This suggests that averaging recent weeks helped smooth short-run fluctuations. However, the dataset is very small, and the result may not hold if there is a sudden change in demand, promotion, holiday effect, or structural break.
AI check: responsible use for time series¶
AI can help with code scaffolding and plot suggestions, but you must:
Ensure forecast calculations use only past information.
Verify formulas manually on a small example.
Avoid overconfident claims.
Record prompts and edits in your prompt/workflow log.
Good prompt examples:
Write Python code to compute a naive forecast and MA(3) forecast for weekly sales.Explain MAE and RMSE in plain language for a business audience.Help me write a cautious forecast memo comparing two baseline methods.Bad prompt example:
Guarantee which forecasting model will be best next month.In-class checkpoints¶
Enter the weekly sales data in Excel.
Compute the naïve forecast for Weeks 5–7.
Compute the MA(3) forecast for Weeks 5–7.
Compute forecast errors.
Compute MAE and RMSE.
Reproduce the same calculation in Python.
Plot actual sales and forecasts.
Compare the two methods.
Write a short forecast memo.
Submission after class¶
Submit either:
a Colab link with view permission, or
a PDF export of your notebook.
Your submission should include:
The actual vs forecast plot.
A metric comparison table with MAE and RMSE.
A short forecast memo:
headline,
evidence,
caveat.
A short AI-use note if AI tools were used.
Review questions¶
Why does time ordering matter in forecasting?
What is a naïve forecast?
What is a moving average forecast?
Why should forecast evaluation use data from the future relative to the training period?
What is the difference between MAE and RMSE?
Why might a simple baseline be useful even when advanced models are available?
What is one event or change that could cause a forecast to fail?
In about 200 words, describe your forecasting result:
which method performed better,
what evidence supports this,
why the method may have performed better,
and one forecast risk that could break the pattern.