Repository: statsmodels/statsmodels

Issue:
Document nan-handling policies for acf()
#### Describe the bug

tsa.stattools.acf() currently documents the `missing` kwarg as taking the following values for nan-handling: [‘none’, ‘raise’, ‘conservative’, ‘drop’].  It isn't too difficult to see what "none" does (it returns nan if there's a nan in the time series) and to guess that "raise" raises an exception if there's a nan, but it would be useful to document better what "drop" and "conservative" do.  I guess "drop" just "compresses" out the nans from the time series first and "conservative" drops out the terms in the summation that are nan, but I'm not even sure of that?  Also, especially for "conservative", it would be nice if there was some reference to the literature as to how to handle such data (e.g., when centering the data, would it make sense to center only the data that will participate in the summation for a given lag?).

#### Code Sample, a copy-pastable example if possible

N/A

#### Expected Output

N/A

#### Output of ``import statsmodels.api as sm; sm.show_versions()``

0.11.1


Discussion:

Resolving patch:
diff --git a/statsmodels/tsa/stattools.py b/statsmodels/tsa/stattools.py
--- a/statsmodels/tsa/stattools.py
+++ b/statsmodels/tsa/stattools.py
@@ -24,17 +24,17 @@
 from statsmodels.tsa.arima_model import ARMA
 from statsmodels.tsa.tsatools import lagmat, lagmat2ds, add_trend
 
-__all__ = ['acovf', 'acf', 'pacf', 'pacf_yw', 'pacf_ols', 'ccovf', 'ccf',
-           'periodogram', 'q_stat', 'coint', 'arma_order_select_ic',
-           'adfuller', 'kpss', 'bds', 'pacf_burg', 'innovations_algo',
-           'innovations_filter', 'levinson_durbin_pacf', 'levinson_durbin',
-           'zivot_andrews']
+__all__ = ["acovf", "acf", "pacf", "pacf_yw", "pacf_ols", "ccovf", "ccf",
+           "periodogram", "q_stat", "coint", "arma_order_select_ic",
+           "adfuller", "kpss", "bds", "pacf_burg", "innovations_algo",
+           "innovations_filter", "levinson_durbin_pacf", "levinson_durbin",
+           "zivot_andrews"]
 
 SQRTEPS = np.sqrt(np.finfo(np.double).eps)
 
 
-#NOTE: now in two places to avoid circular import
-#TODO: I like the bunch pattern for this too.
+# NOTE: now in two places to avoid circular import
+# TODO: I like the bunch pattern for this too.
 class ResultsStore(object):
     def __str__(self):
         return self._str  # pylint: disable=E1101
@@ -58,7 +58,7 @@ def _autolag(mod, endog, exog, startlag, maxlag, method, modargs=(),
         The first zero-indexed column to hold a lag.  See Notes.
     maxlag : int
         The highest lag order for lag length selection.
-    method : {'aic', 'bic', 't-stat'}
+    method : {"aic", "bic", "t-stat"}
         aic - Akaike Information Criterion
         bic - Bayes Information Criterion
         t-stat - Based on last lag
@@ -85,8 +85,8 @@ def _autolag(mod, endog, exog, startlag, maxlag, method, modargs=(),
     assumed to be in contiguous columns from low to high lag length with
     the highest lag in the last column.
     """
-    #TODO: can tcol be replaced by maxlag + 2?
-    #TODO: This could be changed to laggedRHS and exog keyword arguments if
+    # TODO: can tcol be replaced by maxlag + 2?
+    # TODO: This could be changed to laggedRHS and exog keyword arguments if
     #    this will be more general.
 
     results = {}
@@ -100,7 +100,7 @@ def _autolag(mod, endog, exog, startlag, maxlag, method, modargs=(),
     elif method == "bic":
         icbest, bestlag = min((v.bic, k) for k, v in iteritems(results))
     elif method == "t-stat":
-        #stop = stats.norm.ppf(.95)
+        # stop = stats.norm.ppf(.95)
         stop = 1.6448536269514722
         for lag in range(startlag + maxlag, startlag - 1, -1):
             icbest = np.abs(results[lag].tvalues[-1])
@@ -117,15 +117,15 @@ def _autolag(mod, endog, exog, startlag, maxlag, method, modargs=(),
         return icbest, bestlag, results
 
 
-#this needs to be converted to a class like HetGoldfeldQuandt,
+# this needs to be converted to a class like HetGoldfeldQuandt,
 # 3 different returns are a mess
 # See:
-#Ng and Perron(2001), Lag length selection and the construction of unit root
-#tests with good size and power, Econometrica, Vol 69 (6) pp 1519-1554
-#TODO: include drift keyword, only valid with regression == "c"
+# Ng and Perron(2001), Lag length selection and the construction of unit root
+# tests with good size and power, Econometrica, Vol 69 (6) pp 1519-1554
+# TODO: include drift keyword, only valid with regression == "c"
 # just changes the distribution of the test statistic to a t distribution
-#TODO: autolag is untested
-def adfuller(x, maxlag=None, regression="c", autolag='AIC',
+# TODO: autolag is untested
+def adfuller(x, maxlag=None, regression="c", autolag="AIC",
              store=False, regresults=False):
     """
     Augmented Dickey-Fuller unit root test.
@@ -139,21 +139,21 @@ def adfuller(x, maxlag=None, regression="c", autolag='AIC',
         The data series to test.
     maxlag : int
         Maximum lag which is included in test, default 12*(nobs/100)^{1/4}.
-    regression : {'c','ct','ctt','nc'}
+    regression : {"c","ct","ctt","nc"}
         Constant and trend order to include in regression.
 
-        * 'c' : constant only (default).
-        * 'ct' : constant and trend.
-        * 'ctt' : constant, and linear and quadratic trend.
-        * 'nc' : no constant, no trend.
+        * "c" : constant only (default).
+        * "ct" : constant and trend.
+        * "ctt" : constant, and linear and quadratic trend.
+        * "nc" : no constant, no trend.
 
-    autolag : {'AIC', 'BIC', 't-stat', None}
+    autolag : {"AIC", "BIC", "t-stat", None}
         Method to use when automatically determining the lag.
 
         * if None, then maxlag lags are used.
-        * if 'AIC' (default) or 'BIC', then the number of lags is chosen
+        * if "AIC" (default) or "BIC", then the number of lags is chosen
           to minimize the corresponding information criterion.
-        * 't-stat' based choice of maxlag.  Starts with maxlag and drops a
+        * "t-stat" based choice of maxlag.  Starts with maxlag and drops a
           lag until the t-statistic on the last lag length is significant
           using a 5%-sized test.
     store : bool
@@ -167,7 +167,7 @@ def adfuller(x, maxlag=None, regression="c", autolag='AIC',
     adf : float
         The test statistic.
     pvalue : float
-        MacKinnon's approximate p-value based on MacKinnon (1994, 2010).
+        MacKinnon"s approximate p-value based on MacKinnon (1994, 2010).
     usedlag : int
         The number of lags used.
     nobs : int
@@ -204,7 +204,7 @@ def adfuller(x, maxlag=None, regression="c", autolag='AIC',
         unit-root and cointegration tests.  `Journal of Business and Economic
         Statistics` 12, 167-76.
 
-    .. [4] MacKinnon, J.G. 2010. "Critical Values for Cointegration Tests."  Queen's
+    .. [4] MacKinnon, J.G. 2010. "Critical Values for Cointegration Tests."  Queen"s
         University, Dept of Economics, Working Papers.  Available at
         http://ideas.repec.org/p/qed/wpaper/1227.html
 
@@ -212,39 +212,39 @@ def adfuller(x, maxlag=None, regression="c", autolag='AIC',
     --------
     See example notebook
     """
-    x = array_like(x, 'x')
-    maxlag = int_like(maxlag, 'maxlag', optional=True)
-    regression = string_like(regression, 'regression',
-                             options=('c', 'ct', 'ctt', 'nc'))
-    autolag = string_like(autolag, 'autolag', optional=True,
-                          options=('aic', 'bic', 't-stat'))
-    store = bool_like(store, 'store')
-    regresults = bool_like(regresults, 'regresults')
+    x = array_like(x, "x")
+    maxlag = int_like(maxlag, "maxlag", optional=True)
+    regression = string_like(regression, "regression",
+                             options=("c", "ct", "ctt", "nc"))
+    autolag = string_like(autolag, "autolag", optional=True,
+                          options=("aic", "bic", "t-stat"))
+    store = bool_like(store, "store")
+    regresults = bool_like(regresults, "regresults")
 
     if regresults:
         store = True
 
-    trenddict = {None: 'nc', 0: 'c', 1: 'ct', 2: 'ctt'}
+    trenddict = {None: "nc", 0: "c", 1: "ct", 2: "ctt"}
     if regression is None or isinstance(regression, int):
         regression = trenddict[regression]
     regression = regression.lower()
     nobs = x.shape[0]
 
-    ntrend = len(regression) if regression != 'nc' else 0
+    ntrend = len(regression) if regression != "nc" else 0
     if maxlag is None:
         # from Greene referencing Schwert 1989
         maxlag = int(np.ceil(12. * np.power(nobs / 100., 1 / 4.)))
         # -1 for the diff
         maxlag = min(nobs // 2 - ntrend - 1, maxlag)
         if maxlag < 0:
-            raise ValueError('sample size is too short to use selected '
-                             'regression component')
+            raise ValueError("sample size is too short to use selected "
+                             "regression component")
     elif maxlag > nobs // 2 - ntrend - 1:
-        raise ValueError('maxlag must be less than (nobs/2 - 1 - ntrend) '
-                         'where n trend is the number of included '
-                         'deterministic regressors')
+        raise ValueError("maxlag must be less than (nobs/2 - 1 - ntrend) "
+                         "where n trend is the number of included "
+                         "deterministic regressors")
     xdiff = np.diff(x)
-    xdall = lagmat(xdiff[:, None], maxlag, trim='both', original='in')
+    xdall = lagmat(xdiff[:, None], maxlag, trim="both", original="in")
     nobs = xdall.shape[0]
 
     xdall[:, 0] = x[-nobs - 1:-1]  # replace 0 xdiff with level of x
@@ -253,7 +253,7 @@ def adfuller(x, maxlag=None, regression="c", autolag='AIC',
     if store:
         resstore = ResultsStore()
     if autolag:
-        if regression != 'nc':
+        if regression != "nc":
             fullRHS = add_trend(xdall, regression, prepend=True)
         else:
             fullRHS = xdall
@@ -275,7 +275,7 @@ def adfuller(x, maxlag=None, regression="c", autolag='AIC',
         bestlag -= startlag  # convert to lag not column index
 
         # rerun ols with best autolag
-        xdall = lagmat(xdiff[:, None], bestlag, trim='both', original='in')
+        xdall = lagmat(xdiff[:, None], bestlag, trim="both", original="in")
         nobs = xdall.shape[0]
         xdall[:, 0] = x[-nobs - 1:-1]  # replace 0 xdiff with level of x
         xdshort = xdiff[-nobs:]
@@ -283,14 +283,14 @@ def adfuller(x, maxlag=None, regression="c", autolag='AIC',
     else:
         usedlag = maxlag
         icbest = None
-    if regression != 'nc':
+    if regression != "nc":
         resols = OLS(xdshort, add_trend(xdall[:, :usedlag + 1],
-                     regression)).fit()
+                                        regression)).fit()
     else:
         resols = OLS(xdshort, xdall[:, :usedlag + 1]).fit()
 
     adfstat = resols.tvalues[0]
-#    adfstat = (resols.params[0]-1.0)/resols.bse[0]
+    #    adfstat = (resols.params[0]-1.0)/resols.bse[0]
     # the "asymptotically correct" z statistic is obtained as
     # nobs/(1-np.sum(resols.params[1:-(trendorder+1)])) (resols.params[0] - 1)
     # I think this is the statistic that is used for series that are integrated
@@ -299,8 +299,8 @@ def adfuller(x, maxlag=None, regression="c", autolag='AIC',
     # Get approx p-value and critical values
     pvalue = mackinnonp(adfstat, regression=regression, N=1)
     critvalues = mackinnoncrit(N=1, regression=regression, nobs=nobs)
-    critvalues = {"1%" : critvalues[0], "5%" : critvalues[1],
-                  "10%" : critvalues[2]}
+    critvalues = {"1%": critvalues[0], "5%": critvalues[1],
+                  "10%": critvalues[2]}
     if store:
         resstore.resols = resols
         resstore.maxlag = maxlag
@@ -312,7 +312,7 @@ def adfuller(x, maxlag=None, regression="c", autolag='AIC',
                        "unit root")
         resstore.HA = "The coefficient on the lagged level < 1 - stationary"
         resstore.icbest = icbest
-        resstore._str = 'Augmented Dickey-Fuller Test Results'
+        resstore._str = "Augmented Dickey-Fuller Test Results"
         return adfstat, pvalue, critvalues, resstore
     else:
         if not autolag:
@@ -321,7 +321,7 @@ def adfuller(x, maxlag=None, regression="c", autolag='AIC',
             return adfstat, pvalue, usedlag, nobs, critvalues, icbest
 
 
-def acovf(x, unbiased=False, demean=True, fft=None, missing='none', nlag=None):
+def acovf(x, unbiased=False, demean=True, fft=None, missing="none", nlag=None):
     """
     Estimate autocovariances.
 
@@ -329,17 +329,21 @@ def acovf(x, unbiased=False, demean=True, fft=None, missing='none', nlag=None):
     ----------
     x : array_like
         Time series data. Must be 1d.
-    unbiased : bool
+    unbiased : bool, default False
         If True, then denominators is n-k, otherwise n.
-    demean : bool
+    demean : bool, default True
         If True, then subtract the mean x from each element of x.
-    fft : bool
+    fft : bool, default None
         If True, use FFT convolution.  This method should be preferred
         for long time series.
-    missing : str
-        A string in ['none', 'raise', 'conservative', 'drop'] specifying how
-        the NaNs are to be treated.
-    nlag : {int, None}
+    missing : str, default "none"
+        A string in ["none", "raise", "conservative", "drop"] specifying how
+        the NaNs are to be treated. "none" performs no checks. "raise" raises
+        an exception if NaN values are found. "drop" removes the missing
+        observations and then estimates the autocovariances treating the
+        non-missing as contiguous. "conservative" replaces missing with
+        zeros.
+    nlag : {int, None}, default None
         Limit the number of autocovariances returned.  Size of returned
         array is nlag + 1.  Setting nlag when fft is False uses a simple,
         direct estimator of the autocovariances that only computes the first
@@ -357,46 +361,44 @@ def acovf(x, unbiased=False, demean=True, fft=None, missing='none', nlag=None):
            and amplitude modulation. Sankhya: The Indian Journal of
            Statistics, Series A, pp.383-392.
     """
-    unbiased = bool_like(unbiased, 'unbiased')
-    demean = bool_like(demean, 'demean')
-    fft = bool_like(fft, 'fft', optional=True)
-    missing = string_like(missing, 'missing',
-                          options=('none', 'raise', 'conservative', 'drop'))
-    nlag = int_like(nlag, 'nlag', optional=True)
+    unbiased = bool_like(unbiased, "unbiased")
+    demean = bool_like(demean, "demean")
+    fft = bool_like(fft, "fft", optional=True)
+    missing = string_like(missing, "missing",
+                          options=("none", "raise", "conservative", "drop"))
+    nlag = int_like(nlag, "nlag", optional=True)
 
     if fft is None:
         import warnings
-        msg = 'fft=True will become the default in a future version of ' \
-              'statsmodels. To suppress this warning, explicitly set ' \
-              'fft=False.'
+        msg = "fft=True will become the default in a future version of " \
+              "statsmodels. To suppress this warning, explicitly set " \
+              "fft=False."
         warnings.warn(msg, FutureWarning)
         fft = False
 
-    x = array_like(x, 'x', ndim=1)
+    x = array_like(x, "x", ndim=1)
 
     missing = missing.lower()
-    if missing not in ['none', 'raise', 'conservative', 'drop']:
-        raise ValueError("missing option %s not understood" % missing)
-    if missing == 'none':
+    if missing == "none":
         deal_with_masked = False
     else:
         deal_with_masked = has_missing(x)
     if deal_with_masked:
-        if missing == 'raise':
+        if missing == "raise":
             raise MissingDataError("NaNs were encountered in the data")
         notmask_bool = ~np.isnan(x)  # bool
-        if missing == 'conservative':
+        if missing == "conservative":
             # Must copy for thread safety
             x = x.copy()
             x[~notmask_bool] = 0
-        else:  # 'drop'
+        else:  # "drop"
             x = x[notmask_bool]  # copies non-missing
         notmask_int = notmask_bool.astype(int)  # int
 
     if demean and deal_with_masked:
-        # whether 'drop' or 'conservative':
+        # whether "drop" or "conservative":
         xo = x - x.sum() / notmask_int.sum()
-        if missing == 'conservative':
+        if missing == "conservative":
             xo[~notmask_bool] = 0
     elif demean:
         xo = x - x.mean()
@@ -408,14 +410,14 @@ def acovf(x, unbiased=False, demean=True, fft=None, missing='none', nlag=None):
     if nlag is None:
         lag_len = n - 1
     elif nlag > n - 1:
-        raise ValueError('nlag must be smaller than nobs - 1')
+        raise ValueError("nlag must be smaller than nobs - 1")
 
     if not fft and nlag is not None:
         acov = np.empty(lag_len + 1)
         acov[0] = xo.dot(xo)
         for i in range(lag_len):
             acov[i + 1] = xo[i + 1:].dot(xo[:-(i + 1)])
-        if not deal_with_masked or missing == 'drop':
+        if not deal_with_masked or missing == "drop":
             if unbiased:
                 acov /= (n - np.arange(lag_len + 1))
             else:
@@ -428,19 +430,19 @@ def acovf(x, unbiased=False, demean=True, fft=None, missing='none', nlag=None):
                     divisor[i + 1] = notmask_int[i + 1:].dot(notmask_int[:-(i + 1)])
                 divisor[divisor == 0] = 1
                 acov /= divisor
-            else:  # biased, missing data but npt 'drop'
+            else:  # biased, missing data but npt "drop"
                 acov /= notmask_int.sum()
         return acov
 
-    if unbiased and deal_with_masked and missing == 'conservative':
-        d = np.correlate(notmask_int, notmask_int, 'full')
+    if unbiased and deal_with_masked and missing == "conservative":
+        d = np.correlate(notmask_int, notmask_int, "full")
         d[d == 0] = 1
     elif unbiased:
         xi = np.arange(1, n + 1)
         d = np.hstack((xi, xi[:-1][::-1]))
-    elif deal_with_masked:  # biased and NaNs given and ('drop' or 'conservative')
+    elif deal_with_masked:  # biased and NaNs given and ("drop" or "conservative")
         d = notmask_int.sum() * np.ones(2 * n - 1)
-    else:  # biased and no NaNs or missing=='none'
+    else:  # biased and no NaNs or missing=="none"
         d = n * np.ones(2 * n - 1)
 
     if fft:
@@ -450,7 +452,7 @@ def acovf(x, unbiased=False, demean=True, fft=None, missing='none', nlag=None):
         acov = np.fft.ifft(Frf * np.conjugate(Frf))[:nobs] / d[nobs - 1:]
         acov = acov.real
     else:
-        acov = np.correlate(xo, xo, 'full')[n - 1:] / d[n - 1:]
+        acov = np.correlate(xo, xo, "full")[n - 1:] / d[n - 1:]
 
     if nlag is not None:
         # Copy to allow gc of full array rather than view
@@ -481,12 +483,12 @@ def q_stat(x, nobs, type=None):
     -----
     Designed to be used with acf.
     """
-    x = array_like(x, 'x')
-    nobs = int_like(nobs, 'nobs')
+    x = array_like(x, "x")
+    nobs = int_like(nobs, "nobs")
 
     if type is not None:
         import warnings
-        warnings.warn('The `type` argument is deprecated and has no effect',
+        warnings.warn("The `type` argument is deprecated and has no effect",
                       FutureWarning)
     ret = (nobs * (nobs + 2) *
            np.cumsum((1. / (nobs - np.arange(1, len(x) + 1))) * x ** 2))
@@ -494,11 +496,11 @@ def q_stat(x, nobs, type=None):
     return ret, chi2
 
 
-#NOTE: Changed unbiased to False
-#see for example
+# NOTE: Changed unbiased to False
+# see for example
 # http://www.itl.nist.gov/div898/handbook/eda/section3/autocopl.htm
-def acf(x, unbiased=False, nlags=40, qstat=False, fft=None, alpha=None,
-        missing='none'):
+def acf(x, unbiased=False, nlags=None, qstat=False, fft=None, alpha=None,
+        missing="none"):
     """
     Calculate the autocorrelation function.
 
@@ -506,23 +508,27 @@ def acf(x, unbiased=False, nlags=40, qstat=False, fft=None, alpha=None,
     ----------
     x : array_like
        The time series data.
-    unbiased : bool
+    unbiased : bool, default False
        If True, then denominators for autocovariance are n-k, otherwise n.
-    nlags : int, optional
+    nlags : int, default 40
         Number of lags to return autocorrelation for.
-    qstat : bool, optional
+    qstat : bool, default False
         If True, returns the Ljung-Box q statistic for each autocorrelation
         coefficient.  See q_stat for more information.
-    fft : bool, optional
+    fft : bool, default None
         If True, computes the ACF via FFT.
-    alpha : scalar, optional
+    alpha : scalar, default None
         If a number is given, the confidence intervals for the given level are
         returned. For instance if alpha=.05, 95 % confidence intervals are
         returned where the standard deviation is computed according to
-        Bartlett's formula.
-    missing : str, optional
-        A string in ['none', 'raise', 'conservative', 'drop'] specifying how the NaNs
-        are to be treated.
+        Bartlett"s formula.
+    missing : str, default "none"
+        A string in ["none", "raise", "conservative", "drop"] specifying how
+        the NaNs are to be treated. "none" performs no checks. "raise" raises
+        an exception if NaN values are found. "drop" removes the missing
+        observations and then estimates the autocovariances treating the
+        non-missing as contiguous. "conservative" replaces missing with
+        zeros.
 
     Returns
     -------
@@ -555,25 +561,34 @@ def acf(x, unbiased=False, nlags=40, qstat=False, fft=None, alpha=None,
        and amplitude modulation. Sankhya: The Indian Journal of
        Statistics, Series A, pp.383-392.
     """
-    unbiased = bool_like(unbiased, 'unbiased')
-    nlags = int_like(nlags, 'nlags')
-    qstat = bool_like(qstat, 'qstat')
-    fft = bool_like(fft, 'fft', optional=True)
-    alpha = float_like(alpha, 'alpha', optional=True)
-    missing = string_like(missing, 'missing',
-                          options=('none', 'raise', 'conservative', 'drop'))
+    unbiased = bool_like(unbiased, "unbiased")
+    nlags = int_like(nlags, "nlags", optional=True)
+    qstat = bool_like(qstat, "qstat")
+    fft = bool_like(fft, "fft", optional=True)
+    alpha = float_like(alpha, "alpha", optional=True)
+    missing = string_like(missing, "missing",
+                          options=("none", "raise", "conservative", "drop"))
+    if nlags is None:
+        import warnings
+
+        warnings.warn("The default number of lags is changing from 40 to"
+                      "min(int(10 * np.log10(nobs)), nobs - 1) after 0.12"
+                      "is released. Set the number of lags to an integer to "
+                      " silence this warning.",
+                      FutureWarning)
+        nlags = 40
 
     if fft is None:
         import warnings
         warnings.warn(
-            'fft=True will become the default in a future version of '
-            'statsmodels. To suppress this warning, explicitly set '
-            'fft=False.',
+            "fft=True will become the default in a future version of "
+            "statsmodels. To suppress this warning, explicitly set "
+            "fft=False.",
             FutureWarning
         )
         fft = False
-    x = array_like(x, 'x')
-    nobs = len(x)  # TODO: should this shrink for missing='drop' and NaNs in x?
+    x = array_like(x, "x")
+    nobs = len(x)  # TODO: should this shrink for missing="drop" and NaNs in x?
     avf = acovf(x, unbiased=unbiased, demean=True, fft=fft, missing=missing)
     acf = avf[:nlags + 1] / avf[0]
     if not (qstat or alpha):
@@ -582,7 +597,7 @@ def acf(x, unbiased=False, nlags=40, qstat=False, fft=None, alpha=None,
         varacf = np.ones(nlags + 1) / nobs
         varacf[0] = 0
         varacf[1] = 1. / nobs
-        varacf[2:] *= 1 + 2 * np.cumsum(acf[1:-1]**2)
+        varacf[2:] *= 1 + 2 * np.cumsum(acf[1:-1] ** 2)
         interval = stats.norm.ppf(1 - alpha / 2.) * np.sqrt(varacf)
         confint = np.array(lzip(acf - interval, acf + interval))
         if not qstat:
@@ -595,7 +610,7 @@ def acf(x, unbiased=False, nlags=40, qstat=False, fft=None, alpha=None,
             return acf, qstat, pvalue
 
 
-def pacf_yw(x, nlags=40, method='unbiased'):
+def pacf_yw(x, nlags=None, method="unbiased"):
     """
     Partial autocorrelation estimated with non-recursive yule_walker.
 
@@ -603,9 +618,9 @@ def pacf_yw(x, nlags=40, method='unbiased'):
     ----------
     x : array_like
         The observations of time series for which pacf is calculated.
-    nlags : int, optional
+    nlags : int, default 40
         The largest lag for which pacf is returned.
-    method : {'unbiased', 'mle'}
+    method : {"unbiased", "mle"}, default "unbiased"
         The method for the autocovariance calculations in yule walker.
 
     Returns
@@ -620,16 +635,26 @@ def pacf_yw(x, nlags=40, method='unbiased'):
     statsmodels.tsa.stattools.pacf_ols
         Partial autocorrelation estimation using OLS.
     statsmodels.tsa.stattools.pacf_burg
-        Partial autocorrelation estimation using Burg's method.
+        Partial autocorrelation estimation using Burg"s method.
 
     Notes
     -----
     This solves yule_walker for each desired lag and contains
     currently duplicate calculations.
     """
-    x = array_like(x, 'x')
-    nlags = int_like(nlags, 'nlags')
-    method = string_like(method, 'method', options=('unbiased', 'mle'))
+    x = array_like(x, "x")
+    nlags = int_like(nlags, "nlags", optional=True)
+    if nlags is None:
+        import warnings
+
+        warnings.warn("The default number of lags is changing from 40 to"
+                      "min(int(10 * np.log10(nobs)), nobs - 1) after 0.12"
+                      "is released. Set the number of lags to an integer to "
+                      " silence this warning.",
+                      FutureWarning)
+        nlags = 40
+
+    method = string_like(method, "method", options=("unbiased", "mle"))
 
     pacf = [1.]
     for k in range(1, nlags + 1):
@@ -639,7 +664,7 @@ def pacf_yw(x, nlags=40, method='unbiased'):
 
 def pacf_burg(x, nlags=None, demean=True):
     """
-    Calculate Burg's partial autocorrelation estimator.
+    Calculate Burg"s partial autocorrelation estimator.
 
     Parameters
     ----------
@@ -674,13 +699,13 @@ def pacf_burg(x, nlags=None, demean=True):
     .. [1] Brockwell, P.J. and Davis, R.A., 2016. Introduction to time series
         and forecasting. Springer.
     """
-    x = array_like(x, 'x')
+    x = array_like(x, "x")
     if demean:
         x = x - x.mean()
     nobs = x.shape[0]
     p = nlags if nlags is not None else min(int(10 * np.log10(nobs)), nobs - 1)
     if p > nobs - 1:
-        raise ValueError('nlags must be smaller than nobs - 1')
+        raise ValueError("nlags must be smaller than nobs - 1")
     d = np.zeros(p + 1)
     d[0] = 2 * x.dot(x)
     pacf = np.zeros(p + 1)
@@ -703,7 +728,7 @@ def pacf_burg(x, nlags=None, demean=True):
     return pacf, sigma2
 
 
-def pacf_ols(x, nlags=40, efficient=True, unbiased=False):
+def pacf_ols(x, nlags=None, efficient=True, unbiased=False):
     """
     Calculate partial autocorrelations via OLS.
 
@@ -733,7 +758,7 @@ def pacf_ols(x, nlags=40, efficient=True, unbiased=False):
     statsmodels.tsa.stattools.pacf_yw
          Partial autocorrelation estimation using Yule-Walker.
     statsmodels.tsa.stattools.pacf_burg
-        Partial autocorrelation estimation using Burg's method.
+        Partial autocorrelation estimation using Burg"s method.
 
     Notes
     -----
@@ -756,15 +781,25 @@ def pacf_ols(x, nlags=40, efficient=True, unbiased=False):
     .. [1] Box, G. E., Jenkins, G. M., Reinsel, G. C., & Ljung, G. M. (2015).
        Time series analysis: forecasting and control. John Wiley & Sons, p. 66
     """
-    x = array_like(x, 'x')
-    nlags = int_like(nlags, 'nlags')
-    efficient = bool_like(efficient, 'efficient')
-    unbiased = bool_like(unbiased, 'unbiased')
+    x = array_like(x, "x")
+    nlags = int_like(nlags, "nlags", optional=True)
+    efficient = bool_like(efficient, "efficient")
+    unbiased = bool_like(unbiased, "unbiased")
+
+    if nlags is None:
+        import warnings
+
+        warnings.warn("The default number of lags is changing from 40 to"
+                      "min(int(10 * np.log10(nobs)), nobs - 1) after 0.12"
+                      "is released. Set the number of lags to an integer to "
+                      " silence this warning.",
+                      FutureWarning)
+        nlags = 40
 
     pacf = np.empty(nlags + 1)
     pacf[0] = 1.0
     if efficient:
-        xlags, x0 = lagmat(x, nlags, original='sep')
+        xlags, x0 = lagmat(x, nlags, original="sep")
         xlags = add_constant(xlags)
         for k in range(1, nlags + 1):
             params = lstsq(xlags[k:, :k + 1], x0[k:], rcond=None)[0]
@@ -772,7 +807,7 @@ def pacf_ols(x, nlags=40, efficient=True, unbiased=False):
     else:
         x = x - np.mean(x)
         # Create a single set of lags for multivariate OLS
-        xlags, x0 = lagmat(x, nlags, original='sep', trim='both')
+        xlags, x0 = lagmat(x, nlags, original="sep", trim="both")
         for k in range(1, nlags + 1):
             params = lstsq(xlags[:, :k], x0, rcond=None)[0]
             # Last coefficient corresponds to PACF value (see [1])
@@ -785,7 +820,7 @@ def pacf_ols(x, nlags=40, efficient=True, unbiased=False):
     return pacf
 
 
-def pacf(x, nlags=40, method='ywunbiased', alpha=None):
+def pacf(x, nlags=None, method="ywunbiased", alpha=None):
     """
     Partial autocorrelation estimate.
 
@@ -793,22 +828,22 @@ def pacf(x, nlags=40, method='ywunbiased', alpha=None):
     ----------
     x : array_like
         Observations of time series for which pacf is calculated.
-    nlags : int, optional
+    nlags : int, default 40
         The largest lag for which the pacf is returned.
-    method : str, optional
+    method : str, default "ywunbiased"
         Specifies which method for the calculations to use.
 
-        - 'yw' or 'ywunbiased' : Yule-Walker with bias correction in
+        - "yw" or "ywunbiased" : Yule-Walker with bias correction in
           denominator for acovf. Default.
-        - 'ywm' or 'ywmle' : Yule-Walker without bias correction.
-        - 'ols' : regression of time series on lags of it and on constant.
-        - 'ols-inefficient' : regression of time series on lags using a single
+        - "ywm" or "ywmle" : Yule-Walker without bias correction.
+        - "ols" : regression of time series on lags of it and on constant.
+        - "ols-inefficient" : regression of time series on lags using a single
           common sample to estimate all pacf coefficients.
-        - 'ols-unbiased' : regression of time series on lags with a bias
+        - "ols-unbiased" : regression of time series on lags with a bias
           adjustment.
-        - 'ld' or 'ldunbiased' : Levinson-Durbin recursion with bias
+        - "ld" or "ldunbiased" : Levinson-Durbin recursion with bias
           correction.
-        - 'ldb' or 'ldbiased' : Levinson-Durbin recursion without bias
+        - "ldb" or "ldbiased" : Levinson-Durbin recursion without bias
           correction.
 
     alpha : float, optional
@@ -835,7 +870,7 @@ def pacf(x, nlags=40, method='ywunbiased', alpha=None):
     statsmodels.tsa.stattools.pacf_ols
         Partial autocorrelation estimation using OLS.
     statsmodels.tsa.stattools.pacf_burg
-        Partial autocorrelation estimation using Burg's method.
+        Partial autocorrelation estimation using Burg"s method.
 
     Notes
     -----
@@ -847,28 +882,38 @@ def pacf(x, nlags=40, method='ywunbiased', alpha=None):
     Yule-Walker (unbiased) and Levinson-Durbin (unbiased) performed
     consistently worse than the other options.
     """
-    nlags = int_like(nlags, 'nlags')
-    methods = ('ols', 'ols-inefficient', 'ols-unbiased', 'yw', 'ywu', 'ld',
-               'ywunbiased', 'yw_unbiased', 'ywm', 'ywmle', 'yw_mle', 'ldu',
-               'ldunbiased', 'ld_unbiased', 'ldb', 'ldbiased', 'ld_biased')
-    method = string_like(method, 'method', options=methods)
+    nlags = int_like(nlags, "nlags", optional=True)
+    methods = ("ols", "ols-inefficient", "ols-unbiased", "yw", "ywu", "ld",
+               "ywunbiased", "yw_unbiased", "ywm", "ywmle", "yw_mle", "ldu",
+               "ldunbiased", "ld_unbiased", "ldb", "ldbiased", "ld_biased")
+    method = string_like(method, "method", options=methods)
 
-    alpha = float_like(alpha, 'alpha', optional=True)
+    alpha = float_like(alpha, "alpha", optional=True)
 
-    if method in ('ols', 'ols-inefficient', 'ols-unbiased'):
-        efficient = 'inefficient' not in method
-        unbiased = 'unbiased' in method
+    if nlags is None:
+        import warnings
+
+        warnings.warn("The default number of lags is changing from 40 to"
+                      "min(int(10 * np.log10(nobs)), nobs - 1) after 0.12"
+                      "is released. Set the number of lags to an integer to "
+                      " silence this warning.",
+                      FutureWarning)
+        nlags = 40
+
+    if method in ("ols", "ols-inefficient", "ols-unbiased"):
+        efficient = "inefficient" not in method
+        unbiased = "unbiased" in method
         ret = pacf_ols(x, nlags=nlags, efficient=efficient, unbiased=unbiased)
-    elif method in ('yw', 'ywu', 'ywunbiased', 'yw_unbiased'):
-        ret = pacf_yw(x, nlags=nlags, method='unbiased')
-    elif method in ('ywm', 'ywmle', 'yw_mle'):
-        ret = pacf_yw(x, nlags=nlags, method='mle')
-    elif method in ('ld', 'ldu', 'ldunbiased', 'ld_unbiased'):
+    elif method in ("yw", "ywu", "ywunbiased", "yw_unbiased"):
+        ret = pacf_yw(x, nlags=nlags, method="unbiased")
+    elif method in ("ywm", "ywmle", "yw_mle"):
+        ret = pacf_yw(x, nlags=nlags, method="mle")
+    elif method in ("ld", "ldu", "ldunbiased", "ld_unbiased"):
         acv = acovf(x, unbiased=True, fft=False)
         ld_ = levinson_durbin(acv, nlags=nlags, isacov=True)
         ret = ld_[2]
     # inconsistent naming with ywmle
-    else:  # method in ('ldb', 'ldbiased', 'ld_biased')
+    else:  # method in ("ldb", "ldbiased", "ld_biased")
         acv = acovf(x, unbiased=False, fft=False)
         ld_ = levinson_durbin(acv, nlags=nlags, isacov=True)
         ret = ld_[2]
@@ -906,10 +951,10 @@ def ccovf(x, y, unbiased=True, demean=True):
     This uses np.correlate which does full convolution. For very long time
     series it is recommended to use fft convolution instead.
     """
-    x = array_like(x, 'x')
-    y = array_like(y, 'y')
-    unbiased = bool_like(unbiased, 'unbiased')
-    demean = bool_like(demean, 'demean')
+    x = array_like(x, "x")
+    y = array_like(y, "y")
+    unbiased = bool_like(unbiased, "unbiased")
+    demean = bool_like(demean, "demean")
 
     n = len(x)
     if demean:
@@ -920,10 +965,10 @@ def ccovf(x, y, unbiased=True, demean=True):
         yo = y
     if unbiased:
         xi = np.ones(n)
-        d = np.correlate(xi, xi, 'full')
+        d = np.correlate(xi, xi, "full")
     else:
         d = n
-    return (np.correlate(xo, yo, 'full') / d)[n - 1:]
+    return (np.correlate(xo, yo, "full") / d)[n - 1:]
 
 
 def ccf(x, y, unbiased=True):
@@ -950,9 +995,9 @@ def ccf(x, y, unbiased=True):
     If unbiased is true, the denominator for the autocovariance is adjusted
     but the autocorrelation is not an unbiased estimator.
     """
-    x = array_like(x, 'x')
-    y = array_like(y, 'y')
-    unbiased = bool_like(unbiased, 'unbiased')
+    x = array_like(x, "x")
+    y = array_like(y, "y")
+    unbiased = bool_like(unbiased, "unbiased")
 
     cvf = ccovf(x, y, unbiased=unbiased, demean=True)
     return cvf / (np.std(x) * np.std(y))
@@ -982,9 +1027,9 @@ def periodogram(x):
     """
     # TODO: Remove after 0.11
     import warnings
-    warnings.warn('periodogram is deprecated and will be removed after 0.11. '
-                  'Use scipy.signal.periodogram instead.', FutureWarning)
-    x = array_like(x, 'x')
+    warnings.warn("periodogram is deprecated and will be removed after 0.11. "
+                  "Use scipy.signal.periodogram instead.", FutureWarning)
+    x = array_like(x, "x")
 
     pergr = 1. / len(x) * np.abs(np.fft.fft(x)) ** 2
     pergr[0] = 0.  # what are the implications of this?
@@ -1033,9 +1078,9 @@ def levinson_durbin(s, nlags=10, isacov=False):
     sample autocovariance function is calculated with the default options
     (biased, no fft).
     """
-    s = array_like(s, 's')
-    nlags = int_like(nlags, 'nlags')
-    isacov = bool_like(isacov, 'isacov')
+    s = array_like(s, "s")
+    nlags = int_like(nlags, "nlags")
+    isacov = bool_like(isacov, "isacov")
 
     order = nlags
 
@@ -1044,17 +1089,17 @@ def levinson_durbin(s, nlags=10, isacov=False):
     else:
         sxx_m = acovf(s, fft=False)[:order + 1]  # not tested
 
-    phi = np.zeros((order + 1, order + 1), 'd')
+    phi = np.zeros((order + 1, order + 1), "d")
     sig = np.zeros(order + 1)
     # initial points for the recursion
     phi[1, 1] = sxx_m[1] / sxx_m[0]
     sig[1] = sxx_m[0] - phi[1, 1] * sxx_m[1]
     for k in range(2, order + 1):
-        phi[k, k] = (sxx_m[k] - np.dot(phi[1:k, k-1],
-                                       sxx_m[1:k][::-1])) / sig[k-1]
+        phi[k, k] = (sxx_m[k] - np.dot(phi[1:k, k - 1],
+                                       sxx_m[1:k][::-1])) / sig[k - 1]
         for j in range(1, k):
-            phi[j, k] = phi[j, k-1] - phi[k, k] * phi[k-j, k-1]
-        sig[k] = sig[k-1] * (1 - phi[k, k]**2)
+            phi[j, k] = phi[j, k - 1] - phi[k, k] * phi[k - j, k - 1]
+        sig[k] = sig[k - 1] * (1 - phi[k, k] ** 2)
 
     sigma_v = sig[-1]
     arcoefs = phi[1:, -1]
@@ -1088,19 +1133,19 @@ def levinson_durbin_pacf(pacf, nlags=None):
     .. [1] Brockwell, P.J. and Davis, R.A., 2016. Introduction to time series
         and forecasting. Springer.
     """
-    pacf = array_like(pacf, 'pacf')
-    nlags = int_like(nlags, 'nlags', optional=True)
+    pacf = array_like(pacf, "pacf")
+    nlags = int_like(nlags, "nlags", optional=True)
     pacf = np.squeeze(np.asarray(pacf))
 
     if pacf[0] != 1:
-        raise ValueError('The first entry of the pacf corresponds to lags 0 '
-                         'and so must be 1.')
+        raise ValueError("The first entry of the pacf corresponds to lags 0 "
+                         "and so must be 1.")
     pacf = pacf[1:]
     n = pacf.shape[0]
     if nlags is not None:
         if nlags > n:
-            raise ValueError('Must provide at least as many values from the '
-                             'pacf as the number of lags.')
+            raise ValueError("Must provide at least as many values from the "
+                             "pacf as the number of lags.")
         pacf = pacf[:nlags]
         n = pacf.shape[0]
 
@@ -1111,7 +1156,7 @@ def levinson_durbin_pacf(pacf, nlags=None):
     for i in range(1, n):
         prev = arcoefs[:-(n - i)].copy()
         arcoefs[:-(n - i)] = prev - arcoefs[i] * prev[::-1]
-        acf[i + 1] = arcoefs[i] * nu[i-1] + prev.dot(acf[1:-(n - i)][::-1])
+        acf[i + 1] = arcoefs[i] * nu[i - 1] + prev.dot(acf[1:-(n - i)][::-1])
     acf[0] = 1
     return arcoefs, acf
 
@@ -1161,9 +1206,9 @@ def grangercausalitytests(x, maxlag, addconst=True, verbose=True):
     The null hypothesis for all four test is that the coefficients
     corresponding to past values of the second time series are zero.
 
-    'params_ftest', 'ssr_ftest' are based on F distribution
+    "params_ftest", "ssr_ftest" are based on F distribution
 
-    'ssr_chi2test', 'lrtest' are based on chi-square distribution
+    "ssr_chi2test", "lrtest" are based on chi-square distribution
 
     References
     ----------
@@ -1177,7 +1222,7 @@ def grangercausalitytests(x, maxlag, addconst=True, verbose=True):
     >>> from statsmodels.tsa.stattools import grangercausalitytests
     >>> import numpy as np
     >>> data = sm.datasets.macrodata.load_pandas()
-    >>> data = data.data[['realgdp', 'realcons']].pct_change().dropna()
+    >>> data = data.data[["realgdp", "realcons"]].pct_change().dropna()
 
     # All lags up to 4
     >>> gc_res = grangercausalitytests(data, 4)
@@ -1185,21 +1230,21 @@ def grangercausalitytests(x, maxlag, addconst=True, verbose=True):
     # Only lag 4
     >>> gc_res = grangercausalitytests(data, [4])
     """
-    x = array_like(x, 'x', ndim=2)
+    x = array_like(x, "x", ndim=2)
     if not np.isfinite(x).all():
-        raise ValueError('x contains NaN or inf values.')
-    addconst = bool_like(addconst, 'addconst')
-    verbose = bool_like(verbose, 'verbose')
+        raise ValueError("x contains NaN or inf values.")
+    addconst = bool_like(addconst, "addconst")
+    verbose = bool_like(verbose, "verbose")
     try:
         lags = np.array([int(lag) for lag in maxlag])
         maxlag = lags.max()
         if lags.min() <= 0 or lags.size == 0:
-            raise ValueError('maxlag must be a non-empty list containing only '
-                             'positive integers')
+            raise ValueError("maxlag must be a non-empty list containing only "
+                             "positive integers")
     except Exception:
-        maxlag = int_like(maxlag, 'maxlag')
+        maxlag = int_like(maxlag, "maxlag")
         if maxlag <= 0:
-            raise ValueError('maxlag must a a positive integer')
+            raise ValueError("maxlag must a a positive integer")
         lags = np.arange(1, maxlag + 1)
 
     if x.shape[0] <= 3 * maxlag + int(addconst):
@@ -1212,19 +1257,19 @@ def grangercausalitytests(x, maxlag, addconst=True, verbose=True):
     for mlg in lags:
         result = {}
         if verbose:
-            print('\nGranger Causality')
-            print('number of lags (no zero)', mlg)
+            print("\nGranger Causality")
+            print("number of lags (no zero)", mlg)
         mxlg = mlg
 
         # create lagmat of both time series
-        dta = lagmat2ds(x, mxlg, trim='both', dropex=1)
+        dta = lagmat2ds(x, mxlg, trim="both", dropex=1)
 
         # add constant
         if addconst:
             dtaown = add_constant(dta[:, 1:(mxlg + 1)], prepend=False)
             dtajoint = add_constant(dta[:, 1:], prepend=False)
         else:
-            raise NotImplementedError('Not Implemented')
+            raise NotImplementedError("Not Implemented")
             # dtaown = dta[:, 1:mxlg]
             # dtajoint = dta[:, 1:]
 
@@ -1241,28 +1286,28 @@ def grangercausalitytests(x, maxlag, addconst=True, verbose=True):
         fgc1 = ((res2down.ssr - res2djoint.ssr) /
                 res2djoint.ssr / mxlg * res2djoint.df_resid)
         if verbose:
-            print('ssr based F test:         F=%-8.4f, p=%-8.4f, df_denom=%d,'
-                  ' df_num=%d' % (fgc1,
+            print("ssr based F test:         F=%-8.4f, p=%-8.4f, df_denom=%d,"
+                  " df_num=%d" % (fgc1,
                                   stats.f.sf(fgc1, mxlg,
                                              res2djoint.df_resid),
                                   res2djoint.df_resid, mxlg))
-        result['ssr_ftest'] = (fgc1,
+        result["ssr_ftest"] = (fgc1,
                                stats.f.sf(fgc1, mxlg, res2djoint.df_resid),
                                res2djoint.df_resid, mxlg)
 
         # Granger Causality test using ssr (ch2 statistic)
         fgc2 = res2down.nobs * (res2down.ssr - res2djoint.ssr) / res2djoint.ssr
         if verbose:
-            print('ssr based chi2 test:   chi2=%-8.4f, p=%-8.4f, '
-                  'df=%d' % (fgc2, stats.chi2.sf(fgc2, mxlg), mxlg))
-        result['ssr_chi2test'] = (fgc2, stats.chi2.sf(fgc2, mxlg), mxlg)
+            print("ssr based chi2 test:   chi2=%-8.4f, p=%-8.4f, "
+                  "df=%d" % (fgc2, stats.chi2.sf(fgc2, mxlg), mxlg))
+        result["ssr_chi2test"] = (fgc2, stats.chi2.sf(fgc2, mxlg), mxlg)
 
         # likelihood ratio test pvalue:
         lr = -2 * (res2down.llf - res2djoint.llf)
         if verbose:
-            print('likelihood ratio test: chi2=%-8.4f, p=%-8.4f, df=%d' %
+            print("likelihood ratio test: chi2=%-8.4f, p=%-8.4f, df=%d" %
                   (lr, stats.chi2.sf(lr, mxlg), mxlg))
-        result['lrtest'] = (lr, stats.chi2.sf(lr, mxlg), mxlg)
+        result["lrtest"] = (lr, stats.chi2.sf(lr, mxlg), mxlg)
 
         # F test that all lag coefficients of exog are zero
         rconstr = np.column_stack((np.zeros((mxlg, mxlg)),
@@ -1270,10 +1315,10 @@ def grangercausalitytests(x, maxlag, addconst=True, verbose=True):
                                    np.zeros((mxlg, 1))))
         ftres = res2djoint.f_test(rconstr)
         if verbose:
-            print('parameter F test:         F=%-8.4f, p=%-8.4f, df_denom=%d,'
-                  ' df_num=%d' % (ftres.fvalue, ftres.pvalue, ftres.df_denom,
+            print("parameter F test:         F=%-8.4f, p=%-8.4f, df_denom=%d,"
+                  " df_num=%d" % (ftres.fvalue, ftres.pvalue, ftres.df_denom,
                                   ftres.df_num))
-        result['params_ftest'] = (np.squeeze(ftres.fvalue)[()],
+        result["params_ftest"] = (np.squeeze(ftres.fvalue)[()],
                                   np.squeeze(ftres.pvalue)[()],
                                   ftres.df_denom, ftres.df_num)
 
@@ -1282,7 +1327,7 @@ def grangercausalitytests(x, maxlag, addconst=True, verbose=True):
     return resli
 
 
-def coint(y0, y1, trend='c', method='aeg', maxlag=None, autolag='aic',
+def coint(y0, y1, trend="c", method="aeg", maxlag=None, autolag="aic",
           return_results=None):
     """
     Test for no-cointegration of a univariate equation.
@@ -1296,7 +1341,7 @@ def coint(y0, y1, trend='c', method='aeg', maxlag=None, autolag='aic',
 
     **Warning:** The autolag default has changed compared to statsmodels 0.8.
     In 0.8 autolag was always None, no the keyword is used and defaults to
-    'aic'. Use `autolag=None` to avoid the lag search.
+    "aic". Use `autolag=None` to avoid the lag search.
 
     Parameters
     ----------
@@ -1304,24 +1349,24 @@ def coint(y0, y1, trend='c', method='aeg', maxlag=None, autolag='aic',
         The first element in cointegrated system. Must be 1-d.
     y1 : array_like
         The remaining elements in cointegrated system.
-    trend : str {'c', 'ct'}
+    trend : str {"c", "ct"}
         The trend term included in regression for cointegrating equation.
 
-        * 'c' : constant.
-        * 'ct' : constant and linear trend.
-        * also available quadratic trend 'ctt', and no constant 'nc'.
+        * "c" : constant.
+        * "ct" : constant and linear trend.
+        * also available quadratic trend "ctt", and no constant "nc".
 
-    method : {'aeg'}
-        Only 'aeg' (augmented Engle-Granger) is available.
+    method : {"aeg"}
+        Only "aeg" (augmented Engle-Granger) is available.
     maxlag : None or int
         Argument for `adfuller`, largest or given number of lags.
     autolag : str
         Argument for `adfuller`, lag selection criterion.
 
         * If None, then maxlag lags are used without lag search.
-        * If 'AIC' (default) or 'BIC', then the number of lags is chosen
+        * If "AIC" (default) or "BIC", then the number of lags is chosen
           to minimize the corresponding information criterion.
-        * 't-stat' based choice of maxlag.  Starts with maxlag and drops a
+        * "t-stat" based choice of maxlag.  Starts with maxlag and drops a
           lag until the t-statistic on the last lag length is significant
           using a 5%-sized test.
     return_results : bool
@@ -1335,7 +1380,7 @@ def coint(y0, y1, trend='c', method='aeg', maxlag=None, autolag='aic',
     coint_t : float
         The t-statistic of unit-root test on residuals.
     pvalue : float
-        MacKinnon's approximate, asymptotic p-value based on MacKinnon (1994).
+        MacKinnon"s approximate, asymptotic p-value based on MacKinnon (1994).
     crit_value : dict
         Critical values for the test statistic at the 1 %, 5 %, and 10 %
         levels based on regression curve. This depends on the number of
@@ -1366,22 +1411,22 @@ def coint(y0, y1, trend='c', method='aeg', maxlag=None, autolag='aic',
        for Unit-Root and Cointegration Tests." Journal of Business & Economics
        Statistics, 12.2, 167-76.
     .. [2] MacKinnon, J.G. 2010.  "Critical Values for Cointegration Tests."
-       Queen's University, Dept of Economics Working Papers 1227.
+       Queen"s University, Dept of Economics Working Papers 1227.
        http://ideas.repec.org/p/qed/wpaper/1227.html
     """
-    y0 = array_like(y0, 'y0')
-    y1 = array_like(y1, 'y1', ndim=2)
-    trend = string_like(trend, 'trend', options=('c', 'nc', 'ct', 'ctt'))
-    method = string_like(method, 'method', options=('aeg',))
-    maxlag = int_like(maxlag, 'maxlag', optional=True)
-    autolag = string_like(autolag, 'autolag', optional=True,
-                          options=('aic', 'bic', 't-stat'))
-    return_results = bool_like(return_results, 'return_results', optional=True)
+    y0 = array_like(y0, "y0")
+    y1 = array_like(y1, "y1", ndim=2)
+    trend = string_like(trend, "trend", options=("c", "nc", "ct", "ctt"))
+    method = string_like(method, "method", options=("aeg",))
+    maxlag = int_like(maxlag, "maxlag", optional=True)
+    autolag = string_like(autolag, "autolag", optional=True,
+                          options=("aic", "bic", "t-stat"))
+    return_results = bool_like(return_results, "return_results", optional=True)
 
     nobs, k_vars = y1.shape
-    k_vars += 1   # add 1 for y0
+    k_vars += 1  # add 1 for y0
 
-    if trend == 'nc':
+    if trend == "nc":
         xx = y1
     else:
         xx = add_trend(y1, trend=trend, prepend=False)
@@ -1390,7 +1435,7 @@ def coint(y0, y1, trend='c', method='aeg', maxlag=None, autolag='aic',
 
     if res_co.rsquared < 1 - 100 * SQRTEPS:
         res_adf = adfuller(res_co.resid, maxlag=maxlag, autolag=autolag,
-                           regression='nc')
+                           regression="nc")
     else:
         import warnings
         warnings.warn("y0 and y1 are (almost) perfectly colinear."
@@ -1400,7 +1445,7 @@ def coint(y0, y1, trend='c', method='aeg', maxlag=None, autolag='aic',
         res_adf = (-np.inf,)
 
     # no constant or trend, see egranger in Stata and MacKinnon
-    if trend == 'nc':
+    if trend == "nc":
         crit = [np.nan] * 3  # 2010 critical values not available
     else:
         crit = mackinnoncrit(N=k_vars, regression=trend, nobs=nobs - 1)
@@ -1425,9 +1470,9 @@ def _safe_arma_fit(y, order, model_kw, trend, fit_kw, start_params=None):
             # user supplied start_params only get one chance
             return
         # try a little harder, should be handled in fit really
-        elif ('initial' not in error.args[0] or 'initial' in str(error)):
+        elif ("initial" not in error.args[0] or "initial" in str(error)):
             start_params = [.1] * sum(order)
-            if trend == 'c':
+            if trend == "c":
                 start_params = [.1] + start_params
             return _safe_arma_fit(y, order, model_kw, trend, fit_kw,
                                   start_params)
@@ -1437,7 +1482,7 @@ def _safe_arma_fit(y, order, model_kw, trend, fit_kw, start_params=None):
         return
 
 
-def arma_order_select_ic(y, max_ar=4, max_ma=2, ic='bic', trend='c',
+def arma_order_select_ic(y, max_ar=4, max_ma=2, ic="bic", trend="c",
                          model_kw=None, fit_kw=None):
     """
     Compute information criteria for many ARMA models.
@@ -1475,7 +1520,7 @@ def arma_order_select_ic(y, max_ar=4, max_ma=2, ic='bic', trend='c',
     function computes the full exact MLE estimate of each model and can be,
     therefore a little slow. An implementation using approximate estimates
     will be provided in the future. In the meantime, consider passing
-    {method : 'css'} to fit_kw.
+    {method : "css"} to fit_kw.
 
     Examples
     --------
@@ -1491,15 +1536,15 @@ def arma_order_select_ic(y, max_ar=4, max_ma=2, ic='bic', trend='c',
     >>> nobs = 250
     >>> np.random.seed(2014)
     >>> y = arma_generate_sample(arparams, maparams, nobs)
-    >>> res = sm.tsa.arma_order_select_ic(y, ic=['aic', 'bic'], trend='nc')
+    >>> res = sm.tsa.arma_order_select_ic(y, ic=["aic", "bic"], trend="nc")
     >>> res.aic_min_order
     >>> res.bic_min_order
     """
-    max_ar = int_like(max_ar, 'max_ar')
-    max_ma = int_like(max_ma, 'max_ma')
-    trend = string_like(trend, 'trend', options=('nc', 'c'))
-    model_kw = dict_like(model_kw, 'model_kw', optional=True)
-    fit_kw = dict_like(fit_kw, 'fit_kw', optional=True)
+    max_ar = int_like(max_ar, "max_ar")
+    max_ma = int_like(max_ma, "max_ma")
+    trend = string_like(trend, "trend", options=("nc", "c"))
+    model_kw = dict_like(model_kw, "model_kw", optional=True)
+    fit_kw = dict_like(fit_kw, "fit_kw", optional=True)
 
     ar_range = lrange(0, max_ar + 1)
     ma_range = lrange(0, max_ma + 1)
@@ -1511,10 +1556,10 @@ def arma_order_select_ic(y, max_ar=4, max_ma=2, ic='bic', trend='c',
     results = np.zeros((len(ic), max_ar + 1, max_ma + 1))
     model_kw = {} if model_kw is None else model_kw
     fit_kw = {} if fit_kw is None else fit_kw
-    y_arr = array_like(y, 'y', contiguous=True)
+    y_arr = array_like(y, "y", contiguous=True)
     for ar in ar_range:
         for ma in ma_range:
-            if ar == 0 and ma == 0 and trend == 'nc':
+            if ar == 0 and ma == 0 and trend == "nc":
                 results[:, ar, ma] = np.nan
                 continue
 
@@ -1535,7 +1580,7 @@ def arma_order_select_ic(y, max_ar=4, max_ma=2, ic='bic', trend='c',
     min_res = {}
     for i, result in iteritems(res):
         mins = np.where(result.min().min() == result)
-        min_res.update({i + '_min_order': (mins[0][0], mins[1][0])})
+        min_res.update({i + "_min_order": (mins[0][0], mins[1][0])})
     res.update(min_res)
 
     return Bunch(**res)
@@ -1543,13 +1588,13 @@ def arma_order_select_ic(y, max_ar=4, max_ma=2, ic='bic', trend='c',
 
 def has_missing(data):
     """
-    Returns True if 'data' contains missing entries, otherwise False
+    Returns True if "data" contains missing entries, otherwise False
     """
     return np.isnan(np.sum(data))
 
 
-@deprecate_kwarg('lags', 'nlags')
-def kpss(x, regression='c', nlags=None, store=False):
+@deprecate_kwarg("lags", "nlags")
+def kpss(x, regression="c", nlags=None, store=False):
     """
     Kwiatkowski-Phillips-Schmidt-Shin test for stationarity.
 
@@ -1560,17 +1605,17 @@ def kpss(x, regression='c', nlags=None, store=False):
     ----------
     x : array_like, 1d
         The data series to test.
-    regression : str{'c', 'ct'}
+    regression : str{"c", "ct"}
         The null hypothesis for the KPSS test.
 
-        * 'c' : The data is stationary around a constant (default).
-        * 'ct' : The data is stationary around a trend.
+        * "c" : The data is stationary around a constant (default).
+        * "ct" : The data is stationary around a trend.
     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
+        calculated using the legacy method. If "auto", lags is calculated
         using the data-dependent method of Hobijn et al. (1998). See also
         Andrews (1991), Newey & West (1994), and Schwert (1989). If set to
-        'legacy',  uses int(12 * (n / 100)**(1 / 4)) , as outlined in
+        "legacy",  uses int(12 * (n / 100)**(1 / 4)) , as outlined in
         Schwert (1989).
     store : bool
         If True, then a result instance is returned additionally to
@@ -1626,9 +1671,9 @@ def kpss(x, regression='c', nlags=None, store=False):
     """
     from warnings import warn
 
-    x = array_like(x, 'x')
-    regression = string_like(regression, 'regression', options=('c', 'ct'))
-    store = bool_like(store, 'store')
+    x = array_like(x, "x")
+    regression = string_like(regression, "regression", options=("c", "ct"))
+    store = bool_like(store, "store")
 
     nobs = x.shape[0]
     hypo = regression
@@ -1637,32 +1682,32 @@ def kpss(x, regression='c', nlags=None, store=False):
     if nobs != x.size:
         raise ValueError("x of shape {0} not understood".format(x.shape))
 
-    if hypo == 'ct':
+    if hypo == "ct":
         # p. 162 Kwiatkowski et al. (1992): y_t = beta * t + r_t + e_t,
         # where beta is the trend, r_t a random walk and e_t a stationary
         # error term.
         resids = OLS(x, add_constant(np.arange(1, nobs + 1))).fit().resid
         crit = [0.119, 0.146, 0.176, 0.216]
-    elif hypo == 'c':
+    elif hypo == "c":
         # special case of the model above, where beta = 0 (so the null
         # hypothesis is that the data is stationary around r_0).
         resids = x - x.mean()
         crit = [0.347, 0.463, 0.574, 0.739]
 
     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. ' \
-              'After the next release, the default will change to be the ' \
-              'same as lags=\'auto\' which uses an automatic lag length ' \
-              'selection method. To silence this warning, either use ' \
-              '\'auto\' or \'legacy\''
+        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. " \
+              "After the next release, the default will change to be the " \
+              "same as lags=\"auto\" which uses an automatic lag length " \
+              "selection method. To silence this warning, either use " \
+              "\"auto\" or \"legacy\""
         warn(msg, FutureWarning)
-    if nlags == 'legacy':
+    if nlags == "legacy":
         nlags = int(np.ceil(12. * np.power(nobs / 100., 1 / 4.)))
         nlags = min(nlags, nobs - 1)
-    elif nlags == 'auto':
+    elif nlags == "auto":
         # autolag method of Hobijn et al. (1998)
         nlags = _kpss_autolag(resids, nobs)
         nlags = min(nlags, nobs - 1)
@@ -1675,7 +1720,7 @@ def kpss(x, regression='c', nlags=None, store=False):
 
     pvals = [0.10, 0.05, 0.025, 0.01]
 
-    eta = np.sum(resids.cumsum()**2) / (nobs**2)  # eq. 11, p. 165
+    eta = np.sum(resids.cumsum() ** 2) / (nobs ** 2)  # eq. 11, p. 165
     s_hat = _sigma_est_kpss(resids, nobs, nlags)
 
     kpss_stat = eta / s_hat
@@ -1690,14 +1735,14 @@ def kpss(x, regression='c', nlags=None, store=False):
     elif p_value == pvals[0]:
         warn(warn_msg.format(direction="greater"), InterpolationWarning)
 
-    crit_dict = {'10%': crit[0], '5%': crit[1], '2.5%': crit[2], '1%': crit[3]}
+    crit_dict = {"10%": crit[0], "5%": crit[1], "2.5%": crit[2], "1%": crit[3]}
 
     if store:
         rstore = ResultsStore()
         rstore.lags = nlags
         rstore.nobs = nobs
 
-        stationary_type = "level" if hypo == 'c' else "trend"
+        stationary_type = "level" if hypo == "c" else "trend"
         rstore.H0 = "The series is {0} stationary".format(stationary_type)
         rstore.HA = "The series is not {0} stationary".format(stationary_type)
 
@@ -1711,7 +1756,7 @@ def _sigma_est_kpss(resids, nobs, lags):
     Computes equation 10, p. 164 of Kwiatkowski et al. (1992). This is the
     consistent estimator for the variance.
     """
-    s_hat = np.sum(resids**2)
+    s_hat = np.sum(resids ** 2)
     for i in range(1, lags + 1):
         resids_prod = np.dot(resids[i:], resids[:nobs - i])
         s_hat += 2 * resids_prod * (1. - (i / (lags + 1.)))
@@ -1725,7 +1770,7 @@ def _kpss_autolag(resids, nobs):
     (1994), and Schwert (1989). Assumes Bartlett / Newey-West kernel.
     """
     covlags = int(np.power(nobs, 2. / 9.))
-    s0 = np.sum(resids**2) / nobs
+    s0 = np.sum(resids ** 2) / nobs
     s1 = 0
     for i in range(1, covlags + 1):
         resids_prod = np.dot(resids[i:], resids[:nobs - i])
@@ -1743,6 +1788,7 @@ class ZivotAndrewsUnitRoot(object):
     """
     Class wrapper for Zivot-Andrews structural-break unit-root test
     """
+
     def __init__(self):
         """
         Critical values for the three different models specified for the
@@ -1773,7 +1819,7 @@ def __init__(self):
             (95.000, -2.83179), (96.000, -2.76465), (97.000, -2.68624),
             (98.000, -2.57884), (99.000, -2.40044), (99.900, -1.88932)
         )
-        self._za_critical_values['c'] = np.asarray(self._c)
+        self._za_critical_values["c"] = np.asarray(self._c)
         # trend-only model
         self._t = (
             (0.001, -83.9094), (0.100, -13.8837), (0.200, -9.13205),
@@ -1793,7 +1839,7 @@ def __init__(self):
             (95.000, -2.30820), (96.000, -2.25797), (97.000, -2.19648),
             (98.000, -2.11320), (99.000, -1.99138), (99.900, -1.67466)
         )
-        self._za_critical_values['t'] = np.asarray(self._t)
+        self._za_critical_values["t"] = np.asarray(self._t)
         # constant + trend model
         self._ct = (
             (0.001, -38.17800), (0.100, -6.43107), (0.200, -6.07279),
@@ -1813,9 +1859,9 @@ def __init__(self):
             (95.000, -3.08769), (96.000, -3.03088), (97.000, -2.96091),
             (98.000, -2.85581), (99.000, -2.71015), (99.900, -2.28767)
         )
-        self._za_critical_values['ct'] = np.asarray(self._ct)
+        self._za_critical_values["ct"] = np.asarray(self._ct)
 
-    def _za_crit(self, stat, model='c'):
+    def _za_crit(self, stat, model="c"):
         """
         Linear interpolation for Zivot-Andrews p-values and critical values
 
@@ -1823,8 +1869,8 @@ def _za_crit(self, stat, model='c'):
         ----------
         stat : float
             The ZA test statistic
-        model : {'c','t','ct'}
-            The model used when computing the ZA statistic. 'c' is default.
+        model : {"c","t","ct"}
+            The model used when computing the ZA statistic. "c" is default.
 
         Returns
         -------
@@ -1877,7 +1923,7 @@ def _format_regression_data(self, series, nobs, const, trend, cols, lags):
         # lagged y and dy
         exog[:, cols - 1] = series[lags:(nobs - 1)]
         exog[:, cols:] = lagmat(
-            endog, lags, trim='none')[lags:exog.shape[0] + lags]
+            endog, lags, trim="none")[lags:exog.shape[0] + lags]
         return endog, exog
 
     def _update_regression_exog(self, exog, regression, period, nobs, const,
@@ -1886,20 +1932,20 @@ def _update_regression_exog(self, exog, regression, period, nobs, const,
         Update the exog array for the next regression.
         """
         cutoff = (period - (lags + 1))
-        if regression != 't':
+        if regression != "t":
             exog[:cutoff, 1] = 0
             exog[cutoff:, 1] = const
             exog[:, 2] = trend[(lags + 2):(nobs + 1)]
-            if regression == 'ct':
+            if regression == "ct":
                 exog[:cutoff, 3] = 0
                 exog[cutoff:, 3] = trend[1:(nobs - period + 1)]
         else:
             exog[:, 1] = trend[(lags + 2):(nobs + 1)]
-            exog[:(cutoff-1), 2] = 0
-            exog[(cutoff-1):, 2] = trend[0:(nobs - period + 1)]
+            exog[:(cutoff - 1), 2] = 0
+            exog[(cutoff - 1):, 2] = trend[0:(nobs - period + 1)]
         return exog
 
-    def run(self, x, trim=0.15, maxlag=None, regression='c', autolag='AIC'):
+    def run(self, x, trim=0.15, maxlag=None, regression="c", autolag="AIC"):
         """
         Zivot-Andrews structural-break unit-root test.
 
@@ -1916,19 +1962,19 @@ def run(self, x, trim=0.15, maxlag=None, regression='c', autolag='AIC'):
         maxlag : int
             The maximum lag which is included in test, default is
             12*(nobs/100)^{1/4} (Schwert, 1989).
-        regression : {'c','t','ct'}
+        regression : {"c","t","ct"}
             Constant and trend order to include in regression.
 
-            * 'c' : constant only (default).
-            * 't' : trend only.
-            * 'ct' : constant and trend.
-        autolag : {'AIC', 'BIC', 't-stat', None}
+            * "c" : constant only (default).
+            * "t" : trend only.
+            * "ct" : constant and trend.
+        autolag : {"AIC", "BIC", "t-stat", None}
             The method to select the lag length when using automatic selection.
 
             * if None, then maxlag lags are used,
-            * if 'AIC' (default) or 'BIC', then the number of lags is chosen
+            * if "AIC" (default) or "BIC", then the number of lags is chosen
               to minimize the corresponding information criterion,
-            * 't-stat' based choice of maxlag.  Starts with maxlag and drops a
+            * "t-stat" based choice of maxlag.  Starts with maxlag and drops a
               lag until the t-statistic on the last lag length is significant
               using a 5%-sized test.
 
@@ -1976,18 +2022,18 @@ def run(self, x, trim=0.15, maxlag=None, regression='c', autolag='AIC'):
            great crash, the oil-price shock, and the unit-root hypothesis.
            Journal of Business & Economic Studies, 10: 251-270.
         """
-        x = array_like(x, 'x')
-        trim = float_like(trim, 'trim')
-        maxlag = int_like(maxlag, 'maxlag', optional=True)
-        regression = string_like(regression, 'regression',
-                                 options=('c', 't', 'ct'))
-        autolag = string_like(autolag, 'autolag',
-                              options=('aic', 'bic', 't-stat'), optional=True)
+        x = array_like(x, "x")
+        trim = float_like(trim, "trim")
+        maxlag = int_like(maxlag, "maxlag", optional=True)
+        regression = string_like(regression, "regression",
+                                 options=("c", "t", "ct"))
+        autolag = string_like(autolag, "autolag",
+                              options=("aic", "bic", "t-stat"), optional=True)
         if trim < 0 or trim > (1. / 3.):
-            raise ValueError('trim value must be a float in range [0, 1/3)')
+            raise ValueError("trim value must be a float in range [0, 1/3)")
         nobs = x.shape[0]
         if autolag:
-            adf_res = adfuller(x, maxlag=maxlag, regression='ct',
+            adf_res = adfuller(x, maxlag=maxlag, regression="ct",
                                autolag=autolag)
             baselags = adf_res[2]
         elif maxlag:
@@ -1997,7 +2043,7 @@ def run(self, x, trim=0.15, maxlag=None, regression='c', autolag='AIC'):
         trimcnt = int(nobs * trim)
         start_period = trimcnt
         end_period = nobs - trimcnt
-        if regression == 'ct':
+        if regression == "ct":
             basecols = 5
         else:
             basecols = 4
@@ -2020,8 +2066,8 @@ def run(self, x, trim=0.15, maxlag=None, regression='c', autolag='AIC'):
                 o = OLS(endog[baselags:], exog, hasconst=1).fit()
                 if o.df_model < exog.shape[1] - 1:
                     raise ValueError(
-                        'ZA: auxiliary exog matrix is not full rank.\n'
-                        '  cols (exc intercept) = {}  rank = {}'.format(
+                        "ZA: auxiliary exog matrix is not full rank.\n"
+                        "  cols (exc intercept) = {}  rank = {}".format(
                             exog.shape[1] - 1, o.df_model))
                 stats[bp] = o.tvalues[basecols - 1]
             else:
@@ -2035,8 +2081,8 @@ def run(self, x, trim=0.15, maxlag=None, regression='c', autolag='AIC'):
         cvdict = crit[1]
         return zastat, pval, cvdict, baselags, bpidx
 
-    def __call__(self, x, trim=0.15, maxlag=None, regression='c',
-                 autolag='AIC'):
+    def __call__(self, x, trim=0.15, maxlag=None, regression="c",
+                 autolag="AIC"):
         return self.run(x, trim=trim, maxlag=maxlag, regression=regression,
                         autolag=autolag)
 


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
@@ -719,7 +719,7 @@ def test_arma_order_select_ic_failure():
 def test_acf_fft_dataframe():
     # regression test #322
 
-    result = acf(sunspots.load_pandas().data[['SUNACTIVITY']], fft=True)
+    result = acf(sunspots.load_pandas().data[['SUNACTIVITY']], fft=True, nlags=20)
     assert_equal(result.ndim, 1)
 
 
diff --git a/statsmodels/tsa/tests/test_tsa_tools.py b/statsmodels/tsa/tests/test_tsa_tools.py
--- a/statsmodels/tsa/tests/test_tsa_tools.py
+++ b/statsmodels/tsa/tests/test_tsa_tools.py
@@ -24,9 +24,9 @@
 
 
 def test_acf():
-    acf_x = tsa.acf(x100, unbiased=False, fft=False)[:21]
+    acf_x = tsa.acf(x100, unbiased=False, fft=False, nlags=20)
     assert_array_almost_equal(mlacf.acf100.ravel(), acf_x, 8)  # why only dec=8
-    acf_x = tsa.acf(x1000, unbiased=False, fft=False)[:21]
+    acf_x = tsa.acf(x1000, unbiased=False, fft=False, nlags=20)
     assert_array_almost_equal(mlacf.acf1000.ravel(), acf_x, 8)  # why only dec=9