Repository: statsmodels/statsmodels

Issue:
DOC: redundant/conflicting datasets readmes
- datasets.README.txt is copied from an old scikit-learn.
- sandbox/dataset_notes.rst both references scikits.statsmodels and bzr
- docs/source/datasets/dataset_proposal.rst documenting a proposal accepted long long ago?
- docs/source/dev/dataset_notes.rst except for the exhortation to get permission in the sandbox version, this appears to dominate the other.

Can we get this down to a Single Source of Truth?


Discussion:
docs/source/dev/dataset_notes.rst seems to be the dominant one, although there appears to be different information in docs/source/datasets/dataset_proposal.rst that should be incorporated into a single source.
Happy if you want to take the best and make a single one. 
will take a look.

BTW just rebased a handful of CLN PRs.  In particular 5692 would be great to get in so we can finally lint for invalid escapes

Resolving patch:
diff --git a/statsmodels/stats/_adnorm.py b/statsmodels/stats/_adnorm.py
--- a/statsmodels/stats/_adnorm.py
+++ b/statsmodels/stats/_adnorm.py
@@ -8,9 +8,12 @@
 import numpy as np
 from scipy import stats
 
+from statsmodels.tools.validation import array_like, bool_like, int_like
+
 
 def anderson_statistic(x, dist='norm', fit=True, params=(), axis=0):
-    '''calculate anderson-darling A2 statistic
+    """
+    Calculate the Anderson-Darling a2 statistic
 
     Parameters
     ----------
@@ -29,46 +32,50 @@ def anderson_statistic(x, dist='norm', fit=True, params=(), axis=0):
 
     Returns
     -------
-    ad2 : float or ndarray
+    ad2 : {float, ndarray}
         Anderson-Darling statistic
-
-
-    '''
-    x = np.asarray(x)
+    """
+    x = array_like(x, 'x', ndim=None)
+    fit = bool_like(fit, 'fit')
+    axis = int_like(axis, 'axis')
     y = np.sort(x, axis=axis)
-    N = y.shape[axis]
+    nobs = y.shape[axis]
     if fit:
         if dist == 'norm':
             xbar = np.expand_dims(np.mean(x, axis=axis), axis)
             s = np.expand_dims(np.std(x, ddof=1, axis=axis), axis)
-            w = (y-xbar)/s
+            w = (y - xbar) / s
             z = stats.norm.cdf(w)
-            #print z
+            # print z
         elif callable(dist):
             params = dist.fit(x)
-            #print params
+            # print params
             z = dist.cdf(y, *params)
             print(z)
+        else:
+            raise ValueError("dist must be 'norm' or a Callable")
     else:
         if callable(dist):
             z = dist.cdf(y, *params)
         else:
-            raise ValueError('if fit is false, then dist needs to be callable')
+            raise ValueError('if fit is false, then dist must be callable')
 
-    i = np.arange(1,N+1)
-    sl1 = [None]*x.ndim
+    i = np.arange(1, nobs + 1)
+    sl1 = [None] * x.ndim
     sl1[axis] = slice(None)
     sl1 = tuple(sl1)
-    sl2 = [slice(None)]*x.ndim
-    sl2[axis] = slice(None,None,-1)
+    sl2 = [slice(None)] * x.ndim
+    sl2[axis] = slice(None, None, -1)
     sl2 = tuple(sl2)
-    S = np.sum((2*i[sl1]-1.0)/N*(np.log(z)+np.log(1-z[sl2])), axis=axis)
-    A2 = -N-S
-    return A2
+    S = np.sum((2 * i[sl1] - 1.0) / nobs * (np.log(z) + np.log(1 - z[sl2])),
+               axis=axis)
+    a2 = -nobs - S
+    return a2
 
 
 def normal_ad(x, axis=0):
-    '''Anderson-Darling test for normal distribution unknown mean and variance
+    """
+    Anderson-Darling test for normal distribution unknown mean and variance
 
     Parameters
     ----------
@@ -82,39 +89,40 @@ def normal_ad(x, axis=0):
     pval : float
         pvalue for hypothesis that the data comes from a normal distribution
         with unknown mean and variance
-
-    '''
-    #ad2 = stats.anderson(x)[0]
+    """
+    # ad2 = stats.anderson(x)[0]
     ad2 = anderson_statistic(x, dist='norm', fit=True, axis=axis)
     n = x.shape[axis]
 
-    ad2a = ad2 * (1 + 0.75/n + 2.25/n**2)
+    ad2a = ad2 * (1 + 0.75 / n + 2.25 / n ** 2)
 
     if np.size(ad2a) == 1:
         if (ad2a >= 0.00 and ad2a < 0.200):
-            pval = 1 - np.exp(-13.436 + 101.14 * ad2a - 223.73 * ad2a**2)
+            pval = 1 - np.exp(-13.436 + 101.14 * ad2a - 223.73 * ad2a ** 2)
         elif ad2a < 0.340:
-            pval = 1 - np.exp(-8.318 + 42.796 * ad2a - 59.938 * ad2a**2)
+            pval = 1 - np.exp(-8.318 + 42.796 * ad2a - 59.938 * ad2a ** 2)
         elif ad2a < 0.600:
-            pval = np.exp(0.9177 - 4.279 * ad2a - 1.38 * ad2a**2)
+            pval = np.exp(0.9177 - 4.279 * ad2a - 1.38 * ad2a ** 2)
         elif ad2a <= 13:
-            pval = np.exp(1.2937 - 5.709 * ad2a + 0.0186 * ad2a**2)
+            pval = np.exp(1.2937 - 5.709 * ad2a + 0.0186 * ad2a ** 2)
         else:
             pval = 0.0  # is < 4.9542108058458799e-31
 
     else:
         bounds = np.array([0.0, 0.200, 0.340, 0.600])
 
-        pval0 = lambda ad2a: np.nan*np.ones_like(ad2a)
-        pval1 = lambda ad2a: 1 - np.exp(-13.436 + 101.14 * ad2a - 223.73 * ad2a**2)
-        pval2 = lambda ad2a: 1 - np.exp(-8.318 + 42.796 * ad2a - 59.938 * ad2a**2)
-        pval3 = lambda ad2a: np.exp(0.9177 - 4.279 * ad2a - 1.38 * ad2a**2)
-        pval4 = lambda ad2a: np.exp(1.2937 - 5.709 * ad2a + 0.0186 * ad2a**2)
+        pval0 = lambda ad2a: np.nan * np.ones_like(ad2a)
+        pval1 = lambda ad2a: 1 - np.exp(
+            -13.436 + 101.14 * ad2a - 223.73 * ad2a ** 2)
+        pval2 = lambda ad2a: 1 - np.exp(
+            -8.318 + 42.796 * ad2a - 59.938 * ad2a ** 2)
+        pval3 = lambda ad2a: np.exp(0.9177 - 4.279 * ad2a - 1.38 * ad2a ** 2)
+        pval4 = lambda ad2a: np.exp(1.2937 - 5.709 * ad2a + 0.0186 * ad2a ** 2)
 
         pvalli = [pval0, pval1, pval2, pval3, pval4]
 
         idx = np.searchsorted(bounds, ad2a, side='right')
-        pval = np.nan*np.ones_like(ad2a)
+        pval = np.nan * np.ones_like(ad2a)
         for i in range(5):
             mask = (idx == i)
             pval[mask] = pvalli[i](ad2a[mask])
@@ -123,13 +131,15 @@ def normal_ad(x, axis=0):
 
 
 if __name__ == '__main__':
-    x = np.array([-0.1184, -1.3403,  0.0063, -0.612 , -0.3869, -0.2313, -2.8485,
-           -0.2167,  0.4153,  1.8492, -0.3706,  0.9726, -0.1501, -0.0337,
-           -1.4423,  1.2489,  0.9182, -0.2331, -0.6182,  0.183 ])
+    x = np.array([-0.1184, -1.3403, 0.0063, -0.612, -0.3869, -0.2313,
+                  -2.8485, -0.2167, 0.4153, 1.8492, -0.3706, 0.9726,
+                  -0.1501, -0.0337, -1.4423, 1.2489, 0.9182, -0.2331,
+                  -0.6182, 0.1830])
     r_res = np.array([0.58672353588821502, 0.1115380760041617])
     ad2, pval = normal_ad(x)
     print(ad2, pval)
     print(r_res - [ad2, pval])
 
-    print(anderson_statistic((x-x.mean())/x.std(), dist=stats.norm, fit=0))
+    print(anderson_statistic((x - x.mean()) / x.std(), dist=stats.norm,
+                             fit=False))
     print(anderson_statistic(x, dist=stats.norm, fit=True))
diff --git a/statsmodels/tsa/arima_process.py b/statsmodels/tsa/arima_process.py
--- a/statsmodels/tsa/arima_process.py
+++ b/statsmodels/tsa/arima_process.py
@@ -646,7 +646,8 @@ class ArmaProcess(object):
     ----------
     ar : array_like
         Coefficient for autoregressive lag polynomial, including zero lag.
-        See the notes for some information about the sign.
+        Must be entered using the signs from the lag polynomial representation.
+        See the notes for more information about the sign.
     ma : array_like
         Coefficient for moving-average lag polynomial, including zero lag.
     nobs : int, optional
@@ -674,10 +675,13 @@ class ArmaProcess(object):
     .. math::
 
         \left(1-\phi_{1}L-\ldots-\phi_{p}L^{p}\right)y_{t} =
-            \left(1-\theta_{1}L-\ldots-\theta_{q}L^{q}\right)
+            \left(1+\theta_{1}L+\ldots+\theta_{q}L^{q}\right)\epsilon_{t}
 
     Examples
     --------
+    ARMA(2,2) with AR coefficients 0.75 and -0.25, and MA coefficients 0.65 and 0.35
+
+    >>> import statsmodels.api as sm
     >>> import numpy as np
     >>> np.random.seed(12345)
     >>> arparams = np.array([.75, -.25])
@@ -689,10 +693,18 @@ class ArmaProcess(object):
     True
     >>> arma_process.isinvertible
     True
+    >>> arma_process.arroots
+    array([1.5-1.32287566j, 1.5+1.32287566j])
     >>> y = arma_process.generate_sample(250)
     >>> model = sm.tsa.ARMA(y, (2, 2)).fit(trend='nc', disp=0)
     >>> model.params
     array([ 0.79044189, -0.23140636,  0.70072904,  0.40608028])
+
+    The same ARMA(2,2) Using the from_coeffs class method
+
+    >>> arma_process = sm.tsa.ArmaProcess.from_coeffs(arparams, maparams)
+    >>> arma_process.arroots
+    array([1.5-1.32287566j, 1.5+1.32287566j])
     """
 
     # TODO: Check unit root behavior
diff --git a/statsmodels/tsa/statespace/sarimax.py b/statsmodels/tsa/statespace/sarimax.py
--- a/statsmodels/tsa/statespace/sarimax.py
+++ b/statsmodels/tsa/statespace/sarimax.py
@@ -949,7 +949,7 @@ def start_params(self):
             warning_description='ARMA and trend')
 
         # If we have estimated non-stationary start parameters but enforce
-        # stationarity is on, raise an error
+        # stationarity is on, start with 0 parameters and warn
         invalid_ar = (
             self.k_ar > 0 and
             self.enforce_stationarity and
@@ -980,7 +980,7 @@ def start_params(self):
                 warning_description='seasonal ARMA'))
 
         # If we have estimated non-stationary start parameters but enforce
-        # stationarity is on, raise an error
+        # stationarity is on, warn and set start params to 0
         invalid_seasonal_ar = (
             self.k_seasonal_ar > 0 and
             self.enforce_stationarity and


Test patch: