Lesson 42 · Python For Time Series
Using Multilayer Perceptrons for Time Series Forecasting in Christian Analytics
In this lesson, you will learn what ensemble forecasting is and why it is so powerful for predicting things like sales, weather, or daily cases. We will use…
- CoursePython For Time Series
- Lesson42 of 30
- Video10 min
- FormatJupyter notebook · 17 code cells
What you'll learn
Data
No separate download needed — the notebook creates or downloads everything it uses.
📓 Full notebook
Download .ipynb
Welcome to Ensemble Forecasting for Time Series#
In this lesson, you will learn what ensemble forecasting is and why it is so powerful for predicting things like sales, weather, or daily cases.
We will use real-world data and build a simple ensemble model together.
No prior experience is needed let us explore time series and forecasting in Python step by step!
What is a Time Series?#
A time series is just a list of numbers arranged in order over time.
For example, the number of airline passengers each month or daily temperatures.
Time series forecasting tries to predict what will happen next!
import warnings; warnings.filterwarnings("ignore")
# Data setup
import pandas as pd
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv"
data = pd.read_csv(url, parse_dates=["Month"])
print("Shape:", data.shape)
print(data.head())
# Visualize the time series
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 4))
plt.plot(data["Month"], data["Passengers"], label="# Passengers")
plt.xlabel("Month")
plt.ylabel("Passengers")
plt.title("Airline Passengers Over Time")
plt.legend()
plt.show()
Why Use Ensembles?#
An ensemble combines predictions from several different models.
This can give us more accurate and stable forecasts.
Each model may make different mistakes, but together, their average prediction is often better!
That is like asking many people to guess the average guess is usually close to the truth.
# Prepare the data for modeling
data["Passengers"] = data["Passengers"].astype(float)
series = data["Passengers"]
train = series[:-12]
test = series[-12:]
print("Train size:", len(train), "Test size:", len(test))
# Naive Forecast: predicts last observed value
def naive_forecast(train, steps):
return [train.iloc[-1]] * steps
pred_naive = naive_forecast(train, len(test))
print("Naive forecast for next 3 months:", pred_naive[:3])
# Moving Average Forecast: uses last 3 values
def moving_average_forecast(train, steps, window=3):
avg = train.iloc[-window:].mean()
return [avg] * steps
pred_ma = moving_average_forecast(train, len(test))
print("Moving average forecast for next 3 months:", pred_ma[:3])
# Simple Exponential Smoothing
from statsmodels.tsa.holtwinters import SimpleExpSmoothing
model_exp = SimpleExpSmoothing(train).fit()
pred_exp = model_exp.forecast(len(test))
print("Exponential smoothing forecast for next 3 months:", pred_exp[:3].round())
# Compare models visually
plt.figure(figsize=(10,4))
plt.plot(test.index, test.values, label="Actual", marker="o")
plt.plot(test.index, pred_naive, label="Naive", linestyle="--")
plt.plot(test.index, pred_ma, label="Moving Avg", linestyle=":")
plt.plot(test.index, pred_exp, label="Exp Smoothing", linestyle="-.")
plt.title("Comparing Individual Models")
plt.legend()
plt.show()
What is an Ensemble?#
Now for the fun: let us combine our models!
An ensemble will simply average the predictions from each model.
By letting models "vote", we hope to reduce errors from any one model.
# Create a simple ensemble by averaging
import numpy as np
ensemble_pred = np.mean([pred_naive, pred_ma, pred_exp], axis=0)
print("First 3 ensemble forecasts:", ensemble_pred[:3].round())
# Visualize the ensemble against real data
plt.figure(figsize=(10,4))
plt.plot(test.index, test.values, label="Actual", marker="o")
plt.plot(test.index, ensemble_pred, label="Ensemble", color="red", linewidth=2)
plt.title("Ensemble Model vs Actual Data")
plt.legend()
plt.show()
# Calculate errors to compare models
from sklearn.metrics import mean_squared_error
def rmse(y_true, y_pred):
return mean_squared_error(y_true, y_pred, squared=False)
print("Naive RMSE:", rmse(test, pred_naive).round(2))
print("Moving Avg RMSE:", rmse(test, pred_ma).round(2))
print("Exp Smoothing RMSE:", rmse(test, pred_exp).round(2))
print("Ensemble RMSE:", rmse(test, ensemble_pred).round(2))
Real-World Example: Shampoo Sales Ensemble#
Let us see ensemble forecasting at work on a different real-world dataset: shampoo sales.
Ensembles are especially useful in business for planning and resources.
# Load Shampoo Sales Data
url2 = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/shampoo.csv"
sales = pd.read_csv(url2, parse_dates=["Month"])
sales["Sales"] = sales["Sales"].astype(float)
plt.figure(figsize=(10,4))
plt.plot(sales["Month"], sales["Sales"], label="Shampoo Sales")
plt.title("Monthly Shampoo Sales")
plt.xlabel("Month")
plt.ylabel("Sales Volume")
plt.legend()
plt.show()
# Practice: Build your own simple ensemble
practice_series = sales["Sales"]
train_s = practice_series[:-6]
test_s = practice_series[-6:]
naive_s = naive_forecast(train_s, len(test_s))
ma_s = moving_average_forecast(train_s, len(test_s), window=2)
exp_s = SimpleExpSmoothing(train_s).fit().forecast(len(test_s))
user_ensemble = np.mean([naive_s, ma_s, exp_s], axis=0)
plt.figure(figsize=(10,4))
plt.plot(test_s.index, test_s.values, label="Actual", marker="o")
plt.plot(test_s.index, user_ensemble, label="Your Ensemble", color="green")
plt.title("Your Ensemble on Shampoo Sales")
plt.legend()
plt.show()
# Challenge: Try user input for forecast length!
user_steps = int(input("How many future months would you like to forecast? (1-6): "))
if 1 <= user_steps <= 6:
user_pred = np.mean([
naive_forecast(practice_series[:-user_steps], user_steps),
moving_average_forecast(practice_series[:-user_steps], user_steps, window=2),
SimpleExpSmoothing(practice_series[:-user_steps]).fit().forecast(user_steps)
], axis=0)
print("Your ensemble for next", user_steps, "months:", user_pred.round())
else:
print("Please enter a number from 1 to 6.")
])
bm
## Best Practices Checkup
- Always use a baseline model like naive or moving average.
- Check your splits: do not peek at future data during training.
- Compare models with the same error measure (like RMSE).
- Visualize predictions; not just numbers.
- Try different ensemble mixes and look for improvement.
# Troubleshooting tips
try:
result = moving_average_forecast(train, -5)
except Exception as e:
print("Error:", str(e))
# Normally, steps must be positive!
# Extra tip: Weighted ensembles
weights = [0.2, 0.2, 0.6]
weighted_ensemble = np.average([pred_naive, pred_ma, pred_exp], axis=0, weights=weights)
print("Weighted ensemble (more weight on exp smoothing):", weighted_ensemble[:3].round())
Challenge Exercise#
- Try making your own ensemble including at least three different models.
- Test on both airline and shampoo data.
- Try using a different size for your moving average window.
Can your new ensemble beat the best single model?
Recap: What Have You Learned?#
- What a time series is
- How to create and compare basic forecasting models
- How to build an ensemble by combining forecasts
- Why ensembles are often more accurate
- Best practices for reliable time series forecasting
Keep Learning!#
If you enjoyed this lesson, give us a like and subscribe for more beginner-friendly Python tutorials.
Let us know in the comments what topics you want to see next!
Happy forecasting!
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



