How is the time series decomposition working? How does it split a time series into three other: Seasonality, Trends and Random? To understand time series decomposition, we will study the decompose( ) and STL( ) function from R language.

## Understand decomposition

#### Decompose into more times series

A time series decomposition is a mathematical procedure which transform a time series into multiple different time series. The original time series is often computed (decompose) into 3 sub-time series:

**Seasonal:**patterns that repeat with fixed period of time. A website might receive more visit during weekends. This is a seasonality of 7 days.**Trend:**the underlying trend of the metrics. A website who gain in popularity should have a general trend who go up.**Random:**(also call “noise”, “Irregular” or “Remainder”) Is the residuals of the time series after allocation into the seasonal and trends time series.

#### Additive or multiplicative decomposition?

To get a successful decomposition, it is important to choose between the additive or multiplicative model. To choose the right model we need to look at the time series. Does the magnitude of the seasonality increase when the time series increase too?

**Australian beer production** – The seasonal variation looks constant. It doesn’t change when the time series increase. We should use the **additive model.**

**Airline Passenger Numbers** – When the time series increase the seasonal variation increase more and more. We should use the **multiplicative model.**

**Additive:**

Time series = Seasonal + Trend + Random

**Multiplicative:**

Time series = Trend * Seasonal *Random

Based on the model, the decomposition formula varies a little.

## Step-by-step: Time series decomposition

We’ll study the decompose( ) function in R. As a decomposition function, it takes a time series as parameter and decompose it into seasonal, trend and random time series. We’ll reproduce step-by-step the decompose( ) function in R to understand how it works. As the technique isn’t exactly the same with an **additive** and **multiplicative** model we will use two examples: the Australian beer production (**additive**) and the Airline Passenger Numbers (**multiplicative**).

### Step 1: Import the data

#### additive

A good example of additive time series is the beer production see previously. When the metrics values increase, the seasonality stays constant. It doesn’t vary that much.

#### multiplicative

The monthly Airline Passenger Numbers is a good example of multiplicative time series. The more passenger the more seasonality is observed.

1 2 3 4 5 | install.packages("fpp") library(fpp) data(ausbeer) timeserie_beer = tail(head(ausbeer, 17*4+2),17*4-4) plot(as.ts(timeserie_beer)) |

1 2 3 4 5 | install.packages("Ecdat") library(Ecdat) data(AirPassengers) timeserie_air = AirPassengers plot(as.ts(timeserie_air)) |

### Step 2: detect the trend

To detect the underlying trend, we smooth the time series using the “centred moving average“. To perform the decomposition, it is vital to use a moving window of the exact size of the seasonality. Therefore, to decompose a time series we need to know it seasonality period: weekly, monthly, etc… No worry if you don’t know it, you can detect the seasonality using Fourier transform.

#### additive

The Australian beer production clearly follows an annual seasonality. As it is quarterly recorded, there is 4 data points recorded per year **we use moving average windows of 4.**

#### multiplicative

This is the same process used for the additive model. The airline passenger numbers seasonality also looks annually. As it is recorded monthly, we choose a **moving average window of 12.**

1 2 3 4 5 6 | install.packages("forecast") library(forecast) trend_beer = ma(timeserie_beer, order = 4, centre = T) plot(as.ts(timeserie_beer)) lines(trend_beer) plot(as.ts(trend_beer)) |

1 2 3 4 5 6 | install.packages("forecast") library(forecast) trend_air = ma(timeserie_air, order = 12, centre = T) plot(as.ts(timeserie_air)) lines(trend_air) plot(as.ts(trend_air)) |

### Step 3: detrend the time series

Removing the previously calculated trend from the time series will result into a new time series who clearly expose the seasonality.

#### additive

#### multiplicative

1 2 | detrend_beer = timeserie_beer - trend_beer plot(as.ts(detrend_beer)) |

1 2 | detrend_air = timeserie_air / trend_air plot(as.ts(detrend_air)) |

### Step 4: **average **seasonality

From the detrend time series, it’s easy to compute the **average seasonality**. We add the seasonality together and divide by the number of seasonality. Technically speaking, to average together the time series we feed the time series into a matrix. Then, we transform the matrix so each column contains the elements of the same period (same day, same month or same quarter…). Finally, we compute the mean of each column. Here is how to do it in R:

#### additive

quarterly seasonality: we use a matrix of 4 rows.

*The average seasonality is repeat 16 times to compare the graphic later (see below)*

#### multiplicative

Monthly seasonality: we use a matrix of 12 rows.

*The average seasonality is repeat 12 times to compare the graphic later (see below)*

1 2 3 | m_beer = t(matrix(data = detrend_beer, nrow = 4)) seasonal_beer = colMeans(m_beer, na.rm = T) plot(as.ts(rep(seasonal_beer,16))) |

1 2 3 | m_air = t(matrix(data = detrend_air, nrow = 12)) seasonal_air = colMeans(m_air, na.rm = T) plot(as.ts(rep(seasonal_air,12))) |

### Step 5: random noise left

Previous steps already extract most data from the original time series. It only left with some “random” noise.

#### additive

The additive formula define “Time series = Seasonal + Trend + Random” which means “Random = Time series – Seasonal – Trend”

#### multiplicative

The multiplicative formula define “Time series = Seasonal * Trend * Random” which means “Random = Time series / (Trend * Seasonal)”

1 2 | random_beer = timeserie_beer - trend_beer - seasonal_beer plot(as.ts(random_beer)) |

1 2 | random_air = timeserie_air / (trend_air * seasonal_air) plot(as.ts(random_air)) |

### Step 6: reconstruct the original signal

The decomposed time series can logically be re-composed using the model formula. This should reproduce the original signal. Some data are missing at the beginning and the end of the recomposed time series. This is due to the moving average windows who need to ingest some data point before producing average data points.

#### additive

The additive formula define “Time series = Seasonal + Trend + Random” which means “Random = Time series – Seasonal – Trend”

#### multiplicative

The multiplicative formula define “Time series = Seasonal * Trend * Random” which means “Random = Time series / (Trend * Seasonal)”

1 2 | recomposed_beer = trend_beer+seasonal_beer+random_beer plot(as.ts(recomposed_beer)) |

1 2 | recomposed_air = trend_air*seasonal_air*random_air plot(as.ts(recomposed_air)) |

## DECOMPOSE( ) and STL(): Time series decomposition in R

To make our life easier, some R package provides decomposition with a single line of code. As expected, our step-by-step decomposition provides the exact as the DECOMPOSE( ) and the STL( ) function (see the graphic).

#### additive

Only requirement: the seasonality is quarterly (frequency = 4)

**Using the DECOMPOSE( ) function:**

#### multiplicative

Only requirement: the seasonality is monthly (frequency = 12)

1 2 3 4 5 6 7 | ts_beer = ts(timeserie_beer, frequency = 4) decompose_beer = decompose(ts_beer, "additive") plot(as.ts(decompose_beer$seasonal)) plot(as.ts(decompose_beer$trend)) plot(as.ts(decompose_beer$random)) plot(decompose_beer) |

1 2 3 4 5 6 7 | ts_air = ts(timeserie_air, frequency = 12) decompose_air = decompose(ts_air, "multiplicative") plot(as.ts(decompose_air$seasonal)) plot(as.ts(decompose_air$trend)) plot(as.ts(decompose_air$random)) plot(decompose_air) |

**Now using the STL( ) function:**

1 2 3 4 5 6 7 8 9 10 11 | ts_beer = ts(timeserie_beer, frequency = 4) stl_beer = stl(ts_beer, "periodic") seasonal_stl_beer <- stl_beer$time.series[,1] trend_stl_beer <- stl_beer$time.series[,2] random_stl_beer <- stl_beer$time.series[,3] plot(ts_beer) plot(as.ts(seasonal_stl_beer)) plot(trend_stl_beer) plot(random_stl_beer) plot(stl_beer) |

## Conclusion

Often, the decomposition is used to removes the seasonal effect from a time series. It provided a cleaner way to understand the trend. For instance, lower ice-cream sales during winter don’t mean the company performing poorly. To know the answer, we need to remove the seasonality from the time series. Here, at Anomaly.io we detect anomalies, we use the seasonally adjusted time series to detect anomalies. We also use the random (also call reminder) sub-time series from the decomposed time series to detect anomalies and outliers.

**Monitor & detect anomalies with Anomaly.io**