# -*- coding: utf-8 -*- # stationarity tests from pmdarima.arima.stationarity import ADFTest, PPTest, KPSSTest from pmdarima.arima.utils import ndiffs from pmdarima.utils.array import diff from pmdarima.datasets import load_austres from sklearn.utils import check_random_state from numpy.testing import assert_array_almost_equal, assert_almost_equal, \ assert_array_equal import numpy as np import pytest # for testing rand of len 400 for m==365 random_state = check_random_state(42) austres = load_austres() def test_ndiffs_stationary(): # show that for a stationary vector, ndiffs returns 0 x = np.ones(10) assert ndiffs(x, alpha=0.05, test='kpss', max_d=2) == 0 assert ndiffs(x, alpha=0.05, test='pp', max_d=2) == 0 assert ndiffs(x, alpha=0.05, test='adf', max_d=2) == 0 @pytest.mark.parametrize("cls", (KPSSTest, PPTest, ADFTest)) def test_embedding(cls): x = np.arange(5) expected = np.array([ [1, 2, 3, 4], [0, 1, 2, 3] ]) assert_array_almost_equal(cls._embed(x, 2), expected) y = np.array([1, -1, 0, 2, -1, -2, 3]) assert_array_almost_equal(cls._embed(y, 1), np.array([ [1, -1, 0, 2, -1, -2, 3] ])) assert_array_almost_equal(cls._embed(y, 2).T, np.array([ [-1, 1], [0, -1], [2, 0], [-1, 2], [-2, -1], [3, -2] ])) assert_array_almost_equal(cls._embed(y, 3).T, np.array([ [0, -1, 1], [2, 0, -1], [-1, 2, 0], [-2, -1, 2], [3, -2, -1] ])) # Where K close to y dim assert_array_almost_equal(cls._embed(y, 6).T, np.array([ [-2, -1, 2, 0, -1, 1], [3, -2, -1, 2, 0, -1] ])) # Where k == y dim assert_array_almost_equal(cls._embed(y, 7).T, np.array([ [3, -2, -1, 2, 0, -1, 1] ])) # Assert we fail when k > dim with pytest.raises(ValueError): cls._embed(y, 8) def test_adf_ols(): # Test the _ols function of the ADF test x = np.array([1, -1, 0, 2, -1, -2, 3]) k = 2 y = diff(x) assert_array_equal(y, [-2, 1, 2, -3, -1, 5]) z = ADFTest._embed(y, k).T res = ADFTest._ols(x, y, z, k) # Assert on the params of the OLS. The comparisons are those obtained # from the R function. expected = np.array([1.0522, -3.1825, -0.1609, 1.4690]) assert np.allclose(res.params, expected, rtol=0.001) # Now assert on the standard error stat = ADFTest._ols_std_error(res) assert np.allclose(stat, -100.2895) # derived from R code def test_adf_p_value(): # Assert on the ADF test's p-value p_val, do_diff = \ ADFTest(alpha=0.05).should_diff(np.array([1, -1, 0, 2, -1, -2, 3])) assert np.isclose(p_val, 0.01) assert not do_diff @pytest.mark.parametrize('null', ('level', 'trend')) def test_kpss(null): test = KPSSTest(alpha=0.05, null=null, lshort=True) pval, do_diff = test.should_diff(austres) assert do_diff # show it is significant assert_almost_equal(pval, 0.01) # Test on the data provided in issue #67 x = np.array([1, -1, 0, 2, -1, -2, 3]) pval2, do_diff2 = test.should_diff(x) # We expect Trend to be significant, but NOT Level if null == 'level': assert not do_diff2 assert_almost_equal(pval2, 0.1) else: assert do_diff2 assert_almost_equal(pval2, 0.01) # test the ndiffs with the KPSS test assert ndiffs(austres, test='kpss', max_d=5, null=null) == 2 def test_non_default_kpss(): test = KPSSTest(alpha=0.05, null='trend', lshort=False) pval, do_diff = test.should_diff(austres) assert do_diff # show it is significant assert np.allclose(pval, 0.01, atol=0.005) # test the ndiffs with the KPSS test assert ndiffs(austres, test='kpss', max_d=2) == 2 def test_kpss_corner(): test = KPSSTest(alpha=0.05, null='something-else', lshort=True) with pytest.raises(ValueError): test.should_diff(austres) def test_pp(): test = PPTest(alpha=0.05, lshort=True) pval, do_diff = test.should_diff(austres) assert do_diff # Result from R code: 0.9786066 # > pp.test(austres, lshort=TRUE)$p.value assert_almost_equal(pval, 0.9786066, decimal=5) # test n diffs assert ndiffs(austres, test='pp', max_d=2) == 1 # If we use lshort is FALSE, it will be different test = PPTest(alpha=0.05, lshort=False) pval, do_diff = test.should_diff(austres) assert do_diff # Result from R code: 0.9514589 # > pp.test(austres, lshort=FALSE)$p.value assert_almost_equal(pval, 0.9514589, decimal=5) assert ndiffs(austres, test='pp', max_d=2, lshort=False) == 1 def test_adf(): # Test where k = 1 test = ADFTest(alpha=0.05, k=1) pval, do_diff = test.should_diff(austres) # R's value: 0.8488036 # > adf.test(austres, k=1, alternative='stationary')$p.value assert np.isclose(pval, 0.8488036) assert do_diff # Test for k = 2. R's value: 0.7060733 # > adf.test(austres, k=2, alternative='stationary')$p.value test = ADFTest(alpha=0.05, k=2) pval, do_diff = test.should_diff(austres) assert np.isclose(pval, 0.7060733) assert do_diff # Test for k is None. R's value: 0.3493465 # > adf.test(austres, alternative='stationary')$p.value test = ADFTest(alpha=0.05, k=None) pval, do_diff = test.should_diff(austres) assert np.isclose(pval, 0.3493465, rtol=0.0001) assert do_diff def test_adf_corner(): with pytest.raises(ValueError): ADFTest(alpha=0.05, k=-1) # show we can fit with k is None test = ADFTest(alpha=0.05, k=None) test.should_diff(austres) def test_ndiffs_corner_cases(): with pytest.raises(ValueError): ndiffs(austres, max_d=0) def test_base_cases(): classes = (ADFTest, KPSSTest, PPTest) for cls in classes: instance = cls() # Also show we get a warning with the deprecated func with pytest.warns(DeprecationWarning): p_val, is_stationary = instance.is_stationary(None) # results of base-case assert np.isnan(p_val) assert not is_stationary