Lesson 19 · Python For Time Series
Understanding Stationarity and the Augmented Dickey-Fuller Test in Time Series Analysis
Welcome! In this lesson, you will learn how to check if a time series is stationary. You will also try the Augmented Dickey-Fuller (ADF) test in Python. We…
- CoursePython For Time Series
- Lesson19 of 30
- Video14 min
- FormatJupyter notebook · 19 code cells
What you'll learn
Data
No separate download needed — the notebook creates or downloads everything it uses.
📓 Full notebook
Download .ipynb
Stationarity and Augmented Dickey-Fuller Test: A Beginner's Guide#
Welcome! In this lesson, you will learn how to check if a time series is stationary. You will also try the Augmented Dickey-Fuller (ADF) test in Python.
We will use real weather data to understand these topics with simple code and friendly steps.
import warnings; warnings.filterwarnings("ignore")
# Data setup: Load daily minimum temperature data
import pandas as pd
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/daily-min-temperatures.csv"
df = pd.read_csv(url, parse_dates=["Date"])
print("Data shape:", df.shape)
df.head()
# Quick data check: Check for missing values
df.isnull().sum()
# Basic plot: Line chart of daily temperatures
import matplotlib.pyplot as plt
plt.figure(figsize=(10,4))
plt.plot(df["Date"], df["Temp"])
plt.title("Daily Minimum Temperatures")
plt.ylabel("Temperature (Celsius)")
plt.xlabel("Date")
plt.show()
What is Stationarity?#
A stationary time series stays stable over time. Mean and variance do not change as you move along. If trends or seasonality exist, the data is probably not stationary. Why does this matter? Many forecasting methods only work with stationary series.
# Quick mean and variance check
window = 365 # About a year
df["rolling_mean"] = df["Temp"].rolling(window).mean()
df["rolling_var"] = df["Temp"].rolling(window).var()
plt.figure(figsize=(10,4))
plt.plot(df["Date"], df["Temp"], label="Original")
plt.plot(df["Date"], df["rolling_mean"], label="Rolling Mean")
plt.plot(df["Date"], df["rolling_var"], label="Rolling Variance")
plt.legend()
plt.title("Rolling Mean and Variance")
plt.show()
The Augmented Dickey-Fuller (ADF) Test#
The ADF test is a standard way to check for stationarity. It gives a test statistic and a p-value. A low p-value (usually below 0.05) means the data is probably stationary. You do not have to do the math yourself; Python can handle it!
# Run the Augmented Dickey-Fuller test
from statsmodels.tsa.stattools import adfuller
result = adfuller(df["Temp"])
print("ADF Statistic:", result[0])
print("p-value:", result[1])
for key, value in result[4].items():
print("Critical Value ({}): {:.3f}".format(key, value))
# Print a human-friendly summary
if result[1] < 0.05:
print("The series is likely stationary (p < 0.05)")
else:
print("The series is likely not stationary (p >= 0.05)")
Why would a series not be stationary?#
Non-stationary data often has a trend or seasonality. A trend means values go up or down overall. Seasonality is a regular pattern, like higher temperatures each summer. Next, we will try to remove these effects.
# Differencing to remove trend
df["diff_1"] = df["Temp"].diff()
plt.figure(figsize=(10,4))
plt.plot(df["Date"], df["diff_1"])
plt.title("First Difference of Temperature")
plt.show()
# Run ADF on differenced data
import numpy as np
diff_result = adfuller(df["diff_1"].dropna())
print("ADF Statistic (1st diff):", diff_result[0])
print("p-value:", diff_result[1])
# Seasonal differencing to remove seasonality effect
df["seasonal_diff"] = df["Temp"].diff(365)
plt.figure(figsize=(10,4))
plt.plot(df["Date"], df["seasonal_diff"])
plt.title("Seasonal Differencing (365 days)")
plt.show()
# Try ADF again with seasonal differencing
seasonal_result = adfuller(df["seasonal_diff"].dropna())
print("ADF Statistic (seasonal):", seasonal_result[0])
print("p-value:", seasonal_result[1])
Useful tricks: Log transformation#
A log transformation can help make variance more constant. This is useful especially if peaks and dips grow over time. Let us try it out!
# Apply a log transformation
df["log_temp"] = np.log(df["Temp"] + 1)
plt.figure(figsize=(10,4))
plt.plot(df["Date"], df["log_temp"])
plt.title("Log-Transformed Temperature")
plt.show()
# Combine: Log transform AND differencing
df["log_diff"] = df["log_temp"].diff()
plt.figure(figsize=(10,4))
plt.plot(df["Date"], df["log_diff"])
plt.title("First Difference of Log-Transformed Data")
plt.show()
# ADF test after all transformations
transformed_result = adfuller(df["log_diff"].dropna())
print("ADF Statistic (log diff):", transformed_result[0])
print("p-value:", transformed_result[1])
# Mini Project: Ask user for differencing period
period = int(input("Enter differencing period (e.g., 1 for day, 365 for year): "))
df["user_diff"] = df["Temp"].diff(period)
plt.figure(figsize=(10,4))
plt.plot(df["Date"], df["user_diff"], label="User Difference")
plt.title(f"Differencing with Period = {period}")
plt.legend()
plt.show()
# Extra: Try ADF test on user-differenced column
user_result = adfuller(df["user_diff"].dropna())
print("ADF Statistic (Your diff):", user_result[0])
print("p-value:", user_result[1])
Troubleshooting common problems#
If you see errors, check for missing data or try a smaller period. Remember to drop missing data using .dropna() before running the ADF test. If your p-value does not go low, try both differencing and log transforms together!
# Challenge: Try with your own CSV file
file = input("Paste a CSV URL or path to your own time series: ")
try:
new_df = pd.read_csv(file, parse_dates=True)
print(new_df.head())
except Exception as e:
print("Could not load your file. Please check the path and try again.")
Recap: What did we learn?#
You learned how to:
- Load time series data
- Visualize and check for stationarity
- Use the Augmented Dickey-Fuller test
- Transform data for better forecasting
- Debug problems
Great job! Stationarity checks are now part of your data science toolkit.
Next stepsKeep learning and share!#
Practice stationarity tests on new datasets. Share your results with the community or in the video comments.
Like and subscribe if you found this lesson helpful. Happy coding!
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



