<jupyter_start><jupyter_text>______Copyright <NAME>For more information, visit us at www.pieriandata.com  Holt-Winters MethodsIn the previous section on Exponentially Weighted Moving Averages (EWMA) we applied Simple Exponential Smoothing using just one smoothing factor $\alpha$ (alpha). This failed to account for other contributing factors like trend and seasonality.In this section we'll look at Double and Triple Exponential Smoothing with the Holt-Winters Methods. In Double Exponential Smoothing (aka Holt's Method) we introduce a new smoothing factor $\beta$ (beta) that addresses trend:\begin{split}l_t &= (1 - \alpha) l_{t-1} + \alpha x_t, & \text{    level}\\b_t &= (1-\beta)b_{t-1} + \beta(l_t-l_{t-1}) & \text{    trend}\\y_t &= l_t + b_t & \text{    fitted model}\\\hat y_{t+h} &= l_t + hb_t & \text{    forecasting model (} h = \text{ periods into the future)}\end{split}Because we haven't yet considered seasonal fluctuations, the forecasting model is simply a straight sloped line extending from the most recent data point. We'll see an example of this in upcoming lectures.With Triple Exponential Smoothing (aka the Holt-Winters Method) we introduce a smoothing factor $\gamma$ (gamma) that addresses seasonality:\begin{split}l_t &= (1 - \alpha) l_{t-1} + \alpha x_t, & \text{    level}\\b_t &= (1-\beta)b_{t-1} + \beta(l_t-l_{t-1}) & \text{    trend}\\c_t &= (1-\gamma)c_{t-L} + \gamma(x_t-l_{t-1}-b_{t-1}) & \text{    seasonal}\\y_t &= (l_t + b_t) c_t & \text{    fitted model}\\\hat y_{t+m} &= (l_t + mb_t)c_{t-L+1+(m-1)modL} & \text{    forecasting model (} m = \text{ periods into the future)}\end{split}Here $L$ represents the number of divisions per cycle. In our case looking at monthly data that displays a repeating pattern each year, we would use $L=12$.In general, higher values for $\alpha$, $\beta$ and $\gamma$ (values closer to 1), place more emphasis on recent data.Related Functions:statsmodels.tsa.holtwinters.SimpleExpSmoothing(endog)&nbsp;&nbsp;&nbsp;&nbsp;Simple Exponential Smoothingstatsmodels.tsa.holtwinters.ExponentialSmoothing(endog)&nbsp;&nbsp;    Holt-Winters Exponential Smoothing    For Further Reading:NIST/SEMATECH e-Handbook of Statistical Methods&nbsp;&nbsp;What is Exponential Smoothing?  Perform standard imports and load the datasetFor these examples we'll continue to use the International Airline Passengers dataset, which gives monthly totals in thousands from January 1949 to December 1960.<jupyter_code>import pandas as pd
import numpy as np
%matplotlib inline
df = pd.read_csv('../Data/airline_passengers.csv',index_col='Month',parse_dates=True)
df.dropna(inplace=True)
df.index<jupyter_output><empty_output><jupyter_text>Setting a DatetimeIndex FrequencyNote that our DatetimeIndex does not have a frequency. In order to build a Holt-Winters smoothing model, statsmodels needs to know the frequency of the data (whether it's daily, monthly etc.). Since observations occur at the start of each month, we'll use MS.A full list of time series offset aliases can be found here.<jupyter_code>df.index.freq = 'MS'
df.index
df.head()<jupyter_output><empty_output><jupyter_text>___ Simple Exponential SmoothingA variation of the statmodels Holt-Winters function provides Simple Exponential Smoothing. We'll show that it performs the same calculation of the weighted moving average as the pandas .ewm() method:$\begin{split}y_0 &= x_0 \\y_t &= (1 - \alpha) y_{t-1} + \alpha x_t,\end{split}$<jupyter_code>from statsmodels.tsa.holtwinters import SimpleExpSmoothing

span = 12
alpha = 2/(span+1)

df['EWMA12'] = df['Thousands of Passengers'].ewm(alpha=alpha,adjust=False).mean()
df['SES12']=SimpleExpSmoothing(df['Thousands of Passengers']).fit(smoothing_level=alpha,optimized=False).fittedvalues.shift(-1)
df.head()<jupyter_output><empty_output><jupyter_text>NOTE: For some reason, when optimized=False is passed into .fit(), the statsmodels SimpleExpSmoothing function shifts fitted values down one row. We fix this by adding .shift(-1) after .fittedvalues ___ Double Exponential SmoothingWhere Simple Exponential Smoothing employs just one smoothing factor $\alpha$ (alpha), Double Exponential Smoothing adds a second smoothing factor $\beta$ (beta) that addresses trends in the data. Like the alpha factor, values for the beta factor fall between zero and one ($0<\beta≤1$). The benefit here is that the model can anticipate future increases or decreases where the level model would only work from recent calculations.We can also address different types of change (growth/decay) in the trend. If a time series displays a straight-line sloped trend, you would use an additive adjustment. If the time series displays an exponential (curved) trend, you would use a multiplicative adjustment.As we move toward forecasting, it's worth noting that both additive and multiplicative adjustments may become exaggerated over time, and require damping that reduces the size of the trend over future periods until it reaches a flat line.<jupyter_code>from statsmodels.tsa.holtwinters import ExponentialSmoothing

df['DESadd12'] = ExponentialSmoothing(df['Thousands of Passengers'], trend='add').fit().fittedvalues.shift(-1)
df.head()
df[['Thousands of Passengers','EWMA12','DESadd12']].iloc[:24].plot(figsize=(12,6)).autoscale(axis='x',tight=True);<jupyter_output><empty_output><jupyter_text>Here we can see that Double Exponential Smoothing is a much better representation of the time series data.Let's see if using a multiplicative seasonal adjustment helps.<jupyter_code>df['DESmul12'] = ExponentialSmoothing(df['Thousands of Passengers'], trend='mul').fit().fittedvalues.shift(-1)
df.head()
df[['Thousands of Passengers','DESadd12','DESmul12']].iloc[:24].plot(figsize=(12,6)).autoscale(axis='x',tight=True);<jupyter_output><empty_output><jupyter_text>Although minor, it does appear that a multiplicative adjustment gives better results. Note that the green line almost completely overlaps the original data. ___ Triple Exponential SmoothingTriple Exponential Smoothing, the method most closely associated with Holt-Winters, adds support for both trends and seasonality in the data.<jupyter_code>df['TESadd12'] = ExponentialSmoothing(df['Thousands of Passengers'],trend='add',seasonal='add',seasonal_periods=12).fit().fittedvalues
df.head()
df['TESmul12'] = ExponentialSmoothing(df['Thousands of Passengers'],trend='mul',seasonal='mul',seasonal_periods=12).fit().fittedvalues
df.head()
df[['Thousands of Passengers','TESadd12','TESmul12']].plot(figsize=(12,6)).autoscale(axis='x',tight=True);
df[['Thousands of Passengers','TESadd12','TESmul12']].iloc[:24].plot(figsize=(12,6)).autoscale(axis='x',tight=True);<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11292252467843254, 'fraction_numerical': 0.013460963206700568, 'mean_word_length': 6.098726114649682, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 26, 'https://': 0, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '150512', 'license': 'MIT', 'n_tokens_mistral': 2104, 'n_tokens_neox': 1971, 'n_words': 675, 'path': 'tsa/jose/TSA_COURSE_NOTEBOOKS/05-Time-Series-Analysis-with-Statsmodels/03-Holt-Winters-Methods.ipynb', 'repo_name': 'juspreet51/ml_templates', 'size': '6692'}