cultivars.univariate.fractional_integration#

ARFIMA(p, d, q) – fractionally integrated ARMA with long memory.

The model

\[\phi(L)\,(1 - L)^d\,(y_t - \mu) = \theta(L)\,\varepsilon_t, \qquad (1 - L)^d = \sum_{k=0}^{\infty} \frac{\Gamma(k - d)}{\Gamma(-d)\,\Gamma(k + 1)}\,L^k,\]

in which the fractional operator interpolates between a stationary ARMA (\(d = 0\)) and a unit-root process (\(d = 1\)). For \(0 < d < 0.5\) the process is stationary with autocorrelations decaying as \(k^{2d-1}\) and a spectrum behaving as \(\omega^{-2d}\) at the origin – hyperbolic rather than geometric memory, which no finite ARMA reproduces without a near-unit root. The likelihood is

\[\log L(\mu, d, \phi, \theta, \sigma^2) = \log L_{\text{ARMA}}\bigl(w_t(\mu, d);\, \phi, \theta, \sigma^2\bigr), \qquad w_t = (1 - L)^d (y_t - \mu),\]

with the inner term the exact Kalman likelihood of the short-memory block on the differenced series; \(\mu\), \(d\) and the block are estimated jointly, the filter re-applied at every draw because \(w_t\) is itself a function of \(d\). The approximation relative to Sowell’s exact likelihood is the truncation of the filter, not the ARMA step.

Two commitments shape the surface. First, stationarity is not the short-memory test. It needs \(|d| < 0.5\) and a stable autoregressive block, so ARFIMAResult overrides the inherited property rather than reporting a process as stationary because its ARMA block happens to be well behaved; mean reversion, \(d < 1\), is the weaker and separately useful condition and has its own property. Second, the estimator confines \(d\) to \((-0.499, 0.499)\) through a scaled tanh reparameterization, so the stationary-ARMA machinery is always valid on the differenced series and an estimate at the boundary is a sign the data want integer differencing rather than a long-memory fit. The cost of that choice is that the stationarity verdict cannot fail on \(d\); the summary prints the range so the boundary is visible.

Layout. ARFIMA validates order through validate_order_tuple, trend through validate_choice against Trend, and truncation through validate_order on the _FractionalIntegrationModel base in _internals; _build_objective starts \(d\) at local_whittle_d from _core (shared with long_memory) and the ARMA block at its conditional estimate, and hands a _FractionalIntegrationObjective to _maximize_likelihood. The objective’s differenced applies fractional_difference with the weights of fractional_difference_weights, and its state_space builds the short-memory block through _LinearGaussianStateSpace._from_arma, the same form box_jenkins uses. The packed _FractionalIntegrationFit is assembled by ARFIMAResult._from_fit(). Semiparametric estimates of \(d\) that need no short-memory specification are gph() and local_whittle(); long memory in the variance is FIGARCH.

References

Granger, C. W. J., & Joyeux, R. (1980). An introduction to long-memory time series models and fractional differencing. Journal of Time Series Analysis, 1(1), 15-29.

Hosking, J. R. M. (1981). Fractional differencing. Biometrika, 68(1), 165-176.

Sowell, F. (1992). Maximum likelihood estimation of stationary univariate fractionally integrated time series models. Journal of Econometrics, 53(1-3), 165-188.

Beran, J. (1994). Statistics for Long-Memory Processes. Chapman & Hall.

Example

A long-memory series is not a short-memory one with a large root:

>>> import numpy as np
>>> from cultivars.engine._core._transforms import _fractional_difference_weights
>>> from cultivars.univariate.box_jenkins import ARMA
>>> rng = np.random.default_rng(0)
>>> n = 600
>>> w = _fractional_difference_weights(-0.4, n)
>>> y = np.convolve(rng.standard_normal(n + 300), w)[300 : 300 + n]
>>> long = ARFIMA(y, order=(0, 0)).fit()
>>> short = ARMA(y, order=(2, 0)).fit()
>>> bool(abs(long.d - 0.4) < 0.1), long.is_stationary
(True, True)
>>> bool(long.information_criteria.bic < short.information_criteria.bic)
True

Classes#

ARFIMA

Fractionally integrated ARMA specification.

ARFIMAResult

A fitted fractionally integrated ARMA.