Time Series

Complete time series analysis: ACF/PACF, stationarity tests, ETS, ARIMA/SARIMA, automatic model selection, and decomposition.

Time series analysis module.

Phase 7A: ACF/PACF, differencing, and stationarity tests. Phase 7B: Exponential smoothing (ETS) models. Phase 7C: ARIMA models, forecasting, and automatic order selection. Phase 7D: Time series decomposition (classical and STL).

Public API:

acf(x) - Autocorrelation function (matches R stats::acf) pacf(x) - Partial autocorrelation function (matches R stats::pacf) diff(x) - Difference a time series (matches R base::diff) ndiffs(x) - Estimate differences for stationarity (matches R forecast::ndiffs) adf_test(x) - Augmented Dickey-Fuller unit root test (matches R tseries::adf.test) kpss_test(x) - KPSS stationarity test (matches R tseries::kpss.test) ets(y) - Fit an ETS state space model (matches R forecast::ets,

including “Z”-wildcard automatic selection; default model=”ZZZ”. Reported log-likelihood/AIC use the full- Gaussian convention — R’s concentrated numbers differ by a constant in n; model rankings/selection are identical. See timeseries._ets_fit and ._ets_select docstrings.)

forecast_ets(f) - Forecast from a fitted ETS model arima(y) - Fit an ARIMA model (matches R stats::arima) forecast_arima(f, y) - Forecast from a fitted ARIMA model auto_arima(y) - Automatic ARIMA order selection (matches R forecast::auto.arima) decompose(x) - Classical time series decomposition (matches R stats::decompose) stl(x) - STL decomposition (matches R stats::stl; identical parameters

reproduce R’s components to floating-point noise. Interface divergences, both deliberate: seasonal_window defaults to “periodic” where R requires it explicitly, and even/short loess spans raise instead of being silently rounded up.)

pystatistics.timeseries.acf(x, *, max_lag=None, conf_level=0.95, demean=True)[source]

Compute the autocorrelation function.

Matches R’s stats::acf(type=”correlation”).

Algorithm:

c(k) = (1/n) * sum_{t=1}^{n-k} (x_t - x_bar)(x_{t+k} - x_bar) acf(k) = c(k) / c(0)

Confidence intervals use Bartlett’s approximation under the white noise null hypothesis: +/- z_{alpha/2} / sqrt(n).

Parameters:
  • x (ArrayLike) – Time series (1-D array).

  • max_lag (int or None) – Maximum lag to compute. Default: min(10*log10(n), n-1), matching R.

  • conf_level (float) – Confidence level for CI bands. Must be in (0, 1).

  • demean (bool) – Whether to subtract the mean before computing. Default True, matches R.

Returns:

Result containing acf values, lags, and confidence bands.

Return type:

ACFSolution

Raises:

ValidationError – If inputs are invalid (NaN, non-1D, bad max_lag, etc.).

Notes

Validated against R stats::acf().

pystatistics.timeseries.pacf(x, *, max_lag=None, conf_level=0.95)[source]

Compute the partial autocorrelation function.

Matches R’s stats::pacf(). Uses the Durbin-Levinson recursion.

Algorithm:

phi_{1,1} = acf(1) For k = 2, 3, …:

phi_{k,k} = (acf(k) - sum_{j=1}^{k-1} phi_{k-1,j} * acf(k-j)) /

(1 - sum_{j=1}^{k-1} phi_{k-1,j} * acf(j))

phi_{k,j} = phi_{k-1,j} - phi_{k,k} * phi_{k-1,k-j} for j < k

Note: R’s pacf() does NOT include lag 0. Lags start from 1.

Confidence intervals: +/- z_{alpha/2} / sqrt(n) (same as ACF under white noise null hypothesis).

Parameters:
  • x (ArrayLike) – Time series (1-D array).

  • max_lag (int or None) – Maximum lag to compute. Default: min(10*log10(n), n-1), matching R.

  • conf_level (float) – Confidence level for CI bands. Must be in (0, 1).

Returns:

Result with type=’partial’. Lags start at 1 (no lag 0).

Return type:

ACFSolution

Raises:

ValidationError – If inputs are invalid.

Notes

Validated against R stats::pacf().

pystatistics.timeseries.diff(x, differences=1, lag=1)[source]

Difference a time series.

Matches R’s base::diff().

For differences=1, lag=1: y[t] = x[t] - x[t-1] For differences=1, lag=12: y[t] = x[t] - x[t-12] (seasonal) For differences=2: apply differencing twice.

Parameters:
  • x (ArrayLike) – Time series (1-D array).

  • differences (int) – Number of times to difference. Default 1. Must be >= 1.

  • lag (int) – Lag for differencing. Default 1. Must be >= 1.

Returns:

Differenced series of length n - differences * lag.

Return type:

NDArray

Raises:

ValidationError – If inputs are invalid or the series is too short after differencing.

pystatistics.timeseries.ndiffs(x, *, test='kpss', alpha=0.05, max_d=2)[source]

Estimate the number of differences needed for stationarity.

Matches R’s forecast::ndiffs(), including its default test. Repeatedly differences and tests for stationarity until either the test indicates stationarity or max_d is reached.

Parameters:
  • x (ArrayLike) – Time series.

  • test (str) – Stationarity test to use: ‘kpss’ (default, matching R forecast::ndiffs) or ‘adf’. The two tests have opposite null hypotheses (KPSS: stationary; ADF: unit root) and can recommend different d on borderline series.

  • alpha (float) – Significance level for the test.

  • max_d (int) – Maximum number of differences to try.

Returns:

Recommended number of differences (0, 1, …, max_d).

Return type:

int

Raises:

ValidationError – If inputs are invalid.

pystatistics.timeseries.adf_test(x, *, n_lags=None, regression='c')[source]

Augmented Dickey-Fuller test for unit root.

Matches R’s tseries::adf.test().

Tests H0: x has a unit root (non-stationary) vs H1: x is stationary

The test regression is:
Delta_x_t = alpha + beta*t + gamma*x_{t-1}
  • sum_{i=1}^{p} delta_i * Delta_x_{t-i} + eps_t

The test statistic is the t-statistic for gamma. The regression parameter controls which deterministic terms are included: - ‘nc’: no constant, no trend - ‘c’: constant only (default, matches R) - ‘ct’: constant + linear trend

Parameters:
  • x (ArrayLike) – Time series (1-D array). Must have at least 3 observations.

  • n_lags (int or None) – Number of lagged difference terms. Default: floor((n-1)^(1/3)), matching R’s tseries::adf.test().

  • regression (str) – ‘nc’ (none), ‘c’ (constant), ‘ct’ (constant + trend).

Returns:

Test result with statistic, p-value, and critical values.

Return type:

StationaritySolution

Raises:

ValidationError – If inputs are invalid.

Notes

Validated against R tseries::adf.test().

pystatistics.timeseries.kpss_test(x, *, regression='c', n_lags=None)[source]

KPSS test for stationarity.

Matches R’s tseries::kpss.test().

Tests H0: x is (level or trend) stationary vs H1: x has a unit root

NOTE: KPSS has the OPPOSITE null hypothesis to ADF.

Algorithm:
  1. Regress x on deterministic terms (constant, or constant+trend).

  2. Compute partial sums S_t = sum_{i=1}^{t} e_i of residuals.

  3. Statistic: eta = (1/n^2) * sum S_t^2 / sigma^2_LR where sigma^2_LR is the long-run variance estimator using a Bartlett kernel: sigma^2_LR = gamma(0) + 2 * sum_{j=1}^{l} (1 - j/(l+1)) * gamma(j)

Parameters:
  • x (ArrayLike) – Time series (1-D array). Must have at least 3 observations.

  • regression (str) – ‘c’ (level stationarity) or ‘ct’ (trend stationarity).

  • n_lags (int or None) – Number of lags for Bartlett kernel. Default: floor(3*sqrt(n)/13), matching R.

Returns:

Test result with statistic, p-value, and critical values.

Return type:

StationaritySolution

Raises:

ValidationError – If inputs are invalid.

Notes

Validated against R tseries::kpss.test().

class pystatistics.timeseries.ACFParams(acf, lags, n_obs, conf_level, ci_upper, ci_lower, type)[source]

Bases: object

Immutable parameter payload for ACF / PACF results.

Parameters:
acf

Autocorrelation values at each lag. For ACF, includes lag 0 (= 1.0). For PACF, starts at lag 1 (matching R’s pacf()).

Type:

NDArray

lags

Lag indices corresponding to each acf value.

Type:

NDArray

n_obs

Number of observations in the original series.

Type:

int

conf_level

Confidence level used for the confidence bands.

Type:

float

ci_upper

Upper confidence bound per lag.

Type:

NDArray

ci_lower

Lower confidence bound per lag.

Type:

NDArray

type

‘correlation’ for ACF or ‘partial’ for PACF.

Type:

str

acf: ndarray[tuple[Any, ...], dtype[_ScalarT]]
lags: ndarray[tuple[Any, ...], dtype[_ScalarT]]
n_obs: int
conf_level: float
ci_upper: ndarray[tuple[Any, ...], dtype[_ScalarT]]
ci_lower: ndarray[tuple[Any, ...], dtype[_ScalarT]]
type: str
class pystatistics.timeseries.ACFSolution(_result)[source]

Bases: SolutionReprMixin

Result from autocorrelation or partial autocorrelation computation.

Wraps a Result [ACFParams] envelope; every datum is exposed via a read-only @property so the public attribute surface is unchanged from the previous flat dataclass.

Parameters:

_result (Result[ACFParams])

acf

Autocorrelation values at each lag. For ACF, includes lag 0 (= 1.0). For PACF, starts at lag 1 (matching R’s pacf()).

Type:

NDArray

lags

Lag indices corresponding to each acf value.

Type:

NDArray

n_obs

Number of observations in the original series.

Type:

int

conf_level

Confidence level used for the confidence bands.

Type:

float

ci_upper

Upper confidence bound per lag.

Type:

NDArray

ci_lower

Lower confidence bound per lag.

Type:

NDArray

type

‘correlation’ for ACF or ‘partial’ for PACF.

Type:

str

property acf: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property lags: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property n_obs: int
property conf_level: float
property ci_upper: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property ci_lower: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property type: str
property info: dict
property timing: dict[str, float] | None
property backend_name: str
property warnings: tuple[str, ...]
summary()[source]

Return a human-readable summary of the ACF/PACF result.

Returns:

Multi-line summary string.

Return type:

str

class pystatistics.timeseries.StationarityParams(statistic, p_value, method, alternative, n_lags, n_obs, critical_values)[source]

Bases: object

Immutable parameter payload for a stationarity test.

Parameters:
statistic

Test statistic value.

Type:

float

p_value

p-value of the test. For KPSS, may be truncated to the table range (0.01 to 0.10).

Type:

float

method

Name of the test, e.g. ‘Augmented Dickey-Fuller’, ‘KPSS’.

Type:

str

alternative

Alternative hypothesis description, e.g. ‘stationary’ for ADF, ‘unit root’ for KPSS.

Type:

str

n_lags

Number of lags used in the test.

Type:

int

n_obs

Number of observations used (after differencing/lag adjustments).

Type:

int

critical_values

Critical values at standard significance levels, e.g. {‘1%’: -3.43, ‘5%’: -2.86, ‘10%’: -2.57}.

Type:

dict[str, float] | None

statistic: float
p_value: float
method: str
alternative: str
n_lags: int
n_obs: int
critical_values: dict[str, float] | None
class pystatistics.timeseries.StationaritySolution(_result)[source]

Bases: SolutionReprMixin

Result from a stationarity test (ADF, KPSS, PP).

Wraps a Result [StationarityParams] envelope; every datum is exposed via a read-only @property so the public attribute surface is unchanged from the previous flat dataclass.

Parameters:

_result (Result[StationarityParams])

statistic

Test statistic value.

Type:

float

p_value

p-value of the test. For KPSS, may be truncated to the table range (0.01 to 0.10).

Type:

float

method

Name of the test, e.g. ‘Augmented Dickey-Fuller’, ‘KPSS’.

Type:

str

alternative

Alternative hypothesis description, e.g. ‘stationary’ for ADF, ‘unit root’ for KPSS.

Type:

str

n_lags

Number of lags used in the test.

Type:

int

n_obs

Number of observations used (after differencing/lag adjustments).

Type:

int

critical_values

Critical values at standard significance levels, e.g. {‘1%’: -3.43, ‘5%’: -2.86, ‘10%’: -2.57}.

Type:

dict[str, float] | None

property statistic: float
property p_value: float
property method: str
property alternative: str
property n_lags: int
property n_obs: int
property critical_values: dict[str, float] | None
property info: dict
property timing: dict[str, float] | None
property backend_name: str
property warnings: tuple[str, ...]
summary()[source]

Return a human-readable summary of the stationarity test result.

Returns:

Multi-line summary string matching R-style output.

Return type:

str

pystatistics.timeseries.ets(y, *, model='ZZZ', period=1, damped=None, alpha=None, beta=None, gamma=None, phi=None, ic='aicc', tol=1e-10, max_iter=1000)[source]

Fit an ETS (ExponenTial Smoothing) state space model.

Matches R’s forecast::ets(): each component of the model string may be a concrete letter or a "Z" wildcard, and wildcards are resolved by fitting every admissible candidate and selecting the one minimising ic. The default model="ZZZ" performs full automatic selection, as in R. See the module docstring for the exact candidate table and the documented divergences from R.

Parameters:
  • y (ArrayLike) – Time series (1-D). Multiplicative components require strictly positive values.

  • model (str) – ETS model string — error, trend, season — e.g. 'ZZZ' (default: select everything), 'ANN', 'AAdN', 'MZZ', 'ZZN'.

  • period (int) – Seasonal period (e.g. 12 for monthly, 4 for quarterly). Seasonal models require 2 <= period <= 24.

  • damped (bool or None) – Damped-trend control. With a concrete model string it forces or forbids damping; with a 'Z' trend, None means both damped and undamped candidates are tried, True/False restricts the candidate set accordingly. damped=True with a trend fixed to 'N' raises (R: “Forbidden model combination”).

  • alpha (float or None) – Fix specific smoothing parameters (applies to every candidate). Fixed values must lie in R’s “usual” region (see _ets_fit.py); out-of-range values raise instead of being coerced into bounds.

  • beta (float or None) – Fix specific smoothing parameters (applies to every candidate). Fixed values must lie in R’s “usual” region (see _ets_fit.py); out-of-range values raise instead of being coerced into bounds.

  • gamma (float or None) – Fix specific smoothing parameters (applies to every candidate). Fixed values must lie in R’s “usual” region (see _ets_fit.py); out-of-range values raise instead of being coerced into bounds.

  • phi (float or None) – Fix specific smoothing parameters (applies to every candidate). Fixed values must lie in R’s “usual” region (see _ets_fit.py); out-of-range values raise instead of being coerced into bounds.

  • ic (str) – Selection criterion for wildcard models: 'aicc' (default, matching forecast::ets), 'aic', or 'bic'. AICc-based selection needs n >= 5 (see module docstring).

  • tol (float) – Convergence tolerance for the optimiser.

  • max_iter (int) – Maximum optimiser iterations.

Returns:

The fitted (for wildcards: selected) model. For wildcard requests, solution.info["selection"] records the requested string, the criterion, every candidate’s IC value, and any skipped candidates with the reason.

Return type:

ETSSolution

Raises:
  • ValidationError – On invalid inputs; on an explicitly requested component that cannot be honoured (e.g. multiplicative error on non-positive data, a seasonal letter with period of 1 or > 24, damped=True with trend 'N'); when no candidate is admissible; or when no candidate has a finite ic (series too short for AICc).

  • ConvergenceError – If candidates were attempted but none could be fitted.

class pystatistics.timeseries.ETSParams(spec, alpha, beta, gamma, phi, init_level, init_trend, init_season, fitted_values, residuals, states, log_likelihood, aic, aicc, bic, mse, mae, n_obs, n_params, converged)[source]

Bases: object

Immutable parameter payload for a fitted ETS model.

Parameters:
spec

The fitted model specification.

Type:

ETSSpec

alpha

Level smoothing parameter.

Type:

float

beta

Trend smoothing parameter (None if no trend).

Type:

float or None

gamma

Seasonal smoothing parameter (None if no season).

Type:

float or None

phi

Damping parameter (None if not damped).

Type:

float or None

init_level

Estimated initial level.

Type:

float

init_trend

Estimated initial trend (None if no trend).

Type:

float or None

init_season

Estimated initial seasonal indices (None if no season).

Type:

NDArray or None

fitted_values

One-step-ahead fitted values, length n.

Type:

NDArray

residuals

Residuals, length n.

Type:

NDArray

states

Full state history, shape (n + 1, n_states).

Type:

NDArray

log_likelihood

Maximised full Gaussian log-likelihood. R’s forecast::ets reports the concentrated pseudo-log-likelihood -0.5*n*log(SSE) instead; this value equals R’s plus the constant 0.5*n*[log(n/(2*pi)) - 1] (sample-size only, so all model comparisons on the same data are unaffected).

Type:

float

aic

Akaike Information Criterion, -2*log_likelihood + 2*k with the full-Gaussian log-likelihood above. Differs from forecast::ets’s printed AIC by -n*[log(n/(2*pi)) - 1]; AIC differences and rankings between models match R exactly.

Type:

float

aicc

Corrected AIC (for small samples); same convention note as aic.

Type:

float

bic

Bayesian Information Criterion; same convention note as aic.

Type:

float

mse

Mean squared error of residuals.

Type:

float

mae

Mean absolute error of residuals.

Type:

float

n_obs

Number of observations.

Type:

int

n_params

Total number of estimated parameters (smoothing + free initial states + sigma^2). Seasonal models estimate m - 1 initial seasonal states — the remaining one is fixed by the normalisation, as in R forecast::ets — so the count matches R’s.

Type:

int

converged

Whether the optimiser converged.

Type:

bool

spec: ETSSpec
alpha: float
beta: float | None
gamma: float | None
phi: float | None
init_level: float
init_trend: float | None
init_season: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None
fitted_values: ndarray[tuple[Any, ...], dtype[_ScalarT]]
residuals: ndarray[tuple[Any, ...], dtype[_ScalarT]]
states: ndarray[tuple[Any, ...], dtype[_ScalarT]]
log_likelihood: float
aic: float
aicc: float
bic: float
mse: float
mae: float
n_obs: int
n_params: int
converged: bool
class pystatistics.timeseries.ETSSolution(_result)[source]

Bases: SolutionReprMixin

Result from fitting an ETS model.

Wraps a Result [ETSParams] envelope; every datum is exposed via a read-only @property so the public attribute surface is unchanged from the previous flat dataclass.

Parameters:

_result (Result[ETSParams])

property spec: ETSSpec
property alpha: float
property beta: float | None
property gamma: float | None
property phi: float | None
property init_level: float
property init_trend: float | None
property init_season: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None
property fitted_values: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property residuals: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property states: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property log_likelihood: float

Full Gaussian log-likelihood.

R’s forecast::ets reports the concentrated pseudo- log-likelihood -0.5*n*log(SSE); this value equals R’s plus the deterministic constant 0.5*n*[log(n/(2*pi)) - 1]. Model comparisons on the same data are identical either way.

property aic: float

AIC under the full-Gaussian log-likelihood.

Differs from forecast::ets’s printed AIC by the constant -n*[log(n/(2*pi)) - 1]; AIC differences and model rankings match R exactly (same parameter count k).

property aicc: float

AICc; same convention note as aic.

property bic: float

BIC; same convention note as aic.

property mse: float
property mae: float
property n_obs: int
property n_params: int
property converged: bool
property info: dict
property timing: dict[str, float] | None
property backend_name: str
property warnings: tuple[str, ...]
summary()[source]

Return a human-readable summary matching R’s forecast::ets() style.

Returns:

Multi-line summary.

Return type:

str

pystatistics.timeseries.forecast_ets(fitted, h=10, *, levels=None)[source]

Generate forecasts from a fitted ETS model.

Parameters:
  • fitted (ETSSolution) – A fitted ETS model (from ets()).

  • h (int) – Forecast horizon (number of steps ahead).

  • levels (list of int, optional) – Prediction interval levels in percent (default [80, 95]).

Returns:

Point forecasts and prediction intervals.

Return type:

ETSForecast

Raises:

ValidationError – If h < 1 or levels are invalid.

class pystatistics.timeseries.ETSForecast(mean, lower, upper, h, model, fitted)[source]

Bases: object

Forecast from a fitted ETS model.

Parameters:
mean

Point forecasts of length h.

Type:

NDArray

lower

Lower prediction-interval bounds keyed by level (e.g. {80: ..., 95: ...}).

Type:

dict[int, NDArray]

upper

Upper prediction-interval bounds keyed by level.

Type:

dict[int, NDArray]

h

Forecast horizon.

Type:

int

model

Model specification used.

Type:

ETSSpec

fitted

The underlying fitted model.

Type:

ETSSolution

mean: ndarray[tuple[Any, ...], dtype[_ScalarT]]
lower: dict[int, ndarray[tuple[Any, ...], dtype[_ScalarT]]]
upper: dict[int, ndarray[tuple[Any, ...], dtype[_ScalarT]]]
h: int
model: ETSSpec
fitted: ETSSolution
summary()[source]

Return a human-readable forecast summary.

Returns:

Multi-line table of forecasts and intervals.

Return type:

str

class pystatistics.timeseries.ETSSpec(error, trend, season, period, damped)[source]

Bases: object

Specification of an ETS model type.

Parameters:
error

Error type: 'A' (additive) or 'M' (multiplicative).

Type:

str

trend

Trend type: 'N' (none), 'A' (additive), or 'Ad' (damped).

Type:

str

season

Season type: 'N' (none), 'A' (additive), or 'M' (multiplicative).

Type:

str

period

Seasonal period (1 when no seasonal component).

Type:

int

damped

True when trend is 'Ad'.

Type:

bool

error: str
trend: str
season: str
period: int
damped: bool
property name: str

Human-readable model name, e.g. 'ETS(A,Ad,N)'.

property n_states: int

1 (level) + trend? + season?.

Type:

Number of state variables

property n_params: int

Number of smoothing parameters (alpha, beta, gamma, phi).

pystatistics.timeseries.arima(y, *, order=(0, 0, 0), seasonal=None, include_mean=True, method='CSS-ML', tol=1e-08, max_iter=1000, backend=None)[source]

Fit an ARIMA(p, d, q) or seasonal ARIMA(p, d, q)(P, D, Q)[m] model.

Matches the interface and numerical approach of R’s stats::arima().

For non-seasonal ARIMA(p, d, q):
  1. Difference the series d times.

  2. Fit ARMA(p, q) to the differenced series.

For seasonal ARIMA(p, d, q)(P, D, Q)[m]:
  1. Seasonally difference D times (lag m).

  2. Difference d times.

  3. Multiply out the seasonal and non-seasonal AR/MA polynomials to form effective ARMA coefficients.

- ``'CSS'``

Conditional sum of squares (fast, approximate).

- ``'ML'``

Exact maximum likelihood via innovations algorithm.

- ``'CSS-ML'``

CSS for initialization, then ML refinement (default).

Starting values:
  • AR: Yule-Walker estimates from autocorrelations.

  • MA: zeros.

  • Mean: sample mean of the differenced series.

Parameters:
  • y (ArrayLike) – Time series (1-D array).

  • order (tuple[int, int, int]) – (p, d, q) — AR order, differencing order, MA order.

  • seasonal (tuple[int, int, int, int] or None) – (P, D, Q, m) — seasonal AR order, seasonal differencing order, seasonal MA order, and period. None for non-seasonal models.

  • include_mean (bool) – Whether to include a mean term. Default True.

  • method (str) – 'CSS', 'ML', or 'CSS-ML'. Default 'CSS-ML'.

  • tol (float) – Convergence tolerance for the optimizer. Default 1e-8.

  • max_iter (int) – Maximum optimizer iterations. Default 1000.

  • backend (str | None)

Returns:

Fitted model with coefficients, residuals, and diagnostics.

Return type:

ARIMASolution

Raises:
class pystatistics.timeseries.ARIMAParams(order, seasonal_order, ar, ma, seasonal_ar, seasonal_ma, mean, sigma2, vcov, residuals, fitted_values, log_likelihood, aic, aicc, bic, n_obs, n_used, method, converged, n_iter)[source]

Bases: object

Immutable parameter payload for a fitted ARIMA model.

Parameters:
order

(p, d, q) — AR order, differencing order, MA order.

Type:

tuple[int, int, int]

seasonal_order

(P, D, Q, m) — seasonal orders and period, or None.

Type:

tuple[int, int, int, int] or None

ar

AR coefficients (length p). For seasonal models, these are the non-seasonal AR coefficients only.

Type:

NDArray

ma

MA coefficients (length q). For seasonal models, these are the non-seasonal MA coefficients only.

Type:

NDArray

seasonal_ar

Seasonal AR coefficients (length P). Empty if non-seasonal.

Type:

NDArray

seasonal_ma

Seasonal MA coefficients (length Q). Empty if non-seasonal.

Type:

NDArray

mean

Estimated mean of the differenced series (None if include_mean=False).

Type:

float or None

sigma2

Estimated innovation variance.

Type:

float

vcov

Variance-covariance matrix of the estimated coefficients (AR, MA, seasonal AR, seasonal MA, mean). Computed from the numerical Hessian of the negative log-likelihood.

Type:

NDArray

residuals

Innovation residuals (length of the differenced series).

Type:

NDArray

fitted_values

One-step-ahead fitted values (length of the differenced series).

Type:

NDArray

log_likelihood

Maximized log-likelihood value.

Type:

float

aic

Akaike information criterion: -2*loglik + 2*k.

Type:

float

aicc

Corrected AIC: AIC + 2*k*(k+1)/(n-k-1).

Type:

float

bic

Bayesian information criterion: -2*loglik + k*log(n).

Type:

float

n_obs

Length of the original (undifferenced) series.

Type:

int

n_used

Number of observations used in estimation (after differencing).

Type:

int

method

Estimation method: 'CSS', 'ML', or 'CSS-ML'.

Type:

str

converged

Whether the optimizer converged.

Type:

bool

n_iter

Number of optimizer iterations.

Type:

int

order: tuple[int, int, int]
seasonal_order: tuple[int, int, int, int] | None
ar: ndarray[tuple[Any, ...], dtype[_ScalarT]]
ma: ndarray[tuple[Any, ...], dtype[_ScalarT]]
seasonal_ar: ndarray[tuple[Any, ...], dtype[_ScalarT]]
seasonal_ma: ndarray[tuple[Any, ...], dtype[_ScalarT]]
mean: float | None
sigma2: float
vcov: ndarray[tuple[Any, ...], dtype[_ScalarT]]
residuals: ndarray[tuple[Any, ...], dtype[_ScalarT]]
fitted_values: ndarray[tuple[Any, ...], dtype[_ScalarT]]
log_likelihood: float
aic: float
aicc: float
bic: float
n_obs: int
n_used: int
method: str
converged: bool
n_iter: int
class pystatistics.timeseries.ARIMASolution(_result)[source]

Bases: SolutionReprMixin

Result from fitting an ARIMA model.

Wraps a Result [ARIMAParams] envelope; every datum is exposed via a read-only @property so the public attribute surface is unchanged from the previous flat dataclass.

Parameters:

_result (Result[ARIMAParams])

order

(p, d, q) — AR order, differencing order, MA order.

Type:

tuple[int, int, int]

seasonal_order

(P, D, Q, m) — seasonal orders and period, or None.

Type:

tuple[int, int, int, int] or None

ar

AR coefficients (length p). For seasonal models, these are the non-seasonal AR coefficients only.

Type:

NDArray

ma

MA coefficients (length q). For seasonal models, these are the non-seasonal MA coefficients only.

Type:

NDArray

seasonal_ar

Seasonal AR coefficients (length P). Empty if non-seasonal.

Type:

NDArray

seasonal_ma

Seasonal MA coefficients (length Q). Empty if non-seasonal.

Type:

NDArray

mean

Estimated mean of the differenced series (None if include_mean=False).

Type:

float or None

sigma2

Estimated innovation variance.

Type:

float

vcov

Variance-covariance matrix of the estimated coefficients.

Type:

NDArray

residuals

Innovation residuals (length of the differenced series).

Type:

NDArray

fitted_values

One-step-ahead fitted values (length of the differenced series).

Type:

NDArray

log_likelihood

Maximized log-likelihood value.

Type:

float

aic

Akaike information criterion.

Type:

float

aicc

Corrected AIC.

Type:

float

bic

Bayesian information criterion.

Type:

float

n_obs

Length of the original (undifferenced) series.

Type:

int

n_used

Number of observations used in estimation (after differencing).

Type:

int

method

Estimation method: 'CSS', 'ML', or 'CSS-ML'.

Type:

str

converged

Whether the optimizer converged.

Type:

bool

n_iter

Number of optimizer iterations.

Type:

int

property order: tuple[int, int, int]
property seasonal_order: tuple[int, int, int, int] | None
property ar: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property ma: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property seasonal_ar: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property seasonal_ma: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property mean: float | None
property sigma2: float
property vcov: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property residuals: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property fitted_values: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property log_likelihood: float
property aic: float
property aicc: float
property bic: float
property n_obs: int
property n_used: int
property method: str
property converged: bool
property n_iter: int
property info: dict
property timing: dict[str, float] | None
property backend_name: str
property warnings: tuple[str, ...]
property n_params: int

Total number of estimated parameters (AR + MA + seasonal + mean + sigma2).

summary()[source]

R-style summary matching stats::arima() output.

Returns:

Multi-line summary string.

Return type:

str

pystatistics.timeseries.arima_batch(Y, *, order=(0, 0, 0), include_mean=True, method='Whittle', tol=1e-05, max_iter=300, lr=0.05, backend=None)[source]

Fit K independent ARMA(p, d, q) models on the rows of Y.

Parameters:
  • Y (ArrayLike or torch.Tensor) – Shape (K, n). Each row is an independent time series.

  • order (tuple[int, int, int]) – (p, d, q). Differencing d is applied per-series before the ARMA fit.

  • include_mean (bool) – Whether to report the per-series sample mean of the differenced series. Default True. Whittle is centred internally regardless.

  • method (str) – Only 'Whittle' is supported for batch fitting in 1.9.0.

  • tol (float) – Per-series gradient-norm (L∞) convergence tolerance.

  • max_iter (int) – Maximum Adam iterations (batched) / maximum per-series L-BFGS-B iterations (CPU loop).

  • lr (float) – Adam learning rate (GPU path only). 0.05 is the default tuned for typical Whittle NLL curvature — smaller if you see per-series non-convergence, larger if you want faster wall time on easy problems.

  • backend (str or None) – Compute backend = (device, precision). 'cpu' (default — loop over arima() with method='Whittle', float64), 'gpu' (float32, require GPU), 'gpu_fp64' (float64, CUDA only — raises on MPS), 'auto' (GPU-float32 if CUDA present, else CPU loop). A torch.Tensor input routes to its own device automatically (see CONVENTIONS.md).

Return type:

ARMABatchSolution

class pystatistics.timeseries.ARMABatchParams(order, ar, ma, sigma2, mean, n_iter, converged, n_series, n_used, method)[source]

Bases: object

Immutable parameter payload for a batched ARMA fit.

Parameters:
order

(p, d, q). The d that was applied before the ARMA fit.

Type:

tuple[int, int, int]

ar

AR coefficients, shape (K, p).

Type:

NDArray

ma

MA coefficients, shape (K, q).

Type:

NDArray

sigma2

Innovation variance per series, shape (K,).

Type:

NDArray

mean

Per-series sample mean of the differenced series (None if include_mean=False).

Type:

NDArray | None

n_iter

Maximum iteration count across all series.

Type:

int

converged

Per-series boolean convergence flag, shape (K,).

Type:

NDArray

n_series

Number of series K.

Type:

int

n_used

Length of each (post-differencing) series.

Type:

int

method

Which fitter ran: 'Whittle-batch-GPU', 'Whittle-loop-CPU'.

Type:

str

order: tuple[int, int, int]
ar: ndarray[tuple[Any, ...], dtype[_ScalarT]]
ma: ndarray[tuple[Any, ...], dtype[_ScalarT]]
sigma2: ndarray[tuple[Any, ...], dtype[_ScalarT]]
mean: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None
n_iter: int
converged: ndarray[tuple[Any, ...], dtype[_ScalarT]]
n_series: int
n_used: int
method: str
class pystatistics.timeseries.ARMABatchSolution(_result)[source]

Bases: SolutionReprMixin

Result from a batched ARMA fit.

Wraps a Result [ARMABatchParams] envelope; every datum is exposed via a read-only @property so the public attribute surface is unchanged from the previous flat dataclass.

Parameters:

_result (Result[ARMABatchParams])

order

(p, d, q). The d that was applied before the ARMA fit.

Type:

tuple[int, int, int]

ar

AR coefficients, shape (K, p).

Type:

NDArray

ma

MA coefficients, shape (K, q).

Type:

NDArray

sigma2

Innovation variance per series, shape (K,).

Type:

NDArray

mean

Per-series sample mean of the differenced series (None if include_mean=False).

Type:

NDArray | None

n_iter

Maximum iteration count across all series.

Type:

int

converged

Per-series boolean convergence flag, shape (K,).

Type:

NDArray

n_series

Number of series K.

Type:

int

n_used

Length of each (post-differencing) series.

Type:

int

method

Which fitter ran: 'Whittle-batch-GPU', 'Whittle-loop-CPU'.

Type:

str

property order: tuple[int, int, int]
property ar: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property ma: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property sigma2: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property mean: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None
property n_iter: int
property converged: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property n_series: int
property n_used: int
property method: str
property info: dict
property timing: dict[str, float] | None
property backend_name: str
property warnings: tuple[str, ...]
summary()[source]

Compact summary of a batched ARMA fit across the K series.

Return type:

str

pystatistics.timeseries.forecast_arima(fitted, y_original, *, h=10, levels=None)[source]

Generate forecasts from a fitted ARIMA model.

Matches R’s predict.Arima() / forecast::forecast.Arima().

Parameters:
  • fitted (ARIMASolution) – A fitted ARIMA model (from arima()).

  • y_original (ArrayLike) – The original (un-differenced) time series that was passed to arima(). Needed to reverse the differencing.

  • h (int) – Forecast horizon (number of steps ahead). Default 10.

  • levels (list of int, optional) – Prediction-interval levels in percent (default [80, 95]).

Returns:

Point forecasts and prediction intervals on the original scale.

Return type:

ARIMAForecast

Raises:

ValidationError – If h < 1 or levels are invalid.

class pystatistics.timeseries.ARIMAForecast(mean, se, lower, upper, h, order)[source]

Bases: object

Forecast from a fitted ARIMA model.

Parameters:
mean

Point forecasts on the original (un-differenced) scale, length h.

Type:

NDArray

se

Standard errors of forecasts, length h.

Type:

NDArray

lower

Lower prediction-interval bounds keyed by level (e.g. 80, 95).

Type:

dict[int, NDArray]

upper

Upper prediction-interval bounds keyed by level.

Type:

dict[int, NDArray]

h

Forecast horizon.

Type:

int

order

The (p, d, q) order of the model.

Type:

tuple[int, int, int]

mean: ndarray[tuple[Any, ...], dtype[_ScalarT]]
se: ndarray[tuple[Any, ...], dtype[_ScalarT]]
lower: dict[int, ndarray[tuple[Any, ...], dtype[_ScalarT]]]
upper: dict[int, ndarray[tuple[Any, ...], dtype[_ScalarT]]]
h: int
order: tuple[int, int, int]
summary()[source]

Return a human-readable forecast summary.

Returns:

Multi-line table of point forecasts and intervals.

Return type:

str

pystatistics.timeseries.auto_arima(y, *, max_p=5, max_q=5, max_d=2, max_P=2, max_Q=2, max_D=1, period=1, ic='aicc', stepwise=True, tol=1e-08, max_iter=1000, method='CSS-ML', backend=None)[source]

Automatic ARIMA model selection.

Simplified version of R’s forecast::auto.arima().

For stepwise=True the Hyndman–Khandakar (2008) algorithm is used: start from a set of initial candidates and greedily explore neighbouring orders.

For stepwise=False an exhaustive grid search over all p = 0 .. max_p, q = 0 .. max_q combinations is performed (much slower but thorough).

Parameters:
  • y (ArrayLike) – Time series.

  • max_p (int) – Maximum non-seasonal AR / MA orders.

  • max_q (int) – Maximum non-seasonal AR / MA orders.

  • max_d (int) – Maximum non-seasonal differencing order.

  • max_P (int) – Maximum seasonal orders.

  • max_Q (int) – Maximum seasonal orders.

  • max_D (int) – Maximum seasonal orders.

  • period (int) – Seasonal period (1 = non-seasonal).

  • ic (str) – Information criterion: 'aic', 'aicc', or 'bic'.

  • stepwise (bool) – Use stepwise search (default) or grid search.

  • tol (float) – Convergence tolerance passed to arima().

  • max_iter (int) – Maximum iterations passed to arima().

  • method (str) – Estimation method forwarded to every candidate fit. Default 'CSS-ML' matches R. Use 'Whittle' with backend='gpu' to route each candidate through the frequency-domain GPU path.

  • backend (str or None) – Backend forwarded to every candidate fit. Default None → CPU (R-reference path). Pass 'gpu' or 'auto' to opt into the GPU path; only meaningful when the candidate fits actually support it (e.g. method='Whittle').

Returns:

Best model and search history.

Return type:

AutoARIMASolution

Raises:
class pystatistics.timeseries.AutoARIMAParams(best_model, best_order, best_seasonal, best_aic, models_fitted, search_results)[source]

Bases: object

Immutable parameter payload for automatic ARIMA order selection.

Parameters:
best_model

The fitted model with the best information criterion.

Type:

ARIMASolution

best_order

The (p, d, q) order of the best model.

Type:

tuple[int, int, int]

best_seasonal

The (P, D, Q, m) seasonal order, or None.

Type:

tuple[int, int, int, int] | None

best_aic

Value of the chosen information criterion for the best model.

Type:

float

models_fitted

Total number of models successfully evaluated.

Type:

int

search_results

(order, ic_value) pairs for every model tried (including those that failed, recorded with inf).

Type:

list[tuple[tuple, float]]

best_model: object
best_order: tuple[int, int, int]
best_seasonal: tuple[int, int, int, int] | None
best_aic: float
models_fitted: int
search_results: list[tuple[tuple, float]]
class pystatistics.timeseries.AutoARIMASolution(_result)[source]

Bases: SolutionReprMixin

Result from automatic ARIMA order selection.

Wraps a Result [AutoARIMAParams] envelope; every datum is exposed via a read-only @property so the public attribute surface is unchanged from the previous flat dataclass.

Parameters:

_result (Result[AutoARIMAParams])

best_model

The fitted model with the best information criterion.

Type:

ARIMASolution

best_order

The (p, d, q) order of the best model.

Type:

tuple[int, int, int]

best_seasonal

The (P, D, Q, m) seasonal order, or None.

Type:

tuple[int, int, int, int] | None

best_aic

Value of the chosen information criterion for the best model.

Type:

float

models_fitted

Total number of models successfully evaluated.

Type:

int

search_results

(order, ic_value) pairs for every model tried (including those that failed, recorded with inf).

Type:

list[tuple[tuple, float]]

summary()[source]

Human-readable summary of the search.

Return type:

str

property best_model: object
property best_order: tuple[int, int, int]
property best_seasonal: tuple[int, int, int, int] | None
property best_aic: float
property models_fitted: int
property search_results: list[tuple[tuple, float]]
property info: dict
property timing: dict[str, float] | None
property backend_name: str
property warnings: tuple[str, ...]
summary()[source]

Return a human-readable summary of the search.

Returns:

Multi-line summary.

Return type:

str

pystatistics.timeseries.decompose(x, period, *, type='additive')[source]

Classical time series decomposition.

Matches R’s stats::decompose().

Algorithm

  1. Trend via centered moving average of length period.

  2. De-trend: subtract (additive) or divide (multiplicative).

  3. Seasonal: average de-trended values at each seasonal position, then center so they sum to zero (additive) or average to 1 (multiplicative).

  4. Residual: x - trend - seasonal (additive) or x / (trend * seasonal) (multiplicative).

param x:

Time series (1-D). Length must be >= 2 * period.

type x:

ArrayLike

param period:

Seasonal period (>= 2).

type period:

int

param type:

'additive' or 'multiplicative'.

type type:

str

rtype:

DecompositionSolution

raises ValidationError:

On invalid inputs.

Parameters:
Return type:

DecompositionSolution

pystatistics.timeseries.stl(x, period, *, seasonal_window='periodic', seasonal_degree=0, trend_window=None, trend_degree=1, lowpass_window=None, lowpass_degree=None, seasonal_jump=None, trend_jump=None, lowpass_jump=None, robust=False, n_inner=None, n_outer=None)[source]

Seasonal-Trend decomposition using Loess (STL).

Matches R’s stats::stl (Cleveland et al., 1990): identical parameters produce identical seasonal/trend/remainder components up to floating-point noise. Two interface divergences, both deliberate: seasonal_window defaults to "periodic" (R requires it explicitly), and invalid spans raise instead of being silently rounded up as R does.

Parameters:
  • x (ArrayLike) – Time series (1-D, finite). Length must exceed 2 * period.

  • period (int) – Seasonal period (>= 2), e.g. 12 for monthly data.

  • seasonal_window (int, "periodic", or None) – Loess span for cycle-subseries smoothing (odd, >= 3), or "periodic" for an exactly periodic seasonal (equivalent to a span of 10*n + 1 with degree 0, followed by cycle-position averaging). Default "periodic"; None also selects the default, as for every other window parameter. R: s.window.

  • seasonal_degree (int) – Loess degree (0 or 1) for the seasonal smoother. Default 0, matching R. Must be 0 when seasonal_window="periodic".

  • trend_window (int or None) – Loess span for the trend (odd, >= 3). Default nextodd(ceil(1.5*period / (1 - 1.5/seasonal_window))), as in R.

  • trend_degree (int) – Loess degree (0 or 1) for the trend. Default 1, matching R.

  • lowpass_window (int or None) – Loess span of the low-pass filter. Default nextodd(period).

  • lowpass_degree (int or None) – Loess degree of the low-pass filter. Default: trend_degree.

  • seasonal_jump (int or None) – Evaluation strides: each loess is evaluated every jump-th point and linearly interpolated between, exactly as in R. Defaults ceil(window/10) (R’s defaults). Pass 1 to evaluate the loess at every point with no interpolation (R’s own interpolation is a speed shortcut, Cleveland et al. 1990, sec. 3.4; with the default strides the output matches R’s bit-for-bit up to float noise).

  • trend_jump (int or None) – Evaluation strides: each loess is evaluated every jump-th point and linearly interpolated between, exactly as in R. Defaults ceil(window/10) (R’s defaults). Pass 1 to evaluate the loess at every point with no interpolation (R’s own interpolation is a speed shortcut, Cleveland et al. 1990, sec. 3.4; with the default strides the output matches R’s bit-for-bit up to float noise).

  • lowpass_jump (int or None) – Evaluation strides: each loess is evaluated every jump-th point and linearly interpolated between, exactly as in R. Defaults ceil(window/10) (R’s defaults). Pass 1 to evaluate the loess at every point with no interpolation (R’s own interpolation is a speed shortcut, Cleveland et al. 1990, sec. 3.4; with the default strides the output matches R’s bit-for-bit up to float noise).

  • robust (bool) – Enable outer-loop robustness iterations (bisquare weights on the remainder). Changes the n_inner/n_outer defaults to R’s (1, 15) from (2, 0).

  • n_inner (int or None) – Inner-loop passes (>= 1). Default: 1 if robust else 2. R: inner.

  • n_outer (int or None) – Robustness iterations (>= 0). Default: 15 if robust else 0. R: outer.

Returns:

With seasonal + trend + residual == observed exactly. info records the resolved windows/degrees/jumps, the iteration counts, and the final robustness weights.

Return type:

DecompositionSolution

Raises:

ValidationError – On invalid input, spans that are even or < 3, degrees outside {0, 1}, or a series with fewer than two full periods.

class pystatistics.timeseries.DecompositionParams(observed, trend, seasonal, residual, period, type, method)[source]

Bases: object

Immutable parameter payload for a time series decomposition.

Parameters:
observed

Original time series.

Type:

NDArray

trend

Trend component. May contain NaN at edges for classical decomposition.

Type:

NDArray

seasonal

Seasonal component (repeats with the given period).

Type:

NDArray

residual

Remainder after removing trend and seasonal.

Type:

NDArray

period

Seasonal period used.

Type:

int

type

'additive' or 'multiplicative'.

Type:

str

method

'classical' or 'stl'.

Type:

str

observed: ndarray[tuple[Any, ...], dtype[_ScalarT]]
trend: ndarray[tuple[Any, ...], dtype[_ScalarT]]
seasonal: ndarray[tuple[Any, ...], dtype[_ScalarT]]
residual: ndarray[tuple[Any, ...], dtype[_ScalarT]]
period: int
type: str
method: str
class pystatistics.timeseries.DecompositionSolution(_result)[source]

Bases: SolutionReprMixin

Result from time series decomposition.

Wraps a Result [DecompositionParams] envelope; every datum is exposed via a read-only @property so the public attribute surface is unchanged from the previous flat dataclass.

Parameters:

_result (Result[DecompositionParams])

observed

Original time series.

Type:

NDArray

trend

Trend component. May contain NaN at edges for classical decomposition.

Type:

NDArray

seasonal

Seasonal component (repeats with the given period).

Type:

NDArray

residual

Remainder after removing trend and seasonal.

Type:

NDArray

period

Seasonal period used.

Type:

int

type

'additive' or 'multiplicative'.

Type:

str

method

'classical' or 'stl'.

Type:

str

property observed: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property trend: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property seasonal: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property residual: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property period: int
property type: str
property method: str
property info: dict
property timing: dict[str, float] | None
property backend_name: str
property warnings: tuple[str, ...]
summary()[source]

Return a human-readable summary of the decomposition.

Returns:

Multi-line summary string.

Return type:

str