Simple moving averages, or SMAs, show the average value for a numeric value over a specific number of previous periods and are very useful in time series analysis, both as model features and for interpreting patterns in the data. They’re very easy to calculate using the Pandas rolling()
function.
Exponential moving averages (EMAs) or exponentially weighted moving averages (EWMAs), are similar but differ in assigning a greater weight to the most recent observations, allowing them to identify recent trends better than regular moving averages. EMAs are commonly used in financial forecasting as a result.
In this simple tutorial I’ll show you how you can use the Pandas ewm()
method to calculate an exponential moving average of the values in a Pandas column for a number of different periods.
To get started, open a Jupyter notebook and import the Pandas library using the import pandas as pd
naming convention, then import a time series dataset into a Pandas dataframe. This needs to be sorted by date and include a numeric column upon which you can calculate your exponential moving average.
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/flyandlure/datasets/master/ecommerce_sales_by_date.csv',
usecols=['date', 'transactions'],
parse_dates=['date'])
df.head(10)
date | transactions | |
---|---|---|
0 | 2021-01-01 | 125 |
1 | 2021-01-02 | 161 |
2 | 2021-01-03 | 157 |
3 | 2021-01-04 | 99 |
4 | 2021-01-05 | 91 |
5 | 2021-01-06 | 99 |
6 | 2021-01-07 | 87 |
7 | 2021-01-08 | 112 |
8 | 2021-01-09 | 161 |
9 | 2021-01-10 | 164 |
First, we’ll calculate a simple moving average, so you can compare how the result differs from an exponentially weighted moving average. We’ll do this using the Pandas rolling()
function.
We’ll append a call to assign()
to our dataframe and tell it to create a new column called sma_3day
and assign to it the result of rolling(3).mean()
to give us the three-day simple moving average for each column value. Note that rolling()
will give us NaN
values when there aren’t enough prior values to use for the calculation.
df = df.assign(sma_3day = df['transactions'].rolling(3).mean())
df.head()
date | transactions | sma_3day | |
---|---|---|---|
0 | 2021-01-01 | 125 | NaN |
1 | 2021-01-02 | 161 | NaN |
2 | 2021-01-03 | 157 | 147.666667 |
3 | 2021-01-04 | 99 | 139.000000 |
4 | 2021-01-05 | 91 | 115.666667 |
Next, we’ll calculate the EMA using the ewm()
function. There are various parameters you can pass to the Pandas ewm()
function to adjust how Pandas calculates an exponential moving average. The most important of these is the span
parameter which takes an integer value define the number of rows to compare.
For example, df['transactions'].ewm(span=3, adjust=False).mean()
will calculate the exponential moving average for the transactions
column over three previous rows. If there are no previous rows, Pandas will calculate based on the values that are available.
We can use the Pandas assign()
method to calculate the exponentially weighted moving average for several periods simply by providing a different value to the span
parameter and assigning the values back to the new column name and saving the final dataframe.
df = df.assign(
ewm_3day = df['transactions'].ewm(span=3, adjust=False).mean(),
ewm_7day = df['transactions'].ewm(span=7, adjust=False).mean(),
ewm_10day = df['transactions'].ewm(span=7, adjust=False).mean(),
)
df.head(10)
date | transactions | sma_3day | ewm_3day | ewm_7day | ewm_10day | |
---|---|---|---|---|---|---|
0 | 2021-01-01 | 125 | NaN | 125.000000 | 125.000000 | 125.000000 |
1 | 2021-01-02 | 161 | NaN | 143.000000 | 134.000000 | 134.000000 |
2 | 2021-01-03 | 157 | 147.666667 | 150.000000 | 139.750000 | 139.750000 |
3 | 2021-01-04 | 99 | 139.000000 | 124.500000 | 129.562500 | 129.562500 |
4 | 2021-01-05 | 91 | 115.666667 | 107.750000 | 119.921875 | 119.921875 |
5 | 2021-01-06 | 99 | 96.333333 | 103.375000 | 114.691406 | 114.691406 |
6 | 2021-01-07 | 87 | 92.333333 | 95.187500 | 107.768555 | 107.768555 |
7 | 2021-01-08 | 112 | 99.333333 | 103.593750 | 108.826416 | 108.826416 |
8 | 2021-01-09 | 161 | 120.000000 | 132.296875 | 121.869812 | 121.869812 |
9 | 2021-01-10 | 164 | 145.666667 | 148.148438 | 132.402359 | 132.402359 |
Matt Clarke, Monday, January 09, 2023