-
Notifications
You must be signed in to change notification settings - Fork 22
msdecompose
msdecompose performs classical seasonal decomposition for time series with multiple seasonal patterns. It extends the standard decomposition method to handle multiple seasonal periods simultaneously.
This function is used internally by ADAM and ES for initializing ETS models, but can also be used standalone for decomposition and forecasting.
msdecompose(y, lags = c(12),
type = c("additive", "multiplicative"),
smoother = c("lowess", "ma", "supsmu", "global"), ...)def msdecompose(
y,
lags: list[int] = [12],
type: Literal["additive", "multiplicative"] = "additive",
smoother: Literal["lowess", "ma", "global"] = "lowess",
) -> dict: ...smoother="supsmu" (Friedman's SuperSmoother) is R-only — see Roadmap. The R↔Python shared C++ olsCore backend behind smoother="global" produces byte-identical output across languages.
The function separates a time series into:
- Trend: Long-term movement (captured via smoothing)
-
Seasonal components: One for each seasonal period specified in
lags - Residuals: Residual after removing trend and seasonals
This is particularly useful for:
- Hourly data with daily (24) and weekly (168) patterns
- Daily data with weekly (7) and annual (365) patterns
- Monthly data with yearly (12) patterns
- Any time series with multiple overlapping seasonal cycles
For additive decomposition:
yₜ = Trendₜ + Σᵢ Seasonalᵢ(t) + εₜ
For multiplicative decomposition:
yₜ = Trendₜ × ∏ᵢ Seasonalᵢ(t) × εₜ
- Log Transform (if multiplicative): Apply log to convert to additive form
- Missing Value Imputation: Fill NA values using polynomial + Fourier regression
-
Iterative Smoothing: For each lag period (sorted ascending):
- Apply smoother with window = lag period
- Extract seasonal pattern as residual from the smoother level
- Center patterns by removing seasonal mean
- Trend Extraction: Final smoothed series becomes the trend
- Initial States: Compute level and slope from trend for model initialization
library(smooth)
# Basic decomposition with yearly seasonality
result <- msdecompose(AirPassengers, lags=12, type="multiplicative")
# Multiple seasonality (daily and weekly patterns in hourly data)
result <- msdecompose(y, lags=c(24, 168), type="additive")
# Using different smoothers
msdecompose(y, lags=12, type="additive", smoother="ma") # Moving average
msdecompose(y, lags=12, type="additive", smoother="lowess") # LOWESS (STL-like)
msdecompose(y, lags=12, type="additive", smoother="supsmu") # Super smoother
msdecompose(y, lags=12, type="additive", smoother="global") # Global linear trend
# Plot decomposition
plot(result)
# Forecast using decomposition
resultForecast <- forecast(result, model="AAN", h=12)
plot(resultForecast)from smooth import msdecompose
import numpy as np
# Basic decomposition with LOWESS as a smoother
result = msdecompose(y, lags=[12], type='additive', smoother='lowess')
# Access components
trend = result['trend']
seasonal = result['seasonal'][0] # First seasonal pattern
level = result['initial']['nonseasonal']['level']
slope = result['initial']['nonseasonal']['trend']
# Multiple seasonality (hourly data with daily and weekly patterns)
result = msdecompose(hourly_data, lags=[24, 168], type='additive')
daily_pattern = result['seasonal'][0] # 24-hour pattern
weekly_pattern = result['seasonal'][1] # 168-hour pattern
# Multiplicative decomposition (requires positive data)
result = msdecompose(sales_data, lags=[12], type='multiplicative')
# Use for ADAM initialization
result = msdecompose(y, lags=[12], type='additive')
initial_level = result['initial']['nonseasonal']['level']
initial_trend = result['initial']['nonseasonal']['trend']
initial_seasonal = result['initial']['seasonal'][0]| Parameter | Type (R) | Type (Python) | Default | Description |
|---|---|---|---|---|
y |
vector/ts | array-like | - | Time series data (can contain NaN) |
lags |
numeric vector | list/array | 12 / [12] | Seasonal periods to extract |
type |
character | str | "additive" | Decomposition type |
smoother |
character | str | "lowess" | Smoothing method |
... |
- | - | - | Additional parameters for smoothers (R only) |
-
"additive": Components are summed. Use for stable seasonality amplitude. -
"multiplicative": Components are multiplied. Use for proportional seasonality (requires y > 0).
| Smoother | Description |
|---|---|
"ma" |
Centred moving average. Fast, classical decomposition. |
"lowess" |
Locally weighted scatterplot smoothing. Robust to outliers, similar to STL. Default in R and Python. |
"supsmu" |
Friedman's super smoother. More sensitive than LOWESS. |
"global" |
Global linear regression. Fits a straight line for trend, uses ma for seasonality smoothing. |
Python LOWESS: the
"lowess"(and"supsmu") smoothing is provided by thegreyboxpackage (>= 1.0.2), viagreybox.lowess/greybox.smoothers.supsmu.smoothno longer ships its own LOWESS implementation;greyboxis installed automatically as a dependency. Import it directly withfrom greybox import lowessif you need the smoother on its own.
| Data Frequency | Lags | Description |
|---|---|---|
| Monthly | [12] |
Month of year seasonality |
| Daily | [7] |
Day of week seasonality |
| Daily | [7, 365] |
Day of week and year |
| Hourly | [24] |
Hour of day seasonality |
| Hourly | [24, 168] |
Hour of day and week (168 = 24×7) |
| Half-hourly | [48, 336] |
Half-hour of day (48) and week (336 = 48×7) |
Returns an object of class "msdecompose" (R) or a dictionary (Python) containing:
| Element | Type (R) | Type (Python) | Description |
|---|---|---|---|
y |
vector/ts | numpy.ndarray | Original time series |
states |
matrix | numpy.ndarray | State matrix (T × n_states) with level, trend, and seasonal columns |
initial |
list | dict | Named list/dict with nonseasonal (level, trend) and seasonal components |
seasonal |
list | list | List of seasonal patterns, one per lag |
fitted |
vector | numpy.ndarray | Fitted values from decomposition |
lags |
numeric vector | numpy.ndarray | Lags used in decomposition |
type |
character | str | Decomposition type used |
yName |
character | str | Name of the input data |
smoother |
character | str | Smoother type used |
# R
result <- msdecompose(y, lags=12)
result$initial$nonseasonal["level"] # Initial level
result$initial$nonseasonal["trend"] # Initial trend (slope)
result$initial$seasonal[[1]] # First lag[1] seasonal values# Python
result = msdecompose(y, lags=[12])
result['initial']['nonseasonal']['level'] # Initial level
result['initial']['nonseasonal']['trend'] # Initial trend (slope)
result['initial']['seasonal'][0] # First 12 seasonal valuesThe R implementation supports forecasting by fitting an ETS model to the deseasonalised trend:
result <- msdecompose(AirPassengers, lags=12, type="m")
# Forecast with automatic ETS model selection
forecast(result, h=24)
# Specify ETS model for trend
forecast(result, model="AAN", h=24)
# Automaric ETS with prediction intervals
forecast(result, h=24, interval="parametric", level=0.95)The forecast adds back the seasonal patterns to the ETS forecast of the deseasonalised series.
The primary use of msdecompose is to provide initial values for ETS. The decomposition provides:
- Initial level state
- Initial trend state (slope)
- Initial seasonal states for each lag
| Method | Multiple Seasons | Smoothers | Forecasting |
|---|---|---|---|
msdecompose |
Yes | MA, LOWESS, SupSmu, Global | Yes (R) |
stats::decompose |
No | MA | No |
stats::stl |
No | LOWESS with additional steps | Via forecast package |
mstl (forecast) |
Yes | LOWESS with additional steps | Yes |
Missing values (NaN) are automatically imputed using polynomial + Fourier regression before decomposition:
ŷₜ = Σₖ βₖtᵏ + Σⱼ αⱼsin(πtj/m)
where the polynomial degree is min(max(⌊T/10⌋, 1), 5) and m is the maximum lag.
- Svetunkov, I. (2023). Smooth forecasting with the smooth package in R. arXiv:2301.01790. DOI: 10.48550/arXiv.2301.01790