From 5ad66039ff4413d5e2a16c97bdfa4063d257465d Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 4 Feb 2026 10:59:19 +0000 Subject: [PATCH] DOC: Fix documentation for ADF and related tests --- arch/tests/unitroot/test_unitroot.py | 19 ++++++++++++-- arch/unitroot/unitroot.py | 39 +++++++++++++++++----------- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/arch/tests/unitroot/test_unitroot.py b/arch/tests/unitroot/test_unitroot.py index 8a3aef83a8..ae5976a9a3 100644 --- a/arch/tests/unitroot/test_unitroot.py +++ b/arch/tests/unitroot/test_unitroot.py @@ -432,8 +432,22 @@ def test_representations(trend): def test_unknown_method(): rnd = np.random.RandomState(12345) y = np.cumsum(rnd.standard_normal(250)) - with pytest.raises(ValueError, match=r"Unknown method"): + with pytest.raises(ValueError, match=r"method must be one"): assert np.isfinite(ADF(y, method="unknown").stat) + with pytest.raises(TypeError, match=r"method must be a string"): + assert np.isfinite(ADF(y, method=1).stat) + + +@pytest.mark.parametrize("method", ["aic", "AIC", "BIC", "bic", "t-stat", "tstat", "t"]) +def test_acceptable_method(method): + rnd = np.random.RandomState(12345) + y = np.cumsum(rnd.standard_normal(250)) + used_method = ADF(y, method=method)._method + if method in ("t-stat", "t", "tstat"): + expected_method = "t-stat" + else: + expected_method = method.lower() + assert used_method == expected_method def test_auto_low_memory(): @@ -593,12 +607,13 @@ def test_zivot_andrews(series_name): # Test results from package urca.ur.za (1.13-0) y = ZIVOT_ANDREWS_DATA[series_name].dropna() result = series[series_name] + kwargs = {"method": result.method} if result.method is not None else {} za = ZivotAndrews( y, lags=result.lags, trend=result.trend, max_lags=result.max_lags, - method=result.method, + **kwargs, ) assert_almost_equal(za.stat, result.stat, decimal=3) assert_almost_equal(za.pvalue, result.pvalue, decimal=3) diff --git a/arch/unitroot/unitroot.py b/arch/unitroot/unitroot.py index 00ac5fc101..da305ed47e 100644 --- a/arch/unitroot/unitroot.py +++ b/arch/unitroot/unitroot.py @@ -187,8 +187,6 @@ def _select_best_ic( large_tstat = abs(tstat) >= stop lag = int(squeeze(argwhere(large_tstat)).max()) icbest = float(tstat[lag]) - else: - raise ValueError("Unknown method") return icbest, lag @@ -548,6 +546,16 @@ def _compute_if_needed(self) -> None: self._check_specification() self._compute_statistic() + def _clean_method(self, method: str) -> Literal["aic", "bic", "t-stat"]: + if not isinstance(method, str): + raise TypeError("method must be a string") + method = method.lower() + if method in ("t", "tstat", "t-stat"): + return "t-stat" + elif method not in ("aic", "bic"): + raise ValueError("method must be one of 'aic', 'bic' or 't-stat'") + return method + @property def null_hypothesis(self) -> str: """The null hypothesis""" @@ -683,11 +691,11 @@ class ADF(UnitRootTest, metaclass=AbstractDocStringInheritor): max_lags : int, optional The maximum number of lags to use when selecting lag length - method : {"AIC", "BIC", "t-stat"}, optional + method : {"aic", "bic", "t-stat"}, optional The method to use when selecting the lag length - - "AIC" - Select the minimum of the Akaike IC - - "BIC" - Select the minimum of the Schwarz/Bayesian IC + - "aic" - Select the minimum of the Akaike IC + - "bic" - Select the minimum of the Schwarz/Bayesian IC - "t-stat" - Select the minimum of the Schwarz/Bayesian IC low_memory : bool @@ -763,7 +771,7 @@ def __init__( valid_trends = ("n", "c", "ct", "ctt") super().__init__(y, lags, trend, valid_trends) self._max_lags = max_lags - self._method = method + self._method = self._clean_method(method) self._test_name = "Augmented Dickey-Fuller" self._regression = None self._low_memory = bool(low_memory) @@ -798,7 +806,7 @@ def _compute_statistic(self) -> None: y, trend, lags = self._y, self._trend, self._lags resols = _estimate_df_regression(y, cast("UnitRootTrend", trend), lags) self._regression = resols - (self._stat, *_) = (stat, *_) = resols.tvalues + self._stat, *_ = (stat, *_) = resols.tvalues self._nobs = int(resols.nobs) self._pvalue = mackinnonp( stat, @@ -851,11 +859,11 @@ class DFGLS(UnitRootTest, metaclass=AbstractDocStringInheritor): The maximum number of lags to use when selecting lag length. When using automatic lag length selection, the lag is selected using OLS detrending rather than GLS detrending ([pq]_). - method : {"AIC", "BIC", "t-stat"}, optional + method : {"aic", "bic", "t-stat"}, optional The method to use when selecting the lag length - - "AIC" - Select the minimum of the Akaike IC - - "BIC" - Select the minimum of the Schwarz/Bayesian IC + - "aic" - Select the minimum of the Akaike IC + - "bic" - Select the minimum of the Schwarz/Bayesian IC - "t-stat" - Select the minimum of the Schwarz/Bayesian IC Notes @@ -912,7 +920,7 @@ def __init__( valid_trends = ("c", "ct") super().__init__(y, lags, trend, valid_trends) self._max_lags = max_lags - self._method = method + self._method = self._clean_method(method) self._regression = None self._low_memory = low_memory if low_memory is None: @@ -1403,11 +1411,11 @@ class ZivotAndrews(UnitRootTest, metaclass=AbstractDocStringInheritor): calculation in range [0, 0.333] (default=0.15) max_lags : int, optional The maximum number of lags to use when selecting lag length - method : {"AIC", "BIC", "t-stat"}, optional + method : {"aic", "bic", "t-stat"}, optional The method to use when selecting the lag length - - "AIC" - Select the minimum of the Akaike IC - - "BIC" - Select the minimum of the Schwarz/Bayesian IC + - "aic" - Select the minimum of the Akaike IC + - "bic" - Select the minimum of the Schwarz/Bayesian IC - "t-stat" - Select the minimum of the Schwarz/Bayesian IC Notes @@ -1457,7 +1465,8 @@ def __init__( raise ValueError("trim must be a float in range [0, 1/3]") self._trim = trim self._max_lags = max_lags - self._method = method + self._method = self._clean_method(method) + self._test_name = "Zivot-Andrews" self._all_stats = full(self._y.shape[0], nan) self._null_hypothesis = (