SMA
Simple moving average in single-source-of-error state space form, with optional automatic order selection.
- class smooth.SMA(order=None, ic='AICc', h=10, holdout=False, fast=True, verbose=0, **kwargs)
Simple Moving Average in Single Source of Error state space form.
SMA(m) is an AR(m) state-space model where every AR coefficient is fixed at 1/m. It is implemented as a thin wrapper over
ADAMwithmodel="NNN"and the AR vector hard-coded, so it inherits the full ADAM fit / predict / diagnostics surface (multi-step forecasts, prediction intervals, residual diagnostics). Iforderis left unspecified, the order is selected automatically by information criterion.- Parameters:
order (
Optional[int]) – Order of the moving average. If None, selected automatically using the information criterion (ternary search whenfast=True, sequential scan whenfast=False).ic (
Literal['AIC','AICc','BIC','BICc']) – Information criterion used for automatic order selection.h (
int) – Forecast horizon (used withholdout=Trueto reserve a test set).holdout (
bool) – Whether to hold out the lasthobservations for validation.fast (
bool) – If True, use ternary search for order selection (fast, finds a local minimum). If False, evaluate all orders 1 … min(200, T) sequentially. When a pandas Series with a DatetimeIndex is passed, the inferred seasonal period is always evaluated as a candidate regardless of this flag.verbose (
int) – Verbosity level. 0 = silent.**kwargs – Additional arguments passed to ADAM (e.g.
n_iterations).
- model
Model name, e.g.
"SMA(3)".- Type:
str
- ICs_
IC values for each evaluated order (only present after auto-selection). Keys are order integers, values are IC floats.
- Type:
dict
See also
Examples
Fixed order:
>>> import numpy as np >>> from smooth import SMA >>> y = np.cumsum(np.random.randn(60)) + 100 >>> model = SMA(order=4, h=5) >>> model.fit(y) >>> fc = model.predict(h=5) >>> fc.mean
Auto-selected order:
>>> model = SMA(h=5) >>> model.fit(y) >>> print(model.model) # e.g. "SMA(3)" >>> print(model.ICs_)
References
Svetunkov, I., & Petropoulos, F. (2017). Old dog, new tricks: a modelling view of simple moving averages. International Journal of Production Research. https://doi.org/10.1080/00207543.2017.1380326
Overview
SMA(m) is the classical simple moving average expressed as an AR(m)
state-space model with every autoregressive coefficient fixed at 1/m.
Wrapping the moving average inside the ADAM framework — rather than treating
it as a rolling window — gives several practical advantages:
Multi-step forecasts are produced recursively from the state vector, not by repeating the last observation.
Forecast variance and prediction intervals follow directly from the state-space recursion, so intervals widen with the horizon as they should.
Automatic order selection is available: when
orderis left unspecified,SMAevaluates a range of orders and picks the one that minimises an information criterion (defaultAICc).Full ADAM API is inherited —
.fit(),.predict(), residual diagnostics, and theForecastResultreturn type all behave exactly as forADAM.
Internally SMA calls ADAM with model="NNN",
ar_order=m, arma={"ar": [1/m] * m}, initial="backcasting",
loss="MSE", and distribution="dnorm". These are fixed and cannot be
overridden — use ADAM or MSARIMA directly if you need
arbitrary AR coefficients.
Example Usage
Fixed order:
import numpy as np
from smooth import SMA
y = np.cumsum(np.random.randn(60)) + 100
model = SMA(order=4, h=5)
model.fit(y)
print(model) # e.g. "SMA(4)"
fc = model.predict(h=5, interval="prediction", level=0.95)
fc.mean
fc.lower, fc.upper
Automatically selected order:
model = SMA(h=5) # order=None → auto-select
model.fit(y)
print(model.model) # e.g. "SMA(3)"
print(model.ICs_) # {1: ic_1, 2: ic_2, ...} for evaluated orders
With holdout for validation:
model = SMA(h=12, holdout=True)
model.fit(y) # last 12 observations reserved as test set
fc = model.predict(h=12)
Order selection
When order is None, SMA searches over orders
1 … min(200, T) using the criterion given by ic (one of "AIC",
"AICc", "BIC", "BICc"). Two search modes are available:
fast=True(default) — ternary search, which converges to a local IC minimum without evaluating every order. Fast on long series. When the input is a pandasSerieswith aDatetimeIndex, the inferred seasonal period is also evaluated explicitly so seasonal moving averages are never missed.fast=False— sequential scan of every candidate order. Slower but guaranteed to find the global minimum within the search range.
The IC values from the search are stored on the fitted object as ICs_
(a dict keyed by order).
References
Svetunkov, I., & Petropoulos, F. (2017). Old dog, new tricks: a modelling view of simple moving averages. International Journal of Production Research. https://doi.org/10.1080/00207543.2017.1380326