ARIMAX#

class cultivars.univariate.box_jenkins.ARIMAX(endog, *, order, exog, trend='c')[source]#

ARIMA(p, d, q) with exogenous regressors, no seasonal block.

A regression with ARIMA errors,

\[(1 - L)^d\,(y_t - x_t'\beta) = \frac{\theta(L)}{\phi(L)}\,\varepsilon_t,\]

so the regressors enter the observation intercept and the ARIMA structure describes what they leave behind. When d is non-zero the regressors are differenced alongside endog, which is what makes the specification a levels relationship with an integrated error: \(y_t = x_t'\beta + u_t\) with \(u_t \sim\) ARIMA(p, d, q) is estimated on \(\Delta^d y_t = \Delta^d x_t'\beta + \Delta^d u_t\), and a cointegrating relation comes back correctly – y = 2 x1 - x2 + I(1) error recovers about 2.00 and -1.00 at d = 1. The converse is the trap: a relationship between \(\Delta y_t\) and the level of a stationary driver, \(\Delta y_t = 2 x_t + e_t\), is not this model, and fitting it at d = 1 regresses \(\Delta y_t\) on \(\Delta x_t\) and returns about 1.0. That is a property of the specification rather than of the estimator; supply the cumulated driver, or model the differences at d = 0.

exog is required and an empty block is rejected. That is the whole point of the name: an ARIMAX with no regressors is an ARIMA, and silently accepting one would let a call site claim a covariate model it does not have.

Parameters:
  • endog (ArrayLike) – The endogenous series.

  • order (tuple[int, int, int]) – (p, d, q).

  • exog (ArrayLike) – Exogenous regressors, shape (nobs,) or (nobs, k), with at least one column.

  • trend (str) – Deterministic specification.

Raises:

See also

  • SARIMAX – the same model with a seasonal block.

  • ARIMA – without regressors.

  • cointegration – whether a levels relationship with an integrated error is the right reading of the data before it is imposed.

Example

A cointegrating relation in levels with an I(1) error, and the misspecified reading of a differenced series against a stationary driver:

>>> import numpy as np
>>> rng = np.random.default_rng(0)
>>> X = rng.standard_normal((400, 2))
>>> levels = X @ [2.0, -1.0] + np.cumsum(rng.standard_normal(400))
>>> beta = ARIMAX(levels, order=(0, 1, 0), exog=X, trend="n").fit().beta
>>> bool(np.allclose(beta, [2.0, -1.0], atol=0.15))
True
>>> x = rng.standard_normal(400)
>>> y = np.cumsum(2.0 * x + rng.standard_normal(400))
>>> round(float(ARIMAX(y, order=(1, 1, 0), exog=x).fit().beta[1]), 1)
1.0
>>> round(float(ARIMAX(y, order=(1, 1, 0), exog=np.cumsum(x)).fit().beta[1]), 1)
2.0

Attributes#

endog

The validated endogenous series.

exog

The validated exogenous regressors, or None.

order

The non-seasonal order (p, d, q).

seasonal_order

The seasonal order (P, D, Q, s).

trend

The deterministic specification.

Methods#

fit()

Estimate by exact maximum likelihood.