In Part 3.1 we started discussing how decomposes the time series data into trend, seasonality, and residual components, and as it is a smoothing-based technique, it means we need rough estimates of trend and seasonality for STL to perform smoothing.
For that, we calculated a rough estimate of a trend by calculating it using the Centered Moving Averages method, and then by using this initial trend, we also calculated the initial seasonality. (Detailed math is discussed in Part 3.1)
In this part, we implement the LOESS (Locally Estimated Scatterplot Smoothing) method next to get the final trend and seasonal components of the time series.
At the end of part 3.1, we have the following data:
As we have the centered seasonal component, the next step is to subtract this from the original time series to get the deseasonalized series.
We got the series of deseasonalized values, and we know that this contains both trend and residual components.
Now we apply LOESS (Locally Estimated Scatterplot Smoothing) on this deseasonalized series.
Here, we aim to understand the concept and mathematics behind the LOESS technique. To do this we consider a single data point from the deseasonalized series and implement LOESS step by step, observing how the value changes.
Before understanding the math behind the LOESS, we try to understand what is actually done in the LOESS smoothing process.
LOESS is the process similar to Simple Linear Regression, but the only difference here is, we assign weights to the points such that the points nearer to the target point gets more weight and farther from the target point gets less weight.
We can call it a Weighted Simple Linear Regression.
Here the target point is the point at which the LOESS smoothing is done, and, in this process, we select an alpha value which ranges between 0 and 1.
Mostly we use 0.3 or 0.5 as the alpha value.
For example, let’s say alpha = 0.3 which means 30% of the data points is used in this regression, which means if we have 100 data points then 15 points before the target point and 15 points after target point (including target point) are used in this smoothing process.
Same as with Simple Linear Regression, in this smoothing process we fit a line to the data points with added weights.
We add weights to the data points because it helps the line to adapt to the local behavior of the data and ignoring fluctuations or outliers, as we are trying to estimate the trend component in this process.
Now we got an idea that in LOESS smoothing process we fit a line that best fits the data and from that we calculate the smoothed value at the target point.
Next, we will implement LOESS smoothing by taking a single point as an example.
Let’s try to understand what’s actually done in LOESS smoothing by taking a single point as an example.
Consider 01-08-2010, here the deseasonalized value is 14751.02.
Now to understand the math behind LOESS easily, let’s consider a span of five points.
Here the span of five points means we consider the points which are nearest to target point (1-8-2010) including the target point.
To demonstrate LOESS smoothing at August 2010, we considered values from June 2010 to October 2010.
Here the index values (starting from zero) are from the original data.
The first step in LOESS smoothing is that we calculate the distances between the target point and neighboring points.
We calculate this distance based on the index values.
We calculated the distances and the maximum distance from the target point is ‘2’.
Now the next step in LOESS smoothing is to calculate the tricube weights, LOESS assigns weights to each point based on the scaled distances.
Here the tricube weights for 5 points are [0.00, 0.66, 1.00, 0.66, 0.00].
Now that we have calculated the tricube weights, the next step is to perform weighted simple linear regression.
The formulas are similar as SLR with usual averages getting replaced by weighted averages.
Here’s the full step by step math to calculate the LOESS smoothed value at t=7.
Here the LOESS trend estimate at August 2010 is 14212.96 which is less than the deseasonalized value of 14751.02.
In our 5-point window, if we see the values of neighboring months, we can observe that the values are decreasing, and the August value looks like a sudden jump.
LOESS tries to fit a line that best fits the data which represents the underlying local trend; it smooths out sharp spikes or dips and it gives us a true local behavior of the data.
This is how LOESS calculates the smoothed value for a data point.
For our dataset when we implement STL decomposition using Python, the alpha value may be between 0.3 and 0.5 based on the number of points in the dataset.
We can also try different alpha values and see which one represents the data best and select the appropriate one.
This process is repeated for each and every point in the data.
Once we get the LOESS smoothed trend component, it is subtracted from the original series to isolate seasonality and noise.
Next, we follow the same LOESS smoothing procedure across seasonal subseries like all Januaries, Februaries etc. (as in part 3.1) to get LOESS smoothed seasonal component.
After getting both the LOESS smoothed trend and seasonality components, we subtract them from original series to get the residual.
After this, the whole process is repeated to further refine the components, the LOESS smoothed seasonality is subtracted from the original series to find LOESS smoothed trend and this new LOESS smoothed trend is subtracted from the original series to find the LOESS smoothed seasonality.
This we can call as one Iteration, and after several rounds of iteration (10-15), the three components get stabilized and there is no further change and STL returns the final trend, seasonality, and residual components.
This is what happens when we use the code below to apply STL decomposition on the dataset to get the three components.
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.seasonal import STL
# Load the dataset
df = pd.read_csv("C:/RSDSELDN.csv", parse_dates=['Observation_Date'], dayfirst=True)
df.set_index('Observation_Date', inplace=True)
df = df.asfreq('MS') # Ensure monthly frequency
# Extract the time series
series = df['Retail_Sales']
# Apply STL decomposition
stl = STL(series, seasonal=13)
result = stl.fit()
# Plot and save STL components
fig, axs = plt.subplots(4, 1, figsize=(10, 8), sharex=True)
axs[0].plot(result.observed, color='sienna')
axs[0].set_title('Observed')
axs[1].plot(result.trend, color='goldenrod')
axs[1].set_title('Trend')
axs[2].plot(result.seasonal, color='darkslategrey')
axs[2].set_title('Seasonal')
axs[3].plot(result.resid, color='rebeccapurple')
axs[3].set_title('Residual')
plt.suptitle('STL Decomposition of Retail Sales', fontsize=16)
plt.tight_layout()
plt.show()
Dataset: This blog uses publicly available data from FRED (Federal Reserve Economic Data). The series Advance Retail Sales: Department Stores (RSDSELD) is published by the U.S. Census Bureau and can be used for analysis and publication with appropriate citation.
Official citation:
U.S. Census Bureau, Advance Retail Sales: Department Stores [RSDSELD], retrieved from FRED, Federal Reserve Bank of St. Louis; https://fred.stlouisfed.org/series/RSDSELD, July 7, 2025.
Note: All images, unless otherwise noted, are by the author.
I hope you got a basic idea of how STL decomposition works, from calculating initial trend and seasonality to finding final components using LOESS smoothing.
Next in the series, we discuss ‘Stationarity of a Time Series’ in detail.
Thanks for reading!
Source link
#Time #Series #Forecasting #Simple #Part #Deep #Dive #LOESSBased #Smoothing