Here is a complete tutorial on Fourier Series with detailed explanations, illustrations, and Python code examples — designed to help you understand how Fourier terms are used in time series analysis and feature engineering, especially for seasonality modeling.
🎼 Fourier Series for Time Series Analysis
📘 What is a Fourier Series?
The Fourier Series represents a function (especially periodic ones) as a sum of sine and cosine functions.
For a time series \(y(t)\), the Fourier series approximation is:
\[
y(t) = \sum_{k=1}^{K} \left[ a_k \cos\left(\frac{2\pi k t}{T} \right) + b_k \sin\left(\frac{2\pi k t}{T} \right) \right]
\]
- \(T\): period of the seasonal cycle (e.g., 12 for months, 365 for daily data)
- \(K\): number of harmonics (Fourier order)
- \(a_k, b_k\): coefficients for cosine and sine terms
📌 Why Use Fourier Terms?
- Models complex and smooth seasonal patterns
- Often used in Prophet, ARIMA with exogenous variables, and neural nets
- Captures both short-term and long-term cyclic behaviors
🧮 Fourier Series in Python
🧰 Function to Create Fourier Features
import numpy as np
import pandas as pd
def create_fourier_terms(df, time_col, period, order):
"""
Add Fourier terms to a time series DataFrame.
:param df: DataFrame with a datetime index
:param time_col: Name of the datetime index or column
:param period: Seasonality period (e.g., 365 for yearly)
:param order: Number of harmonics
:return: DataFrame with Fourier terms
"""
df = df.copy()
t = np.arange(len(df))
for k in range(1, order + 1):
df[f'sin_{k}'] = np.sin(2 * np.pi * k * t / period)
df[f'cos_{k}'] = np.cos(2 * np.pi * k * t / period)
return df
📈 Example: Simulate Seasonal Time Series
import matplotlib.pyplot as plt
# Simulate a signal with yearly seasonality
t = np.linspace(0, 365, 365)
y = np.sin(2 * np.pi * t / 365) + 0.5 * np.sin(2 * np.pi * 2 * t / 365)
plt.figure(figsize=(10, 4))
plt.plot(t, y, label='Simulated Seasonal Signal')
plt.title('Fourier Series Approximation of Seasonality')
plt.xlabel('Day of Year')
plt.ylabel('Signal')
plt.legend()
plt.grid(True)
plt.show()
📊 Use Case: Add Fourier Terms to Real Data
# Example using airline passenger dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/airline-passengers.csv'
df = pd.read_csv(url, parse_dates=['Month'], index_col='Month')
# Add Fourier terms for seasonal pattern (monthly data: T = 12)
df_fourier = create_fourier_terms(df, time_col='Month', period=12, order=2)
df_fourier.head()
🤖 Fourier Features with Time Series Models
You can use Fourier features as exogenous variables (X) in time series models like:
🧠 ARIMA / SARIMAX:
from statsmodels.tsa.statespace.sarimax import SARIMAX
model = SARIMAX(
df['Passengers'],
exog=df_fourier[['sin_1', 'cos_1', 'sin_2', 'cos_2']],
order=(1, 1, 1),
seasonal_order=(1, 1, 1, 12)
)
results = model.fit()
print(results.summary())
🕵️ Prophet:
from prophet import Prophet
from prophet.make_holidays import make_holidays_df
df_prophet = df.reset_index().rename(columns={"Month": "ds", "Passengers": "y"})
m = Prophet()
m.add_seasonality(name='yearly', period=365.25, fourier_order=4)
m.fit(df_prophet)
future = m.make_future_dataframe(periods=24, freq='MS')
forecast = m.predict(future)
m.plot(forecast)
📌 Tips on Choosing Period and Order
Use Case | Period | Fourier Order |
---|---|---|
Monthly data (yearly seasonality) | 12 | 2–6 |
Daily data (yearly seasonality) | 365 | 4–10 |
Weekly data (annual seasonality) | 52 | 2–8 |
Higher order allows capturing more complex cycles but may lead to overfitting.
✅ Summary
Concept | Purpose |
---|---|
Fourier Series | Decompose signal into sine/cosine |
Period | Time span of one seasonal cycle |
Order | Number of harmonics |
Use cases | ARIMA, Prophet, deep learning models |
Benefits | Capture smooth and non-linear seasonality |
📁 Optional: Export Fourier Features
df_fourier.to_csv("data_with_fourier_features.csv")