Demand forecasting : Double exponential smoothing

The drawback of simple exponential smoothing is that it can only see a level (the average value around which the demand varies over time) and is unable to identify and project a trend. Double exponential smoothing brings together "level" and "trend" to generate forecasts.

For a given period, "t" with demand, d,  the "Level" and "Trend" can be expressed as:

$$ a_{t}, b_{t}$$

The "Level", which is a function of demand and forecast, can be calculated as:

$$ a_{t}=\alpha d_{t}+(1-\alpha)(a_{t-1}+b_{t-1})$$

and the "Trend", which is a function of the difference in levels as well as the previous trend, can be calculated as:

$$ b_{t}=\beta (a_{t}-a_{t-1}) + (1-\beta) b_{t-1}$$

Forecast = Level + Trend

$$f_{t+1}=a_{t}+b_{t}$$

for a generalised forecast, the expression can be written as:

$$f_{t+\lambda}=a_{t}+\lambda b_{t}$$

Now moving on to the implementation of the Double Exponential smoothing model.

The simplest way to initialise the model is to assign 

$$ a_{0} = d_{0}$$

$$ b_{0} = d_{1}-d_{0}$$


def double_exp_smooth(d,alpha, beta):
   
    f=np.full(len(d)+1,np.nan)
    level=np.full(len(d)+1,np.nan)
    trend=np.full(len(d)+1,np.nan)
    d=np.append(d,[np.nan])
    
    #Initialising forecast
    level[0]=d[0]
    trend[0]=d[1]-d[0]
    
    #Creating t+1 forecast
    for t in range (1,len(d)):
        f[t]= level[t-1]+trend[t-1]
        level[t]= alpha*d[t-1]+(1-alpha)*(level[t-1]+trend[t-1])
        trend[t]= beta*(level[t]-level[t-1])+(1-beta)* trend[t-1]
        
   # f[t+1]=level[t]+trend[t]
    df=pd.DataFrame.from_dict({'Demand':d,'Forecast':f,'Level':level,'Trend':trend,'Error':d-f})
        
    return df

# For my test, I have used a csv file with demand data for the last 50 periods.
# The contents were generated using the random() function in excel.

import pandas as pd
import numpy as np

df_read=pd.read_csv('Demand50.csv')
d=df_read.values

# Calling the Double exponential smoothing function 
df_smooth= double_exp_smooth(d,0.4,0.4)

df_smooth.index.name ='Period'
df_smooth[['Demand','Forecast']].plot() 


Comments