Invertibility addresses whether a moving average (MA) or autoregressive moving average (ARMA) process can be reexpressed as an infinite-order autoregressive (AR) process.

This property ensures a unique mapping between the process and its autocorrelation function, critical for parameter estimation from observed data.

Concept of Invertibility

For an MA() process:

invertibility allows rewriting it as:

with coefficients . This is possible when the MA characteristic polynomial:

has roots exceeding 1 in modulus ( for MA(1)).

Invertibility resolves nonuniqueness in MA models, where different values yield the same autocorrelation function.

MA(1) Example

Consider . Rewrite as:

Substitute recursively:

Continuing infinitely:

Thus:

Notice that converges if and only if .

And if converges, then is invertible.

For , the series diverges, rendering it non-invertible.

Nonuniqueness Issue

For MA(1), . Replacing with yields the same .

Example:

and both give , but only (root ) is invertible (), while (root ) is not ().

General MA() and ARMA(,)

Invertibility requires all roots of the MA characteristic equation to have modulus greater than 1.

For ARMA(,), both stationarity (AR roots > 1 in modulus) and invertibility (MA roots > 1 in modulus) are required for a well-defined model.

Implications

Invertibility ensures a unique, physically sensible MA representation, restricting attention to models where past observations can predict the noise term without infinite amplification.

Python Example

import numpy as np
import matplotlib.pyplot as plt
 
# Simulate MA(1) processes with invertible and non-invertible theta
np.random.seed(42)
n = 100
e_t = np.random.normal(0, 1, n + 1)  # White noise
theta_inv = 0.5   # Invertible: |theta| < 1
theta_non = 2.0   # Non-invertible: |theta| > 1
 
# Generate MA(1) series
Y_inv = np.zeros(n)
Y_non = np.zeros(n)
for t in range(n):
    Y_inv[t] = e_t[t + 1] - theta_inv * e_t[t]
    Y_non[t] = e_t[t + 1] - theta_non * e_t[t]
 
# Attempt to recover e_t (invert the process)
e_rec_inv = np.zeros(n)
e_rec_non = np.zeros(n)
for t in range(1, n):
    e_rec_inv[t] = Y_inv[t] + theta_inv * e_rec_inv[t - 1]
    e_rec_non[t] = Y_non[t] + theta_non * e_rec_non[t - 1]
 
# Plot original vs recovered noise
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(e_t[1:], label='True $e_t$', alpha=0.5)
plt.plot(e_rec_inv, label='Recovered $e_t$ (Invertible, $\\theta=0.5$)', linestyle='--')
plt.title('Invertible MA(1)')
plt.legend()
plt.subplot(2, 1, 2)
plt.plot(e_t[1:], label='True $e_t$', alpha=0.5)
plt.plot(e_rec_non, label='Recovered $e_t$ (Non-invertible, $\\theta=2.0$)', linestyle='--')
plt.title('Non-invertible MA(1)')
plt.legend()
plt.tight_layout()
plt.show()
 
# Check autocorrelation
from statsmodels.tsa.stattools import acf
acf_inv = acf(Y_inv, nlags=5, fft=False)
acf_non = acf(Y_non, nlags=5, fft=False)
print(f"ACF (Invertible, theta={theta_inv}): {acf_inv[:3]}")
print(f"ACF (Non-invertible, theta={theta_non}): {acf_non[:3]}")

Explanation

This code simulates two MA(1) processes: one with (invertible) and one with (non-invertible). It attempts to recover the white noise using the infinite AR representation. For , the recovered closely matches the true noise, while for , it diverges due to non-invertibility. The autocorrelation functions (ACF) are computed, showing both processes have the same , illustrating nonuniqueness without invertibility constraints.

Output plots demonstrate the stability of the invertible case versus the explosive behavior of the non-invertible case.