def test_innovations_algo_rtol(): ma = np.array([-0.9, 0.5]) acovf = np.array([1 + (ma ** 2).sum(), ma[0] + ma[1] * ma[0], ma[1]]) theta, sigma2 = innovations_algo(acovf, nobs=500) theta_2, sigma2_2 = innovations_algo(acovf, nobs=500, rtol=1e-8) assert_allclose(theta, theta_2) assert_allclose(sigma2, sigma2_2)
def test_innovations_algo_brockwell_davis(): ma = -0.9 acovf = np.array([1 + ma ** 2, ma]) theta, sigma2 = innovations_algo(acovf, nobs=4) exp_theta = np.array([[0], [-.4972], [-.6606], [-.7404]]) assert_allclose(theta, exp_theta, rtol=1e-4) assert_allclose(sigma2, [1.81, 1.3625, 1.2155, 1.1436], rtol=1e-4) theta, sigma2 = innovations_algo(acovf, nobs=500) assert_allclose(theta[-1, 0], ma) assert_allclose(sigma2[-1], 1.0)
def test_innovations_algo_filter_kalman_filter(reset_randomstate): # Test the innovations algorithm and filter against the Kalman filter # for exact likelihood evaluation of an ARMA process ar_params = np.array([0.5]) ma_params = np.array([0.2]) # TODO could generalize to sigma2 != 1, if desired, after #5324 is merged # and there is a sigma2 argument to arma_acovf # (but maybe this is not really necessary for the point of this test) sigma2 = 1 endog = np.random.normal(size=10) # Innovations algorithm approach acovf = arma_acovf(np.r_[1, -ar_params], np.r_[1, ma_params], nobs=len(endog)) theta, v = innovations_algo(acovf) u = innovations_filter(endog, theta) llf_obs = -0.5 * u ** 2 / (sigma2 * 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 atol = 1e-6 if PLATFORM_WIN else 0.0 assert_allclose(u, res.forecasts_error[0], rtol=1e-6, atol=atol) assert_allclose(theta[1:, 0], res.filter_results.kalman_gain[0, 0, :-1], atol=atol) assert_allclose(llf_obs, res.llf_obs, atol=atol)
def test_innovations_algo_filter_kalman_filter(reset_randomstate): # Test the innovations algorithm and filter against the Kalman filter # for exact likelihood evaluation of an ARMA process ar_params = np.array([0.5]) ma_params = np.array([0.2]) # TODO could generalize to sigma2 != 1, if desired, after #5324 is merged # and there is a sigma2 argument to arma_acovf # (but maybe this is not really necessary for the point of this test) sigma2 = 1 endog = np.random.normal(size=10) # Innovations algorithm approach acovf = arma_acovf(np.r_[1, -ar_params], np.r_[1, ma_params], nobs=len(endog)) theta, v = innovations_algo(acovf) u = innovations_filter(endog, theta) llf_obs = -0.5 * u**2 / (sigma2 * 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 atol = 1e-6 if PLATFORM_WIN else 0.0 assert_allclose(u, res.forecasts_error[0], atol=atol) assert_allclose(theta[1:, 0], res.filter_results.kalman_gain[0, 0, :-1], atol=atol) assert_allclose(llf_obs, res.llf_obs, atol=atol)
def test_innovations_errors(): ma = -0.9 acovf = np.array([1 + ma ** 2, ma]) with pytest.raises(TypeError): innovations_algo(acovf, nobs=2.2) with pytest.raises(ValueError): innovations_algo(acovf, nobs=-1) with pytest.raises(ValueError): innovations_algo(np.empty((2, 2))) with pytest.raises(TypeError): innovations_algo(acovf, rtol='none')
def test_innovations_errors(): ma = -0.9 acovf = np.array([1 + ma ** 2, ma]) with pytest.raises(ValueError): innovations_algo(acovf, nobs=2.2) with pytest.raises(ValueError): innovations_algo(acovf, nobs=-1) with pytest.raises(ValueError): innovations_algo(np.empty((2, 2))) with pytest.raises(ValueError): innovations_algo(acovf, rtol='none')
def test_innovations_filter_errors(): ma = -0.9 acovf = np.array([1 + ma ** 2, ma]) theta, _ = innovations_algo(acovf, nobs=4) with pytest.raises(ValueError): innovations_filter(np.empty((2, 2)), theta) with pytest.raises(ValueError): innovations_filter(np.empty(4), theta[:-1]) with pytest.raises(ValueError): innovations_filter(pd.DataFrame(np.empty((1, 4))), theta)
def test_innovations_filter_pandas(reset_randomstate): ma = np.array([-0.9, 0.5]) acovf = np.array([1 + (ma**2).sum(), ma[0] + ma[1] * ma[0], ma[1]]) theta, _ = innovations_algo(acovf, nobs=10) endog = np.random.randn(10) endog_pd = pd.Series(endog, index=pd.date_range('2000-01-01', periods=10)) resid = innovations_filter(endog, theta) resid_pd = innovations_filter(endog_pd, theta) assert_allclose(resid, resid_pd.values) assert_index_equal(endog_pd.index, resid_pd.index)
def test_innovations_filter_pandas(reset_randomstate): ma = np.array([-0.9, 0.5]) acovf = np.array([1 + (ma ** 2).sum(), ma[0] + ma[1] * ma[0], ma[1]]) theta, _ = innovations_algo(acovf, nobs=10) endog = np.random.randn(10) endog_pd = pd.Series(endog, index=pd.date_range('2000-01-01', periods=10)) resid = innovations_filter(endog, theta) resid_pd = innovations_filter(endog_pd, theta) assert_allclose(resid, resid_pd.values) assert_index_equal(endog_pd.index, resid_pd.index)
def test_innovations_filter_brockwell_davis(reset_randomstate): ma = -0.9 acovf = np.array([1 + ma ** 2, ma]) theta, _ = innovations_algo(acovf, nobs=4) e = np.random.randn(5) endog = e[1:] + ma * e[:-1] resid = innovations_filter(endog, theta) expected = [endog[0]] for i in range(1, 4): expected.append(endog[i] - theta[i, 0] * expected[-1]) expected = np.array(expected) assert_allclose(resid, expected)
def innovations(endog, ma_order=0, demean=True): """ Estimate MA parameters using innovations algorithm. Parameters ---------- endog : array_like or SARIMAXSpecification Input time series array, assumed to be stationary. ma_order : int, optional Maximum moving average order. Default is 0. demean : bool, optional Whether to estimate and remove the mean from the process prior to fitting the moving average coefficients. Default is True. Returns ------- parameters : list of SARIMAXParams objects List elements correspond to estimates at different `ma_order`. For example, parameters[0] is an `SARIMAXParams` instance corresponding to `ma_order=0`. other_results : Bunch Includes one component, `spec`, containing the `SARIMAXSpecification` instance corresponding to the input arguments. Notes ----- The primary reference is [1]_, section 5.1.3. This procedure assumes that the series is stationary. References ---------- .. [1] Brockwell, Peter J., and Richard A. Davis. 2016. Introduction to Time Series and Forecasting. Springer. """ spec = max_spec = SARIMAXSpecification(endog, ma_order=ma_order) endog = max_spec.endog if demean: endog = endog - endog.mean() if not max_spec.is_ma_consecutive: raise ValueError('Innovations estimation unavailable for models with' ' seasonal or otherwise non-consecutive MA orders.') sample_acovf = acovf(endog, fft=True) theta, v = innovations_algo(sample_acovf, nobs=max_spec.ma_order + 1) ma_params = [theta[i, :i] for i in range(1, max_spec.ma_order + 1)] sigma2 = v out = [] for i in range(max_spec.ma_order + 1): spec = SARIMAXSpecification(ma_order=i) p = SARIMAXParams(spec=spec) if i == 0: p.params = sigma2[i] else: p.params = np.r_[ma_params[i - 1], sigma2[i]] out.append(p) # Construct other results other_results = Bunch({ 'spec': spec, }) return out, other_results