Skip to content

MSARIMA

Ivan Svetunkov edited this page Jun 16, 2026 · 8 revisions

MSARIMA - Multiple Seasonal ARIMA

MSARIMA (Multiple Seasonal ARIMA) is an optimized implementation of ARIMA for handling multiple seasonal patterns. It is a wrapper of ADAM that skips zero polynomials, making it substantially faster and more accurate than SSARIMA for high-frequency data.

Function signatures

R

msarima(y, orders = list(ar = c(0), i = c(1), ma = c(1)), lags = c(1),
        constant = FALSE, arma = NULL, model = NULL,
        initial = c("backcasting", "optimal", "two-stage", "complete"),
        ic = c("AICc", "AIC", "BIC", "BICc"),
        loss = c("likelihood", "MSE", "MAE", "HAM",
                 "MSEh", "TMSE", "GTMSE", "MSCE", "GPL"),
        h = 0, holdout = FALSE,
        bounds = c("usual", "admissible", "none"),
        silent = TRUE,
        xreg = NULL, regressors = c("use", "select", "adapt"),
        initialX = NULL, ...)

auto.msarima(y, orders = list(ar = c(3, 3), i = c(2, 1), ma = c(3, 3)),
             lags = c(1, frequency(y)),
             initial = c("backcasting", "optimal", "two-stage", "complete"),
             ic = c("AICc", "AIC", "BIC", "BICc"),
             loss = c("likelihood", "MSE", "MAE", "HAM",
                      "MSEh", "TMSE", "GTMSE", "MSCE", "GPL"),
             h = 0, holdout = FALSE,
             bounds = c("usual", "admissible", "none"),
             silent = TRUE, xreg = NULL,
             regressors = c("use", "select", "adapt"),
             initialX = NULL, ...)

Python

class MSARIMA(ADAM):
    def __init__(
        self,
        orders: dict | None = None,
        lags: list[int] | None = None,
        ar_order: int | list[int] = 0,
        i_order: int | list[int] = 1,
        ma_order: int | list[int] = 1,
        arima_select: bool = False,
        constant: bool | float = False,
        arma: dict | None = None,
        initial: str | dict | None = "backcasting",
        initial_X: NDArray | None = None,
        ic: Literal["AIC", "AICc", "BIC", "BICc"] = "AICc",
        loss: str = "likelihood",
        h: int | None = None,
        holdout: bool = False,
        bounds: Literal["usual", "admissible", "none"] = "usual",
        verbose: int = 0,
        regressors: Literal["use", "select", "adapt"] = "use",
        **kwargs,
    ) -> None: ...

class AutoMSARIMA(AutoADAM):
    def __init__(
        self,
        lags: list[int] | None = None,
        ar_order: int | list[int] | None = [3, 3],
        i_order: int | list[int] | None = [2, 1],
        ma_order: int | list[int] | None = [3, 3],
        orders: dict | None = None,
        constant: bool | float = False,
        initial: str | dict | None = "backcasting",
        initial_X: NDArray | None = None,
        ic: Literal["AIC", "AICc", "BIC", "BICc"] = "AICc",
        loss: str = "likelihood",
        h: int | None = None,
        holdout: bool = False,
        bounds: Literal["usual", "admissible", "none"] = "usual",
        regressors: Literal["use", "select", "adapt"] = "use",
        outliers: Literal["ignore", "use", "select"] = "ignore",
        level: float = 0.99,
        verbose: int = 0,
        **kwargs,
    ) -> None: ...

MSARIMA rejects ADAM-only kwargs (model, persistence, phi, distribution) with ValueError. AutoMSARIMA likewise rejects model, distribution, arima_select — order selection is always on.

Overview

MSARIMA efficiently handles complex seasonal structures like:

  • Hourly data with daily (24) and weekly (168) patterns
  • Daily data with weekly (7) and annual (365) patterns
  • Sub-daily data with multiple intraday and interday cycles

The implementation differs from SSARIMA by directly mapping non-zero components, reducing the state dimension and improving computational efficiency.

Python Usage

from smooth import MSARIMA
import numpy as np

y = np.array([...])  # your time series

# Default: ARIMA(0,1,1)
model = MSARIMA()
model.fit(y)
print(model)

# ARIMA(1,1,1)
model = MSARIMA(ar_order=1, i_order=1, ma_order=1)
model.fit(y)

# SARIMA(1,1,1)(1,1,1)[12] via dict
model = MSARIMA(
    orders={"ar": [1, 1], "i": [1, 1], "ma": [1, 1]},
    lags=[1, 12],
)
model.fit(y)

# ARIMA(1,1,1) with drift
model = MSARIMA(ar_order=1, i_order=1, ma_order=1, constant=True)
model.fit(y)
print(f"Drift: {model.constant_value:.4f}")

# Fixed ARMA coefficients (not estimated)
model = MSARIMA(ar_order=1, i_order=1, ma_order=1,
                arma={"ar": [0.5], "ma": [0.2]})
model.fit(y)

# Forecasts
forecasts = model.predict(h=12)
forecasts = model.predict(h=12, interval="prediction", level=0.95)

Automatic Order Selection

# Preferred: use AutoMSARIMA for automatic order selection
from smooth import AutoMSARIMA
model = AutoMSARIMA(lags=[1, 12])
model.fit(y)

# Alternative: MSARIMA with arima_select=True (same result)
model = MSARIMA(
    orders={"ar": [2, 1], "i": [1, 1], "ma": [2, 1], "select": True},
    lags=[1, 24],
)
model.fit(y)

R Usage

library(smooth)

# Basic non-seasonal ARIMA(1,1,1)
msarima(y, orders=c(1,1,1), lags=1)

# SARIMA(1,1,1)(0,1,1)[12]
msarima(y, orders=list(ar=c(1,0), i=c(1,1), ma=c(1,1)), lags=c(1,12))

# Complex multiple seasonality
# SARIMA(1,1,1)(0,1,1)[24](2,0,1)[168](0,0,1)[720]
msarima(y,
    orders=list(ar=c(1,0,2,0), i=c(1,1,0,0), ma=c(1,1,1,1)),
    lags=c(1,24,168,720)
)

# With holdout validation
msarima(y, orders=list(ar=c(1,1), i=c(1,1), ma=c(1,1)),
        lags=c(1,24), h=48, holdout=TRUE)

# Fixed ARMA coefficients
msarima(y, orders=c(1,1,1), arma=list(ar=0.5, ma=0.2))

Automatic Order Selection

auto.msarima() is a wrapper of auto.adam().

# Automatic selection
auto.msarima(y, h=24, holdout=TRUE)

# With maximum orders
auto.msarima(y, orders=list(ar=c(2,1), i=c(1,1), ma=c(2,1)), lags=c(1,24))

# Check constant necessity
auto.msarima(y, constant=NULL)

AutoMSARIMA — Automatic Order Selection

AutoMSARIMA (Python) / auto.msarima() (R) automatically selects the best ARIMA orders using information criteria. It is a wrapper around AutoADAM with model="NNN" and distribution="dnorm" fixed.

Python Usage

from smooth import AutoMSARIMA

# Automatic non-seasonal ARIMA
model = AutoMSARIMA(lags=[1])
model.fit(y)
print(model)  # AutoMSARIMA: ARIMA([p],[d],[q])

# Automatic seasonal ARIMA (monthly data)
model = AutoMSARIMA(lags=[1, 12])
model.fit(y)
fc = model.predict(h=24)

# Reduce search space for speed
model = AutoMSARIMA(
    lags=[1, 12],
    ar_order=[2, 1],
    i_order=[2, 1],
    ma_order=[2, 1],
)
model.fit(y)

# With external regressors
model = AutoMSARIMA(lags=[1, 12], regressors="select")
model.fit(y, X=X)

R Usage

# Automatic selection
auto.msarima(y, h=24, holdout=TRUE)

# With maximum orders
auto.msarima(y, orders=list(ar=c(2,1), i=c(2,1), ma=c(2,1)),
             lags=c(1,12))

# With external regressors
auto.msarima(y, lags=c(1,12), xreg=X)

Parameters

Parameter Type (R) Type (Python) Default Description
lags numeric vector List[int]/None frequency(y) / None Seasonal period(s)
orders list Dict/None see description / None Max ARIMA orders. R default: list(ar=c(3,3),i=c(2,1),ma=c(3,3)). Python: dict with "ar", "i", "ma" keys (overrides scalar params).
ar_order - int/List[int] - / [3, 3] Max AR order(s) per lag level
i_order - int/List[int] - / [2, 1] Max integration order(s) per lag level
ma_order - int/List[int] - / [3, 3] Max MA order(s) per lag level
constant logical/numeric bool/float FALSE / False Include constant/drift term
initial character str/Dict "backcasting" Initialisation method
initialX numeric vector NDArray/None (initial_X) NULL / None Initial regressor coefficients
ic character str "AICc" Information criterion for selection
loss character str "likelihood" Loss function
h integer int/None 0 / None Forecast horizon
holdout logical bool FALSE / False Use holdout validation
bounds character str "usual" Parameter bounds type
regressors character str "use" How to handle external regressors
xreg matrix - (pass X to .fit()) NULL / - External regressors (R only; Python uses X in fit())
outliers - str - / "ignore" Outlier handling: "ignore", "use", "select" (Python only)
level - float - / 0.99 Confidence level for outlier detection (Python only)

The Python parameters model, distribution, and arima_select are fixed ("NNN", "dnorm", True) and cannot be overridden; passing them raises ValueError.

Parameters

Parameter Type (R) Type (Python) Default Description
y vector/ts NDArray - Time series data
orders list/vector Dict/None None ARIMA orders per lag (R-style dict)
ar_order - int/List[int] 0 AR order(s); Python-preferred alternative
i_order - int/List[int] 1 Integration order(s)
ma_order - int/List[int] 1 MA order(s)
lags numeric vector List[int]/None None Seasonal period(s)
arima_select orders$select bool False Automatic order selection
constant logical/numeric bool/float False Include constant/drift
arma list Dict/None None Fixed AR/MA parameter values
initial character str/Dict "backcasting" Initialization method
initial_X initialX NDArray/None None Initial regressor coefficients
bounds character str "usual" Parameter bounds
ic character str "AICc" Information criterion
loss character str "likelihood" Loss function
h integer int/None None Forecast horizon
holdout logical bool False Use holdout validation
regressors character str "use" How to handle regressors

Orders Specification

Each element in ar, i, ma vectors corresponds to the lag at the same position:

# SARIMA(1,1,1)(1,0,1)[12](0,1,1)[52]
orders = list(
    ar = c(1, 1, 0),   # AR(1) at lag 1, AR(1) at lag 12, AR(0) at lag 52
    i  = c(1, 0, 1),   # I(1) at lag 1, I(0) at lag 12, I(1) at lag 52
    ma = c(1, 1, 1)    # MA(1) at all lags
)
lags = c(1, 12, 52)
# Python equivalent using dict
model = MSARIMA(
    orders={"ar": [1, 1, 0], "i": [1, 0, 1], "ma": [1, 1, 1]},
    lags=[1, 12, 52],
)

See Orders-and-Lags for full details.

Fixed ARMA Parameters (arma)

Use arma to fix AR or MA coefficients at specified values instead of estimating them. The dict keys "ar" and "ma" take lists of values matching the total AR/MA order.

# Fix only MA coefficient
model = MSARIMA(ar_order=0, i_order=1, ma_order=1, arma={"ma": [0.3]})

# Fix both AR and MA
model = MSARIMA(ar_order=1, i_order=1, ma_order=1,
                arma={"ar": [0.5], "ma": [0.2]})

# Seasonal ARIMA — provide one value per total AR/MA term
# SARIMA(1,0,0)(0,0,1)[12]: fix AR at lag 1 and MA at lag 12
model = MSARIMA(
    orders={"ar": [1, 0], "i": [1, 1], "ma": [0, 1]},
    lags=[1, 12],
    arma={"ar": [0.5], "ma": [0.3]},
)

Fixed parameters do not appear in model.coef (nothing to estimate). They are accessible via model._arima["arma_parameters"].

Initialization Methods

  • "backcasting": Recommended for high-frequency data
  • "optimal": Optimize initial states
  • "two-stage": Backcast then optimize
  • "complete": Full backcasting including regressors

More detailed explanation is provided in Section 11.4 of Svetunkov (2023).

With External Regressors

# R: MSARIMAX model
msarima(y, orders=list(ar=c(1,0), i=c(1,1), ma=c(1,1)),
        lags=c(1,24), xreg=X)
# Python
model = MSARIMA(ar_order=[1, 0], i_order=[1, 1], ma_order=[1, 1], lags=[1, 24])
model.fit(y, X=X)

Output / Attributes

Element (R) Element (Python) Type (R) Type (Python) Description
modelName() model_name character str Full model name (e.g., "ARIMA(0,1,1)")
orders() _arima["ar_orders"] etc. list Dict ARIMA orders used
lags() lags_used vector List Lags vector used
arma _arima["arma_parameters"] list list/None AR/MA parameter values (fixed or initialized)
constant constant_value numeric float/None Constant/drift value
B coef vector NDArray Estimated parameters (empty when all ARMA fixed)
fitted() fitted vector Series In-sample fitted values
residuals() residuals vector Series Model residuals
states states matrix DataFrame State matrix over time
transition transition matrix NDArray Transition matrix F
persistence persistence_vector vector Dict Persistence vector g
measurement measurement matrix NDArray Measurement matrix W
logLik loglik / loss_value numeric float Log-likelihood / loss value
AIC aic numeric float Akaike Information Criterion
AICc aicc numeric float Corrected AIC
BIC bic numeric float Bayesian Information Criterion
distribution distribution_ character str Error distribution used
scale scale / sigma numeric float Scale parameter

MSARIMA vs SSARIMA

Feature MSARIMA SSARIMA
Speed Fast Slow
Memory usage Low High
Multiple seasonality Optimized Full polynomial expansion
High-frequency data Recommended Can be slow

Use MSARIMA (or ADAM) for:

  • Hourly, sub-hourly data
  • Multiple seasonal patterns
  • Large datasets

References

See Also

Related Functions

  • ADAM - Unified framework (Python/R)
  • AutoADAM - Automatic distribution and ARIMA selection
  • SSARIMA - Original State Space ARIMA
  • ES - Exponential Smoothing

Parameter Documentation

Clone this wiki locally