Mathew K Analytics

Lesson 14 · Python For Time Series

Master Rolling Mean & Exponential Moving Average in Python for Time Series Analysis

Welcome! In this lesson, we will learn two key ways to analyze trends in data: rolling mean and exponential moving average. These tools help us smooth out…

⬇ Download notebookOpen in Colab ↗

What you'll learn

Data

No separate download needed — the notebook creates or downloads everything it uses.

📓 Full notebook

Download .ipynb
 

Rolling Mean and Exponential Moving Average in Python#

Welcome! In this lesson, we will learn two key ways to analyze trends in data: rolling mean and exponential moving average. These tools help us smooth out noisy data to see underlying patterns.

By the end, you will know how to use them on real-world datasets and apply them to your own projects.

# Let us turn off warnings for a smoother experience.
import warnings
warnings.filterwarnings("ignore")
# Let us import the libraries we need.
import pandas as pd
import matplotlib.pyplot as plt

What is a Rolling Mean?#

A rolling mean, also called a moving average, calculates the average value over a sliding window in your data.

It helps you spot trends by smoothing out short-term ups and downs.

# Data setup: let us load monthly airline passenger data.
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv"
df = pd.read_csv(url)
print("Shape:", df.shape)
df.head()
Shape: (144, 2)
Month Passengers
0 1949-01 112
1 1949-02 118
2 1949-03 132
3 1949-04 129
4 1949-05 121
# Let us plot the passenger numbers over time.
plt.figure(figsize=(10,4))
plt.plot(df['Passengers'])
plt.title("Airline Passengers Over Time")
plt.xlabel("Month")
plt.ylabel("Number of Passengers")
plt.show()
No description has been provided for this image

Rolling Mean in Practice#

We can use pandas to calculate a rolling mean using the .rolling() and .mean() methods.

Let us start with a window size of 3 months. This means our mean at each point is the average of that month and the two before.

# Calculate the 3-month rolling mean and add as a new column.
df['RollingMean3'] = df['Passengers'].rolling(window=3).mean()

# Show the result for the first 10 rows
df[['Passengers', 'RollingMean3']].head(10)
Passengers RollingMean3
0 112 NaN
1 118 NaN
2 132 120.666667
3 129 126.333333
4 121 127.333333
5 135 128.333333
6 148 134.666667
7 148 143.666667
8 136 144.000000
9 119 134.333333
# Let us plot the original data and the rolling mean.
plt.figure(figsize=(10,4))
plt.plot(df['Passengers'], label='Original')
plt.plot(df['RollingMean3'], label='3-Month Rolling Mean', color='orange')
plt.title("Passengers and Rolling Mean")
plt.xlabel("Month")
plt.ylabel("Number of Passengers")
plt.legend()
plt.show()
No description has been provided for this image

Exponential Moving Average (EMA)#

A rolling mean averages all values in its window equally. But what if we want to give more weight to newer months?

That is what an Exponential Moving Average does. It reacts faster to new changes.

# Calculate the Exponential Moving Average (span=3 months)
df['EMA3'] = df['Passengers'].ewm(span=3, adjust=False).mean()

# Show first 10 values for comparison
df[['Passengers', 'RollingMean3', 'EMA3']].head(10)
Passengers RollingMean3 EMA3
0 112 NaN 112.000000
1 118 NaN 115.000000
2 132 120.666667 123.500000
3 129 126.333333 126.250000
4 121 127.333333 123.625000
5 135 128.333333 129.312500
6 148 134.666667 138.656250
7 148 143.666667 143.328125
8 136 144.000000 139.664062
9 119 134.333333 129.332031
# Plot all three: original, rolling mean, E M A.
plt.figure(figsize=(10,4))
plt.plot(df['Passengers'], label='Original')
plt.plot(df['RollingMean3'], label='3-Month Rolling Mean', color='orange')
plt.plot(df['EMA3'], label='EMA (Span=3)', color='green')
plt.title("Rolling Mean vs EMA")
plt.xlabel("Month")
plt.ylabel("Passengers")
plt.legend()
plt.show()
No description has been provided for this image
# Try using a bigger window for rolling mean and E M A (12 months).
df['RollingMean12'] = df['Passengers'].rolling(window=12).mean()
df['EMA12'] = df['Passengers'].ewm(span=12, adjust=False).mean()

plt.figure(figsize=(10,4))
plt.plot(df['Passengers'], label='Original', alpha=0.5)
plt.plot(df['RollingMean12'], label='12-Month Rolling Mean', color='red')
plt.plot(df['EMA12'], label='EMA (Span=12)', color='purple')
plt.title("Yearly Rolling Mean and EMA")
plt.xlabel("Month")
plt.ylabel("Passengers")
plt.legend()
plt.show()
No description has been provided for this image
# Using input to pick a window size for rolling mean.
window = int(input("Enter a window size (number of months) for rolling mean: "))
df['UserRollingMean'] = df['Passengers'].rolling(window=window).mean()

plt.figure(figsize=(10,4))
plt.plot(df['Passengers'], label='Original')
plt.plot(df['UserRollingMean'], label=f'Rolling Mean (Window={window})', color='orange')
plt.title(f'Rolling Mean with Window {window}')
plt.xlabel("Month")
plt.ylabel("Passengers")
plt.legend()
plt.show()
No description has been provided for this image
 
# Check for missing values after rolling mean.
missing = df['UserRollingMean'].isna().sum()
print(f"Missing values in UserRollingMean: {missing}")
Missing values in UserRollingMean: 5
# Fill missing values with the column's first valid value.
df['UserRollingMeanFilled'] = df['UserRollingMean'].fillna(method='bfill')
df[['UserRollingMean', 'UserRollingMeanFilled']].head(window+2)
UserRollingMean UserRollingMeanFilled
0 NaN 124.5
1 NaN 124.5
2 NaN 124.5
3 NaN 124.5
4 NaN 124.5
5 124.5 124.5
6 130.5 130.5
7 135.5 135.5
# Rolling mean with an odd window, such as 5 months.
df['RollingMean5'] = df['Passengers'].rolling(window=5, min_periods=1).mean()
df[['Passengers', 'RollingMean5']].head(7)
Passengers RollingMean5
0 112 112.000000
1 118 115.000000
2 132 120.666667
3 129 122.750000
4 121 122.400000
5 135 127.000000
6 148 133.000000

Real-World Use Case#

Rolling means and EMAs are helpful in many fields:

  • Stock market trends
  • COVID-19 case smoothing
  • Weather forecasting
  • Website visitor analysis

Let us use what you have learned on a new dataset next.

# Mini project: Daily minimum temperatures dataset.
temp_url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/daily-min-temperatures.csv"
temps = pd.read_csv(temp_url)
print("Shape:", temps.shape)
temps.head()
Shape: (3650, 2)
Date Temp
0 1981-01-01 20.7
1 1981-01-02 17.9
2 1981-01-03 18.8
3 1981-01-04 14.6
4 1981-01-05 15.8
# Plot daily temperatures for one year.
temps['Date'] = pd.to_datetime(temps['Date'])
one_year = temps[temps['Date'].dt.year == 1981]
plt.figure(figsize=(10,4))
plt.plot(one_year['Date'], one_year['Temp'], label='Daily Min Temp')
plt.title("Daily Min Temperature (1981)")
plt.xlabel("Date")
plt.ylabel("Temp (C)")
plt.legend()
plt.show()
No description has been provided for this image
# Compute and plot 7-day rolling mean and E M A
one_year['Rolling7'] = one_year['Temp'].rolling(window=7).mean()
one_year['EMA7'] = one_year['Temp'].ewm(span=7, adjust=False).mean()
plt.figure(figsize=(10,4))
plt.plot(one_year['Date'], one_year['Temp'], label='Daily Min Temp', alpha=0.3)
plt.plot(one_year['Date'], one_year['Rolling7'], label='7-Day Rolling Mean', color='orange')
plt.plot(one_year['Date'], one_year['EMA7'], label='EMA (Span=7)', color='green')
plt.title("7-Day Rolling Mean and E M A of Temperatures")
plt.xlabel("Date")
plt.ylabel("Temp (C)")
plt.legend()
plt.show()
No description has been provided for this image

Best Practices and Troubleshooting#

  • Try different window sizes to see what fits your data best.
  • Watch out for missing values after rolling.
  • Use rolling mean for gradual trends, and EMA when you need quicker changes.

If graphs look strange, check for outliers or missing entries.

# Challenge: Ask the user for a span value for E M A calculation.
span = int(input("Enter a span (number of days) for EMA: "))
one_year['ChallengeEMA'] = one_year['Temp'].ewm(span=span, adjust=False).mean()
plt.figure(figsize=(10,4))
plt.plot(one_year['Date'], one_year['Temp'], label='Daily Min Temp', alpha=0.3)
plt.plot(one_year['Date'], one_year['ChallengeEMA'], label=f'EMA (Span={span})', color='green')
plt.title(f'Challenge: EMA with Span {span}')
plt.xlabel("Date")
plt.ylabel("Temp (C)")
plt.legend()
plt.show()
No description has been provided for this image
 

Recap#

We practiced rolling mean and exponential moving average on real data.

  • Rolling mean gives equal weight to each point in the window.
  • E M A responds faster to new changes.

You can quickly spot trends or sudden changes with these techniques.

Thanks and Next Steps!#

Thanks for learning with us. Try using rolling mean or EMA in your own projects.

If you liked this lesson, please subscribe and hit the bell for more beginner Python videos!

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.