All about it: Time Series Analysis — Holt — Winters’ Seasonal Method

Sreeram Kashyap
Analytics Vidhya
Published in
5 min readFeb 4, 2021

--

This article is a part of the series of articles on time series analysis. In the previous article, simple exponential smoothing was explained. You can see it here. In this article we are going to discuss holt’s and Holt-Winter methods for exponential smoothing.

Let’s dive in.

Simple exponential smoothing makes forecasts based on a smoothing factor applied to historical data. It does not account for seasonality and trend adjustments. To solve that, holt’s proposed adjustment factors for both the components. That makes the number of components for exponential smoothing method as three namely level, trend and seasonality. Lets first discuss the holt’s method first and then extend it to Holt-winter’s method.

Holt proposed two ways based on the seasonality

Holt’s method proposes two ways for smoothing namely additive and multiplicative. The classification is based on the seasonality in the data. When the variations in the seasonality component in the data are roughly constant the additive model is used. In the additive model the sum of all seasonal variations adds up to zero. When the variations tend to change with the level of the data in proportion to the level of the data then the multiplicative method is used.

The three components in the Holt-Winters’ formulation are level, trend and seasonality. The related smoothing factors are called alphs beta and gamma respectively.

Lets see an example problem with stock market data.

Data: We will use stock market data for 10 months using yahoo finance API.

Language: Python

Libraries: statmodels, pandas, matplotlib

API: yfinance

First install the libraries.

!pip install pandas, matplotlib
!pip install statmodels

Now we are ready to start. We need to import the following libraries

import pandas as pd
import yfinance as yf
import datetime
import matplotlib.pyplot as plt
from statsmodels.tsa.api import Holt, ExponentialSmoothing

Now we need to download the data from yfinance. The yfinance API updates stock market data for everyday. It takes three main arguments namely tickers, period and interval. Period is the total period of data we want to download an interval is the gap between two recordings or the size of each timestep. Tickers takes the symbol of the stock we want as listed in the stock market. You can check the symbols of your favorite stock from NYSE or s&p 500 list.

The following command downloads the data.

data = yf.download(tickers='TSLA', period='10mo', interval='1d')

Let’s first plot the downloaded data and see how it looks

today = datetime.date.today()
plt.figure(figsize=(10,6))
plt.title(' TESLA STOCK FOR LAST 1 MONTH AS ON '+ str(today))
plt.plot(data['Close'])
plt.show()

Lets first see the results with additive and multiplicative holt’s methods.

fit_add = Holt(stock_data, initialization_method=”estimated”).fit(smoothing_level=0.3, smoothing_trend=0.2, optimized=False)
forecast1 = fit_add.forecast(5).rename(“Holt’s linear trend”)
fit_mul = Holt(stock_data, exponential=True, initialization_method=”estimated”).fit(smoothing_level=0.6, smoothing_trend=0.2, optimized=False)
forecast2 = fit_mul.forecast(5).rename(“Multiplicative trend”)

Here I have used alpha = 0.3 for additive and alpha = 0.6 for multiplicative methods respectively. The above two fits will give you the following output .

Here you can see that additive and multiplicative methods show a small difference in the forecasts at each step.

At this point you will guess that we haven’t discussed trend component.

If you see the above picture you can observe a clear trend of overall increase of the price of the stock over time. There is a chance that at any point the forecast will give an irrational increase in the price because of historical behavior in the last few steps. So we need to dampen the trend. Thats where we get to winter-Holt’s method.

Lets use winter-Holt’s method on our data and see the results. We will be using trend dampening in addition to additive or multiplicative seasonal smoothing. Also instead of experimenting with the values of alpha beta and gamma we will use an optimizer to chose the best value.

fit1 = ExponentialSmoothing(stock_data, seasonal_periods=4, trend=’add’, seasonal=’add’, initialization_method=”estimated”).fit()
fit2 = ExponentialSmoothing(stock_data, seasonal_periods=4, trend=’add’, seasonal=’mul’,initialization_method=”estimated”).fit()
fit3 = ExponentialSmoothing(stock_data, seasonal_periods=4, trend=’add’, seasonal=’add’, damped_trend=True,initialization_method=”estimated”).fit()
fit4 = ExponentialSmoothing(stock_data, seasonal_periods=4, trend=’add’, seasonal=’mul’, damped_trend=True, initialization_method=”estimated”).fit()

The above formulation gives two sets of results, additive and multiplicative both with and without damping factor. They can be visualized as follows.

Traditionally many empirical experiments have resulted in a common notion that multiplicative seasonal component with damping gives the best results for exponential smoothing forecasts. Even though the research for an explanation is still going on the notion stands and it is clear when you experiment with multiple datasets.

The complete code for Holt winter’s method of exponential smoothing is given below.

import numpy as np
import pandas as pd
import yfinance as yf
import datetime
import matplotlib.pyplot as plt
from statsmodels.tsa.api import SimpleExpSmoothing,Holt, ExponentialSmoothing
# DOWNLOADING DATA FROM API
data = yf.download(tickers='TSLA', period='10mo', interval='1d')
#TEST RUN FOR DATA
# data.head(3)
# #PLOT DOWNLOADED DATA
today = datetime.date.today()
plt.figure(figsize=(10,6))
plt.title(' MICROSOFT STOCK FOR LAST 10 MONTH AS ON '+ str(today))
plt.plot(data['Close'])
plt.show()
#DEFINING INPUTS
data = data['Close'].tolist()
#CHANGE DATA FOR 30 DAYS FROM THE DATE WHEN YOU ARE RUNNING THIS CODE
start_date = '2020-04-16'
end_date = '2021-02-03'
index= pd.date_range(start=start_date, end=end_date, freq='B')
stock_data = pd.Series(data, index)
forecast_timestep = 2
get_ipython().magic('matplotlib inline')
fit1 = ExponentialSmoothing(stock_data, seasonal_periods=4, trend='add', seasonal='add', use_boxcox=True, initialization_method="estimated").fit()
fit2 = ExponentialSmoothing(stock_data, seasonal_periods=4, trend='add', seasonal='mul', use_boxcox=True, initialization_method="estimated").fit()
fit3 = ExponentialSmoothing(stock_data, seasonal_periods=4, trend='add', seasonal='add', damped_trend=True, use_boxcox=True, initialization_method="estimated").fit()
fit4 = ExponentialSmoothing(stock_data, seasonal_periods=4, trend='add', seasonal='mul', damped_trend=True, use_boxcox=True, initialization_method="estimated").fit()
ax = stock_data.plot(figsize=(16,10), color='black', title="Forecasts Without Damping factor" )
ax.set_ylabel("Prices $")
ax.set_xlabel("Date")
fit1.fittedvalues.plot(ax=ax, style='--', color='red')
fit2.fittedvalues.plot(ax=ax, style='--', color='green')
fit1.forecast(2).rename('Holt-Winters (add-seasonal)').plot(ax=ax, style='--', color='red', legend=True)
fit2.forecast(2).rename('Holt-Winters (mul-seasonal)').plot(ax=ax, style='--', color='green', legend=True)
ax = stock_data.plot(figsize=(16,10), color='black', title="Forecasts with Damping Factor" )
ax.set_ylabel("Prices $ ")
ax.set_xlabel("Year")
fit3.fittedvalues.plot(ax=ax, style='--', color='red')
fit4.fittedvalues.plot(ax=ax, style='--', color='green')
fit3.forecast(2).rename('Holt-Winters (add-seasonal)').plot(ax=ax, style='--', color='red', legend=True)
fit4.forecast(2).rename('Holt-Winters (mul-seasonal)').plot(ax=ax, style='--', color='green', legend=True)
plt.show()

References:

McKenzie, Eddie & Gardner, Everette. (2010). Damped trend exponential smoothing: A modelling viewpoint. International Journal of Forecasting. 26. 661–665. 10.1016/j.ijforecast.2009.07.001.

--

--