Blog

Time Series Decomposition in R

Learn how to interpret time series data with two decomposition methods: classical moving averages and LOESS-based STL.

Time series analysis involves examining data points collected or observed at consistent intervals over time to understand patterns, trends, and other underlying structures. These data often exhibit distinct behaviors such as long-term growth or decline (known as the trend component) and repetitive ups and downs repeating at predictable intervals (the seasonal component). Decomposition, a key technique in time series analysis, breaks down the observed series into these core parts—trend, seasonality, and any remaining random fluctuations—to help analysts interpret and forecast future values more effectively.

Components of Time Series

We know that there are four time series components, with trend and seasonality being the primary ones. We can assume two models for time series – the additive model and the multiplicative model.

When we assume the additive model, the data at any period t, i.e., Yt, is the sum of the trend (Tt), seasonal (St), and remainder (error) (Rt) components at period t.

Alternatively, in a multiplicative model, we assume that Yt is the product of different components Tt, St, and Rt. When the magnitude of seasonal fluctuations or the variation around a trend cycle does not vary with the level of the time series, the additive model is more appropriate than the multiplicative model.

  • Yt: Time series value at period t
  • St: Seasonal component at period t
  • Tt: Trend cycle component at period t
  • Rt: Remainder (irregular or error) component at period t

Alternatively, a multiplicative model would be written as:

Yt = Tt × St × Rt

Understanding Moving Averages

In time series analysis, the moving average method is a common approach for estimating trends. Moving averages are calculated for consecutive data from overlapping subgroups of a fixed length, which helps to smooth out random fluctuations.

  • Non-seasonal data often uses a shorter moving average length (e.g., 3 or 5).
  • Seasonal data typically uses a moving average length equal to the number of observations in a season (12 for monthly data, 4 for quarterly data, etc.).

For a moving average of period 3, the first two moving averages are not calculated. The moving average for day 3 is the average of values at day 1, 2, and 3, for day 4 it is the average of values at day 2, 3, and 4, and so on. The same logic applies to other periods, such as 5.

Worked example of a moving average of period 3 on five days of end-of-day sales: the first two values are not calculated (NA), then (1500 + 2100 + 1750) / 3 = 1783.33, followed by 1916.67 and 1766.67.

Time Series Decomposition – Simple Method

The first technique for time series decomposition involves three main steps:

  1. Estimating the trend
  2. Eliminating the trend
  3. Estimating seasonality

To find the trend, we obtain moving averages covering one season. Next, we eliminate the trend component from the original time series by calculating Yt − Tt, where Tt is the trend value. Then, to estimate the seasonal component for a given time period, we average the de-trended values for that time period. These seasonal indexes are adjusted so that they sum (or average) to zero for an additive model. The remainder component is computed by subtracting the estimated seasonal and trend-cycle components from the original series.

The three steps of the simple decomposition method: find the trend with moving averages covering one season, eliminate it by calculating Yt − Tt, and estimate seasonality by averaging the de-trended values for each period, adjusted so that they add to zero.

Let’s consider an example. Suppose we have monthly data for three years: 2014, 2015, and 2016. First, calculate the moving average using 13 values to capture the yearly trend: the previous 6 months, the following 6 months, and the current month. This provides the trend component. Subtract the trend Tt from Yt. Finally, the seasonal index for July is the average of all de-trended July values in 2014, 2015, and 2016. (Note that this particular moving-average approach uses both pre and post-data values for a given period.)

Worked example on monthly data: a 13-month moving average centred on July 2015 gives the trend, the trend is removed from the original series, and July's seasonal index is the average of the de-trended July values for 2014, 2015 and 2016.

Case Study

Let’s take monthly sales data for three years (2013–2015). Our goal is to apply decomposition methods and analyze each component of the time series separately. We have 36 records, with year, month, and sales as the study variables.

Data Snapshot

Below is a snapshot of the data. It has three columns: Year, Month, and Sales. The first two are time variables, while Sales is our series of interest.

Data snapshot of the three-year sales data: Year, Month and Sales (in USD million) for monthly observations from January 2013, starting at 123, with a table describing each column.

Time Series Decomposition in R – Simple Method

  1. Import the data using read.csv.
  2. Convert the sales column to a time series object using ts().
  3. Perform a classical seasonal decomposition through moving averages with decompose().
  4. Plot the decomposed data using plot().
R
# Time Series Decomposition
salesdata <- read.csv("Sales Data for 3 Years.csv", header=TRUE)
salesseries <- ts(
  salesdata$Sales,
  start=c(2013,1),
  end=c(2015,12),
  frequency=12
)

# decompose() performs classical seasonal decomposition
# through moving averages
decomp <- decompose(salesseries)

# Plot the decomposed data
plot(decomp)
  • ts() converts a column from a data frame to a simple time series object.
  • start= and end= specify the x-axis scale (year and month).
  • frequency=12 tells R that the data is monthly.
  • decompose() performs classical seasonal decomposition through moving averages.
  • plot() of a decompose object gives a four-level visual representation: original series, trend, seasonal, and remainder.

R defaults to the additive time series model. To use the multiplicative model, set type="multiplicative" inside decompose(). Notice the trend isn’t calculated for the first and last few values, and the seasonal component repeats year after year.

R plot of the decompose() output for the additive model in four panels: the observed series, the trend (missing at the start and end), a seasonal pattern that repeats each year with a December peak, and the random component.

We can view each decomposition component separately by using the object name and the $ operator. Since the trend is not calculated for the first and last values, you may see NAs in those positions, which will also appear in the remainder component.

R
# Analyzing the decompose() object
# Each component can be viewed using the $ operator
decomp$trend
decomp$seasonal
decomp$random
R output of decomp$seasonal, decomp$trend and decomp$random by month for 2013 to 2015: the same seasonal values repeat each year (December is highest, at 35.54), and the trend and random components are NA for the first and last six months.

By subtracting the seasonal component from the original time series, we can obtain a seasonally adjusted time series, as illustrated below.

R
# Doing Seasonal Adjustment
seasadj <- salesseries - decomp$seasonal
plot(seasadj)
R plot of the seasonally adjusted sales series, rising steadily from 2013 to the end of 2015.

Time Series Decomposition – Local Regression Method (LOESS)

The second technique for decomposition is called the local regression method, abbreviated as LOESS. This is a non-parametric generalization of ordinary least squares regression. Unlike standard regression, LOESS does not require specifying the relationship between dependent and independent variables beforehand.

STL (Seasonal and Trend decomposition using LOESS) operates by iteratively smoothing the seasonal and trend components. It applies to regular time series, where the design points (data intervals) are equally spaced.

Time Series Decomposition in R – LOESS Method

In R, the stl() function carries out decomposition by LOESS. The argument s.window specifies the window for the seasonal component. It can be a character string ("periodic") or a numeric span (in lags). The argument t.window specifies the window for the trend component (if not specified, R uses a default based on the data).

R
# Local Regression Method for Seasonal Decomposition
decomp <- stl(salesseries, s.window="periodic")
plot(decomp)
  • stl() is used to decompose a time series via LOESS.
  • s.window="periodic" uses a periodic seasonal window.
  • t.window= sets the trend window. If NULL, R determines a default value.
  • The plot() function provides a decomposition plot: original series, trend, seasonal, and remainder.
R plot of the stl() decomposition in four panels (data, seasonal, trend and remainder): the data shows trend and seasonality, and trend values are estimated for every period, unlike with decompose().

Here, the trend values are estimated for all periods, and you can see how the seasonal component evolves across the entire time span.

Key takeaways

  • A time series can be split into trend, seasonal and remainder components, combined either additively or multiplicatively.
  • The additive model is more appropriate when the size of the seasonal fluctuations does not vary with the level of the series.
  • decompose() performs classical seasonal decomposition with moving averages. It does not calculate the trend for the first and last few values, and subtracting its seasonal component gives a seasonally adjusted series.
  • stl() uses LOESS to smooth the seasonal and trend components iteratively, giving a more flexible decomposition with trend values for every period.

Verify a credential

Enter the reference from a DSI certificate to open its record in the issuing register.

Paste the credential link, or enter the reference on its own. The QR code on the certificate opens the same record.