Repository: statsmodels/statsmodels

Issue:
Interface for tsa.acf and tsa.graphics.plot_acf differs
The interface for the function `tsa.acf` uses the parameter `nlags` while the function `tsa.graphics.tsa.plot_acf` uses the parameter `lags`. 


Discussion:
I don't remember the details or reason.
Based on the docstring and implementation of the `lags` option in `plot_acf`, those two are different, lags is more general than nlags, and allows for an arbitrary array of lags, while acf nlags specifies a fixed number of consecutive lags.


Resolving patch:
diff --git a/statsmodels/tsa/stattools.py b/statsmodels/tsa/stattools.py
--- a/statsmodels/tsa/stattools.py
+++ b/statsmodels/tsa/stattools.py
@@ -2,6 +2,7 @@
 Statistical tools for time series analysis
 """
 from statsmodels.compat.python import iteritems, lrange, lzip
+from statsmodels.compat.pandas import deprecate_kwarg
 from statsmodels.compat.numpy import lstsq
 from statsmodels.compat.scipy import _next_regular
 
@@ -1493,7 +1494,8 @@ def has_missing(data):
     return np.isnan(np.sum(data))
 
 
-def kpss(x, regression='c', lags=None, store=False):
+@deprecate_kwarg('lags', 'nlags')
+def kpss(x, regression='c', nlags=None, store=False):
     """
     Kwiatkowski-Phillips-Schmidt-Shin test for stationarity.
 
@@ -1508,7 +1510,7 @@ def kpss(x, regression='c', lags=None, store=False):
         Indicates the null hypothesis for the KPSS test
         * 'c' : The data is stationary around a constant (default)
         * 'ct' : The data is stationary around a trend
-    lags : {None, str, int}, optional
+    nlags : {None, str, int}, optional
         Indicates the number of lags to be used. If None (default), lags is
         calculated using the legacy method. If 'auto', lags is calculated
         using the data-dependent method of Hobijn et al. (1998). See also
@@ -1591,8 +1593,8 @@ def kpss(x, regression='c', lags=None, store=False):
         resids = x - x.mean()
         crit = [0.347, 0.463, 0.574, 0.739]
 
-    if lags is None:
-        lags = 'legacy'
+    if nlags is None:
+        nlags = 'legacy'
         msg = 'The behavior of using lags=None will change in the next ' \
               'release. Currently lags=None is the same as ' \
               'lags=\'legacy\', and so a sample-size lag length is used. ' \
@@ -1601,24 +1603,24 @@ def kpss(x, regression='c', lags=None, store=False):
               'selection method. To silence this warning, either use ' \
               '\'auto\' or \'legacy\''
         warn(msg, FutureWarning)
-    if lags == 'legacy':
-        lags = int(np.ceil(12. * np.power(nobs / 100., 1 / 4.)))
-        lags = min(lags, nobs - 1)
-    elif lags == 'auto':
+    if nlags == 'legacy':
+        nlags = int(np.ceil(12. * np.power(nobs / 100., 1 / 4.)))
+        nlags = min(nlags, nobs - 1)
+    elif nlags == 'auto':
         # autolag method of Hobijn et al. (1998)
-        lags = _kpss_autolag(resids, nobs)
-        lags = min(lags, nobs - 1)
+        nlags = _kpss_autolag(resids, nobs)
+        nlags = min(nlags, nobs - 1)
     else:
-        lags = int(lags)
+        nlags = int(nlags)
 
-    if lags >= nobs:
+    if nlags >= nobs:
         raise ValueError("lags ({}) must be < number of observations ({})"
-                         .format(lags, nobs))
+                         .format(nlags, nobs))
 
     pvals = [0.10, 0.05, 0.025, 0.01]
 
     eta = np.sum(resids.cumsum()**2) / (nobs**2)  # eq. 11, p. 165
-    s_hat = _sigma_est_kpss(resids, nobs, lags)
+    s_hat = _sigma_est_kpss(resids, nobs, nlags)
 
     kpss_stat = eta / s_hat
     p_value = np.interp(kpss_stat, crit, pvals)
@@ -1632,7 +1634,7 @@ def kpss(x, regression='c', lags=None, store=False):
 
     if store:
         rstore = ResultsStore()
-        rstore.lags = lags
+        rstore.lags = nlags
         rstore.nobs = nobs
 
         stationary_type = "level" if hypo == 'c' else "trend"
@@ -1641,7 +1643,7 @@ def kpss(x, regression='c', lags=None, store=False):
 
         return kpss_stat, p_value, crit_dict, rstore
     else:
-        return kpss_stat, p_value, lags, crit_dict
+        return kpss_stat, p_value, nlags, crit_dict
 
 
 def _sigma_est_kpss(resids, nobs, lags):


Test patch:
diff --git a/statsmodels/tsa/tests/test_stattools.py b/statsmodels/tsa/tests/test_stattools.py
--- a/statsmodels/tsa/tests/test_stattools.py
+++ b/statsmodels/tsa/tests/test_stattools.py
@@ -476,7 +476,7 @@ class TestKPSS(SetupKPSS):
     def test_fail_nonvector_input(self, reset_randomstate):
         # should be fine
         with pytest.warns(InterpolationWarning):
-            kpss(self.x, lags='legacy')
+            kpss(self.x, nlags='legacy')
 
         x = np.random.rand(20, 2)
         assert_raises(ValueError, kpss, x)
@@ -484,13 +484,13 @@ def test_fail_nonvector_input(self, reset_randomstate):
     def test_fail_unclear_hypothesis(self):
         # these should be fine,
         with pytest.warns(InterpolationWarning):
-            kpss(self.x, 'c', lags='legacy')
+            kpss(self.x, 'c', nlags='legacy')
         with pytest.warns(InterpolationWarning):
-            kpss(self.x, 'C', lags='legacy')
+            kpss(self.x, 'C', nlags='legacy')
         with pytest.warns(InterpolationWarning):
-            kpss(self.x, 'ct', lags='legacy')
+            kpss(self.x, 'ct', nlags='legacy')
         with pytest.warns(InterpolationWarning):
-            kpss(self.x, 'CT', lags='legacy')
+            kpss(self.x, 'CT', nlags='legacy')
 
         assert_raises(ValueError, kpss, self.x, "unclear hypothesis",
                       lags='legacy')
@@ -525,22 +525,22 @@ def test_store(self):
     def test_lags(self):
         # real GDP from macrodata data set
         with pytest.warns(InterpolationWarning):
-            res = kpss(self.x, 'c', lags='auto')
+            res = kpss(self.x, 'c', nlags='auto')
         assert_equal(res[2], 9)
         # real interest rates from macrodata data set
-        res = kpss(sunspots.load(True).data['SUNACTIVITY'], 'c', lags='auto')
+        res = kpss(sunspots.load(True).data['SUNACTIVITY'], 'c', nlags='auto')
         assert_equal(res[2], 7)
         # volumes from nile data set
         with pytest.warns(InterpolationWarning):
-            res = kpss(nile.load(True).data['volume'], 'c', lags='auto')
+            res = kpss(nile.load(True).data['volume'], 'c', nlags='auto')
         assert_equal(res[2], 5)
         # log-coinsurance from randhie data set
         with pytest.warns(InterpolationWarning):
-            res = kpss(randhie.load(True).data['lncoins'], 'ct', lags='auto')
+            res = kpss(randhie.load(True).data['lncoins'], 'ct', nlags='auto')
         assert_equal(res[2], 75)
         # in-vehicle time from modechoice data set
         with pytest.warns(InterpolationWarning):
-            res = kpss(modechoice.load(True).data['invt'], 'ct', lags='auto')
+            res = kpss(modechoice.load(True).data['invt'], 'ct', nlags='auto')
         assert_equal(res[2], 18)
 
     def test_kpss_fails_on_nobs_check(self):
@@ -551,10 +551,11 @@ def test_kpss_fails_on_nobs_check(self):
         msg = (r"lags \({}\) must be < number of observations \({}\)"
                .format(nobs, nobs))
         with pytest.raises(ValueError, match=msg):
-            kpss(self.x, 'c', lags=nobs)
+            kpss(self.x, 'c', nlags=nobs)
 
     def test_kpss_autolags_does_not_assign_lags_equal_to_nobs(self):
-        # Test that if *autolags* exceeds number of observations, we set suitable lags
+        # Test that if *autolags* exceeds number of observations, we set
+        # suitable lags
         # GH5925
         data_which_breaks_autolag = np.array(
             [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0,
@@ -572,18 +573,18 @@ def test_kpss_autolags_does_not_assign_lags_equal_to_nobs(self):
              1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1,
              1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0]).astype(float)
 
-        kpss(data_which_breaks_autolag, lags="auto")
+        kpss(data_which_breaks_autolag, nlags="auto")
 
     def test_legacy_lags(self):
         # Test legacy lags are the same
         with pytest.warns(InterpolationWarning):
-            res = kpss(self.x, 'c', lags='legacy')
+            res = kpss(self.x, 'c', nlags='legacy')
         assert_equal(res[2], 15)
 
     def test_unknown_lags(self):
         # Test legacy lags are the same
         with pytest.raises(ValueError):
-            kpss(self.x, 'c', lags='unknown')
+            kpss(self.x, 'c', nlags='unknown')
 
     def test_deprecation(self):
         with pytest.warns(FutureWarning):