reconnect moved files to git repo

This commit is contained in:
root
2025-08-01 04:33:03 -04:00
commit 5d3c35492d
23190 changed files with 4750716 additions and 0 deletions

View File

@ -0,0 +1,52 @@
"""
Tests for ARMA innovations algorithm wrapper
"""
import numpy as np
import pytest
from numpy.testing import assert_allclose
from statsmodels.tsa.innovations import arma_innovations
from statsmodels.tsa.statespace.sarimax import SARIMAX
@pytest.mark.parametrize("ar_params,ma_params,sigma2", [
(np.array([]), np.array([]), 1),
(np.array([0.]), np.array([0.]), 1),
(np.array([0.9]), np.array([]), 1),
(np.array([]), np.array([0.9]), 1),
(np.array([0.2, -0.4, 0.1, 0.1]), np.array([0.5, 0.1]), 1.123),
(np.array([0.5, 0.1]), np.array([0.2, -0.4, 0.1, 0.1]), 1.123),
])
def test_innovations_algo_filter_kalman_filter(ar_params, ma_params, sigma2):
# Test the innovations algorithm and filter against the Kalman filter
# for exact likelihood evaluation of an ARMA process
np.random.seed(42)
endog = np.random.normal(size=100)
# Innovations algorithm approach
llf = arma_innovations.arma_loglike(endog, ar_params, ma_params, sigma2)
llf_obs = arma_innovations.arma_loglikeobs(endog, ar_params, ma_params,
sigma2)
score = arma_innovations.arma_score(endog, ar_params, ma_params, sigma2)
score_obs = arma_innovations.arma_scoreobs(endog, ar_params, ma_params,
sigma2)
# Kalman filter apparoach
mod = SARIMAX(endog, order=(len(ar_params), 0, len(ma_params)))
params = np.r_[ar_params, ma_params, sigma2]
# Test that the two approaches are the same
assert_allclose(llf, mod.loglike(params))
assert_allclose(llf_obs, mod.loglikeobs(params))
# Note: the tolerance on the two gets worse as more nobs are added
assert_allclose(score, mod.score(params), atol=1e-5)
assert_allclose(score_obs, mod.score_obs(params), atol=1e-5)
@pytest.mark.parametrize("ar_params", ([1.9, -0.8], [1.0], [2.0, -1.0]))
def test_innovations_nonstationary(ar_params):
np.random.seed(42)
endog = np.random.normal(size=100)
with pytest.raises(ValueError, match="The model's autoregressive"):
arma_innovations.arma_innovations(endog, ar_params=ar_params)

View File

@ -0,0 +1,357 @@
"""
Tests for fast version of ARMA innovations algorithm
"""
import numpy as np
import pytest
from numpy.testing import assert_equal, assert_allclose
from statsmodels.tsa.arima_process import arma_acovf
from statsmodels.tsa.innovations import _arma_innovations, arma_innovations
from statsmodels.tsa.statespace.sarimax import SARIMAX
def test_brockwell_davis_ex533():
# See Brockwell and Davis (2009) - Time Series Theory and Methods
# Example 5.3.3: ARMA(1, 1) process, p.g. 177
nobs = 10
ar_params = np.array([0.2])
ma_params = np.array([0.4])
sigma2 = 8.92
p = len(ar_params)
q = len(ma_params)
m = max(p, q)
ar = np.r_[1, -ar_params]
ma = np.r_[1, ma_params]
# First, get the autocovariance of the process
arma_process_acovf = arma_acovf(ar, ma, nobs=nobs, sigma2=sigma2)
unconditional_variance = (
sigma2 * (1 + 2 * ar_params[0] * ma_params[0] + ma_params[0]**2) /
(1 - ar_params[0]**2))
assert_allclose(arma_process_acovf[0], unconditional_variance)
# Next, get the autocovariance of the transformed process
# Note: as required by {{prefix}}arma_transformed_acovf, we first divide
# through by sigma^2
arma_process_acovf /= sigma2
unconditional_variance /= sigma2
transformed_acovf = _arma_innovations.darma_transformed_acovf_fast(
ar, ma, arma_process_acovf)
acovf, acovf2 = (np.array(arr) for arr in transformed_acovf)
# `acovf` is an m^2 x m^2 matrix, where m = max(p, q)
# but it is only valid for the autocovariances of the first m observations
# (this means in particular that the block `acovf[m:, m:]` should *not* be
# used)
# `acovf2` then contains the (time invariant) autocovariance terms for
# the observations m + 1, ..., nobs - since the autocovariance is the same
# for these terms, to save space we do not construct the autocovariance
# matrix as we did for the first m terms. Thus `acovf2[0]` is the variance,
# `acovf2[1]` is the first autocovariance, etc.
# Test the autocovariance function for observations m + 1, ..., nobs
# (it is time invariant here)
assert_equal(acovf2.shape, (nobs - m,))
assert_allclose(acovf2[0], 1 + ma_params[0]**2)
assert_allclose(acovf2[1], ma_params[0])
assert_allclose(acovf2[2:], 0)
# Test the autocovariance function for observations 1, ..., m
# (it is time varying here)
assert_equal(acovf.shape, (m * 2, m * 2))
# (we need to check `acovf[:m * 2, :m]`, i.e. `acovf[:2, :1])`
ix = np.diag_indices_from(acovf)
ix_lower = (ix[0][:-1] + 1, ix[1][:-1])
# acovf[ix] is the diagonal, and we want to check the first m
# elements of the diagonal
assert_allclose(acovf[ix][:m], unconditional_variance)
# acovf[ix_lower] is the first lower off-diagonal
assert_allclose(acovf[ix_lower][:m], ma_params[0])
# Now, check that we compute the moving average coefficients and the
# associated variances correctly
out = _arma_innovations.darma_innovations_algo_fast(
nobs, ar_params, ma_params, acovf, acovf2)
theta = np.array(out[0])
v = np.array(out[1])
# Test v (see eq. 5.3.13)
desired_v = np.zeros(nobs)
desired_v[0] = unconditional_variance
for i in range(1, nobs):
desired_v[i] = 1 + (1 - 1 / desired_v[i - 1]) * ma_params[0]**2
assert_allclose(v, desired_v)
# Test theta (see eq. 5.3.13)
# Note that they will have shape (nobs, m + 1) here, not (nobs, nobs - 1)
# as in the original (non-fast) version
assert_equal(theta.shape, (nobs, m + 1))
desired_theta = np.zeros(nobs)
for i in range(1, nobs):
desired_theta[i] = ma_params[0] / desired_v[i - 1]
assert_allclose(theta[:, 0], desired_theta)
assert_allclose(theta[:, 1:], 0)
# Test against Table 5.3.1
endog = np.array([
-1.1, 0.514, 0.116, -0.845, 0.872, -0.467, -0.977, -1.699, -1.228,
-1.093])
u = _arma_innovations.darma_innovations_filter(endog, ar_params, ma_params,
theta)
# Note: Table 5.3.1 has \hat X_n+1 = -0.5340 for n = 1, but this seems to
# be a typo, since equation 5.3.12 gives the form of the prediction
# equation as \hat X_n+1 = \phi X_n + \theta_n1 (X_n - \hat X_n)
# Then for n = 1 we have:
# \hat X_n+1 = 0.2 (-1.1) + (0.2909) (-1.1 - 0) = -0.5399
# And for n = 2 if we use what we have computed, then we get:
# \hat X_n+1 = 0.2 (0.514) + (0.3833) (0.514 - (-0.54)) = 0.5068
# as desired, whereas if we used the book's number for n=1 we would get:
# \hat X_n+1 = 0.2 (0.514) + (0.3833) (0.514 - (-0.534)) = 0.5045
# which is not what Table 5.3.1 shows.
desired_hat = np.array([
0, -0.540, 0.5068, -0.1321, -0.4539, 0.7046, -0.5620, -0.3614,
-0.8748, -0.3869])
desired_u = endog - desired_hat
assert_allclose(u, desired_u, atol=1e-4)
def test_brockwell_davis_ex534():
# See Brockwell and Davis (2009) - Time Series Theory and Methods
# Example 5.3.4: ARMA(1, 1) process, p.g. 178
nobs = 10
ar_params = np.array([1, -0.24])
ma_params = np.array([0.4, 0.2, 0.1])
sigma2 = 1
p = len(ar_params)
q = len(ma_params)
m = max(p, q)
ar = np.r_[1, -ar_params]
ma = np.r_[1, ma_params]
# First, get the autocovariance of the process
arma_process_acovf = arma_acovf(ar, ma, nobs=nobs, sigma2=sigma2)
assert_allclose(arma_process_acovf[:3],
[7.17133, 6.44139, 5.06027], atol=1e-5)
# Next, get the autocovariance of the transformed process
transformed_acovf = _arma_innovations.darma_transformed_acovf_fast(
ar, ma, arma_process_acovf)
acovf, acovf2 = (np.array(arr) for arr in transformed_acovf)
# See test_brockwell_davis_ex533 for details on acovf vs acovf2
# Test acovf
assert_equal(acovf.shape, (m * 2, m * 2))
ix = np.diag_indices_from(acovf)
ix_lower1 = (ix[0][:-1] + 1, ix[1][:-1])
ix_lower2 = (ix[0][:-2] + 2, ix[1][:-2])
ix_lower3 = (ix[0][:-3] + 3, ix[1][:-3])
ix_lower4 = (ix[0][:-4] + 4, ix[1][:-4])
assert_allclose(acovf[ix][:m], 7.17133, atol=1e-5)
desired = [6.44139, 6.44139, 0.816]
assert_allclose(acovf[ix_lower1][:m], desired, atol=1e-5)
assert_allclose(acovf[ix_lower2][0], 5.06027, atol=1e-5)
assert_allclose(acovf[ix_lower2][1:m], 0.34, atol=1e-5)
assert_allclose(acovf[ix_lower3][:m], 0.1, atol=1e-5)
assert_allclose(acovf[ix_lower4][:m], 0, atol=1e-5)
# Test acovf2
assert_equal(acovf2.shape, (nobs - m,))
assert_allclose(acovf2[:4], [1.21, 0.5, 0.24, 0.1])
assert_allclose(acovf2[4:], 0)
# Test innovations algorithm output
out = _arma_innovations.darma_innovations_algo_fast(
nobs, ar_params, ma_params, acovf, acovf2)
theta = np.array(out[0])
v = np.array(out[1])
# Test v (see Table 5.3.2)
desired_v = [7.1713, 1.3856, 1.0057, 1.0019, 1.0016, 1.0005, 1.0000,
1.0000, 1.0000, 1.0000]
assert_allclose(v, desired_v, atol=1e-4)
# Test theta (see Table 5.3.2)
assert_equal(theta.shape, (nobs, m + 1))
desired_theta = np.array([
[0, 0.8982, 1.3685, 0.4008, 0.3998, 0.3992, 0.4000, 0.4000, 0.4000,
0.4000],
[0, 0, 0.7056, 0.1806, 0.2020, 0.1995, 0.1997, 0.2000, 0.2000, 0.2000],
[0, 0, 0, 0.0139, 0.0722, 0.0994, 0.0998, 0.0998, 0.0999, 0.1]]).T
assert_allclose(theta[:, :m], desired_theta, atol=1e-4)
assert_allclose(theta[:, m:], 0)
# Test innovations filter output
endog = np.array([1.704, 0.527, 1.041, 0.942, 0.555, -1.002, -0.585, 0.010,
-0.638, 0.525])
u = _arma_innovations.darma_innovations_filter(endog, ar_params, ma_params,
theta)
desired_hat = np.array([
0, 1.5305, -0.1710, 1.2428, 0.7443, 0.3138, -1.7293, -0.1688,
0.3193, -0.8731])
desired_u = endog - desired_hat
assert_allclose(u, desired_u, atol=1e-4)
@pytest.mark.parametrize("ar_params,ma_params,sigma2", [
(np.array([]), np.array([]), 1),
(np.array([0.]), np.array([0.]), 1),
(np.array([0.9]), np.array([]), 1),
(np.array([]), np.array([0.9]), 1),
(np.array([0.2, -0.4, 0.1, 0.1]), np.array([0.5, 0.1]), 1.123),
(np.array([0.5, 0.1]), np.array([0.2, -0.4, 0.1, 0.1]), 1.123),
])
def test_innovations_algo_filter_kalman_filter(ar_params, ma_params, sigma2):
# Test the innovations algorithm and filter against the Kalman filter
# for exact likelihood evaluation of an ARMA process
ar = np.r_[1, -ar_params]
ma = np.r_[1, ma_params]
endog = np.random.normal(size=10)
nobs = len(endog)
# Innovations algorithm approach
arma_process_acovf = arma_acovf(ar, ma, nobs=nobs, sigma2=sigma2)
transformed_acov = _arma_innovations.darma_transformed_acovf_fast(
ar, ma, arma_process_acovf / sigma2)
acovf, acovf2 = (np.array(mv) for mv in transformed_acov)
theta, r = _arma_innovations.darma_innovations_algo_fast(
nobs, ar_params, ma_params, acovf, acovf2)
u = _arma_innovations.darma_innovations_filter(endog, ar_params, ma_params,
theta)
v = np.array(r) * sigma2
u = np.array(u)
llf_obs = -0.5 * u**2 / v - 0.5 * np.log(2 * np.pi * v)
# Kalman filter apparoach
mod = SARIMAX(endog, order=(len(ar_params), 0, len(ma_params)))
res = mod.filter(np.r_[ar_params, ma_params, sigma2])
# Test that the two approaches are identical
assert_allclose(u, res.forecasts_error[0])
# assert_allclose(theta[1:, 0], res.filter_results.kalman_gain[0, 0, :-1])
assert_allclose(llf_obs, res.llf_obs)
# Get llf_obs directly
llf_obs2 = _arma_innovations.darma_loglikeobs_fast(
endog, ar_params, ma_params, sigma2)
assert_allclose(llf_obs2, res.llf_obs)
@pytest.mark.parametrize("ar_params,ma_params,sigma2", [
(np.array([]), np.array([]), 1),
(np.array([0.]), np.array([0.]), 1),
(np.array([0.9]), np.array([]), 1),
(np.array([]), np.array([0.9]), 1),
(np.array([0.2, -0.4, 0.1, 0.1]), np.array([0.5, 0.1]), 1.123),
(np.array([0.5, 0.1]), np.array([0.2, -0.4, 0.1, 0.1]), 1.123),
])
def test_innovations_algo_direct_filter_kalman_filter(ar_params, ma_params,
sigma2):
# Test the innovations algorithm and filter against the Kalman filter
# for exact likelihood evaluation of an ARMA process, using the direct
# function.
endog = np.random.normal(size=10)
# Innovations algorithm approach
u, r = arma_innovations.arma_innovations(endog, ar_params, ma_params,
sigma2)
v = np.array(r) * sigma2
u = np.array(u)
llf_obs = -0.5 * u**2 / v - 0.5 * np.log(2 * np.pi * v)
# Kalman filter apparoach
mod = SARIMAX(endog, order=(len(ar_params), 0, len(ma_params)))
res = mod.filter(np.r_[ar_params, ma_params, sigma2])
# Test that the two approaches are identical
assert_allclose(u, res.forecasts_error[0])
# assert_allclose(theta[1:, 0], res.filter_results.kalman_gain[0, 0, :-1])
assert_allclose(llf_obs, res.llf_obs)
# Get llf_obs directly
llf_obs2 = _arma_innovations.darma_loglikeobs_fast(
endog, ar_params, ma_params, sigma2)
assert_allclose(llf_obs2, res.llf_obs)
@pytest.mark.parametrize("ar_params,diff,ma_params,sigma2", [
(np.array([]), 1, np.array([]), 1),
(np.array([0.]), 1, np.array([0.]), 1),
(np.array([0.9]), 1, np.array([]), 1),
(np.array([]), 1, np.array([0.9]), 1),
(np.array([0.2, -0.4, 0.1, 0.1]), 1, np.array([0.5, 0.1]), 1.123),
(np.array([0.5, 0.1]), 1, np.array([0.2, -0.4, 0.1, 0.1]), 1.123),
(np.array([0.5, 0.1]), 2, np.array([0.2, -0.4, 0.1, 0.1]), 1.123),
])
def test_integrated_process(ar_params, diff, ma_params, sigma2):
# Test loglikelihood computation when model has integration
nobs = 100
endog = np.cumsum(np.random.normal(size=nobs))
# Innovations algorithm approach
llf_obs = arma_innovations.arma_loglikeobs(
np.diff(endog, diff), ar_params, ma_params, sigma2)
# Kalman filter apparoach
mod = SARIMAX(endog, order=(len(ar_params), diff, len(ma_params)),
simple_differencing=True)
res = mod.filter(np.r_[ar_params, ma_params, sigma2])
# Test that the two approaches are identical
assert_allclose(llf_obs, res.llf_obs)
@pytest.mark.parametrize("ar_params,ma_params,sigma2", [
(np.array([]), np.array([]), 1),
(np.array([0.]), np.array([0.]), 1),
(np.array([0.9]), np.array([]), 1),
(np.array([]), np.array([0.9]), 1),
(np.array([0.2, -0.4, 0.1, 0.1]), np.array([0.5, 0.1]), 1.123),
(np.array([0.5, 0.1]), np.array([0.2, -0.4, 0.1, 0.1]), 1.123),
])
def test_regression_with_arma_errors(ar_params, ma_params, sigma2):
# Test loglikelihood computation when model has regressors
nobs = 100
eps = np.random.normal(nobs)
exog = np.c_[np.ones(nobs), np.random.uniform(size=nobs)]
beta = [5, -0.2]
endog = np.dot(exog, beta) + eps
# Innovations algorithm approach
beta_hat = np.squeeze(np.linalg.pinv(exog).dot(endog))
demeaned = endog - np.dot(exog, beta_hat)
llf_obs = arma_innovations.arma_loglikeobs(
demeaned, ar_params, ma_params, sigma2)
# Kalman filter approach
# (this works since we impose here that the regression coefficients are
# beta_hat - in practice, the MLE estimates will not necessarily match
# the OLS estimates beta_hat)
mod = SARIMAX(endog, exog=exog, order=(len(ar_params), 0, len(ma_params)))
res = mod.filter(np.r_[beta_hat, ar_params, ma_params, sigma2])
# Test that the two approaches are identical
assert_allclose(llf_obs, res.llf_obs)