Repository: statsmodels/statsmodels

Issue:
No summary result output for AR in ar_model
Hi,

If I do:

from statsmodels.tsa.ar_model import AR

res  = AR(df[x]).fit(4)

I can't do for instance res.summary() to see a summary table with the coefficient values, tstatistics, and so on. But for ARIMA it works.



Discussion:

Resolving patch:
diff --git a/statsmodels/tsa/ar_model.py b/statsmodels/tsa/ar_model.py
--- a/statsmodels/tsa/ar_model.py
+++ b/statsmodels/tsa/ar_model.py
@@ -5,6 +5,8 @@
 from numpy import dot, identity
 from numpy.linalg import inv, slogdet
 from scipy.stats import norm
+
+from statsmodels.iolib.summary import Summary
 from statsmodels.regression.linear_model import OLS
 from statsmodels.tsa.tsatools import (lagmat, add_trend,
                                       _ar_transparams, _ar_invtransparams)
@@ -783,6 +785,17 @@ def roots(self):
         k = self.k_trend
         return np.roots(np.r_[1, -self.params[k:]]) ** -1
 
+    @cache_readonly
+    def arfreq(self):
+        r"""
+        Returns the frequency of the AR roots.
+
+        This is the solution, x, to z = abs(z)*exp(2j*np.pi*x) where z are the
+        roots.
+        """
+        z = self.roots
+        return np.arctan2(z.imag, z.real) / (2 * np.pi)
+
     @cache_readonly
     def fittedvalues(self):
         return self.model.predict(self.params)
@@ -797,6 +810,88 @@ def predict(self, start=None, end=None, dynamic=False):
     preddoc = AR.predict.__doc__.split('\n')
     predict.__doc__ = '\n'.join(preddoc[:5] + preddoc[7:])
 
+    def summary(self, alpha=.05):
+        """Summarize the Model
+
+        Parameters
+        ----------
+        alpha : float, optional
+            Significance level for the confidence intervals.
+
+        Returns
+        -------
+        smry : Summary instance
+            This holds the summary table and text, which can be printed or
+            converted to various output formats.
+
+        See Also
+        --------
+        statsmodels.iolib.summary.Summary
+        """
+        model = self.model
+        title = model.__class__.__name__ + ' Model Results'
+        method = model.method
+        # get sample
+        start = 0 if 'mle' in method else self.k_ar
+        if self.data.dates is not None:
+            dates = self.data.dates
+            sample = [dates[start].strftime('%m-%d-%Y')]
+            sample += ['- ' + dates[-1].strftime('%m-%d-%Y')]
+        else:
+            sample = str(start) + ' - ' + str(len(self.data.orig_endog))
+
+        k_ar = self.k_ar
+        order = '({0})'.format(k_ar)
+        dep_name = str(self.model.endog_names)
+        top_left = [('Dep. Variable:', dep_name),
+                    ('Model:', [model.__class__.__name__ + order]),
+                    ('Method:', [method]),
+                    ('Date:', None),
+                    ('Time:', None),
+                    ('Sample:', [sample[0]]),
+                    ('', [sample[1]])
+                    ]
+
+        top_right = [
+            ('No. Observations:', [str(len(self.model.endog))]),
+            ('Log Likelihood', ["%#5.3f" % self.llf]),
+            ('S.D. of innovations', ["%#5.3f" % self.sigma2 ** .5]),
+            ('AIC', ["%#5.3f" % self.aic]),
+            ('BIC', ["%#5.3f" % self.bic]),
+            ('HQIC', ["%#5.3f" % self.hqic])]
+
+        smry = Summary()
+        smry.add_table_2cols(self, gleft=top_left, gright=top_right,
+                             title=title)
+        smry.add_table_params(self, alpha=alpha, use_t=False)
+
+        # Make the roots table
+        from statsmodels.iolib.table import SimpleTable
+
+        if k_ar:
+            arstubs = ["AR.%d" % i for i in range(1, k_ar + 1)]
+            stubs = arstubs
+            roots = self.roots
+            freq = self.arfreq
+        else:  # AR(0) model
+            stubs = []
+        if len(stubs):  # not AR(0)
+            modulus = np.abs(roots)
+            data = np.column_stack((roots.real, roots.imag, modulus, freq))
+            roots_table = SimpleTable([('%17.4f' % row[0],
+                                        '%+17.4fj' % row[1],
+                                        '%17.4f' % row[2],
+                                        '%17.4f' % row[3]) for row in data],
+                                      headers=['            Real',
+                                               '         Imaginary',
+                                               '         Modulus',
+                                               '        Frequency'],
+                                      title="Roots",
+                                      stubs=stubs)
+
+            smry.tables.append(roots_table)
+        return smry
+
 
 class ARResultsWrapper(wrap.ResultsWrapper):
     _attrs = {}


Test patch:
diff --git a/statsmodels/tsa/tests/test_ar.py b/statsmodels/tsa/tests/test_ar.py
--- a/statsmodels/tsa/tests/test_ar.py
+++ b/statsmodels/tsa/tests/test_ar.py
@@ -1,18 +1,17 @@
 """
 Test AR Model
 """
-import statsmodels.api as sm
-from statsmodels.tsa.ar_model import AR
-from statsmodels.tsa.arima_model import ARMA
-from numpy.testing import (assert_almost_equal, assert_allclose, assert_)
-from statsmodels.tools.testing import assert_equal
-from .results import results_ar
-
-import pytest
 import numpy as np
 import numpy.testing as npt
+import pytest
+from numpy.testing import (assert_almost_equal, assert_allclose, assert_)
 from pandas import Series, Index, date_range, period_range
 
+import statsmodels.api as sm
+from statsmodels.tools.testing import assert_equal
+from statsmodels.tsa.ar_model import AR
+from statsmodels.tsa.arima_model import ARMA
+from .results import results_ar
 
 DECIMAL_6 = 6
 DECIMAL_5 = 5
@@ -45,6 +44,10 @@ def test_pickle(self):
         res_unpickled = self.res1.__class__.load(fh)
         assert type(res_unpickled) is type(self.res1)  # noqa: E721
 
+    @pytest.mark.smoke
+    def test_summary(self):
+        assert isinstance(self.res1.summary().as_text(), str)
+
 
 class TestAROLSConstant(CheckARMixin):
     """
@@ -363,6 +366,22 @@ def test_constant_column_trend():
     assert_allclose(pred, expected)
 
 
+def test_summary_corner():
+    data = sm.datasets.macrodata.load_pandas().data["cpi"].diff().dropna()
+    dates = period_range(start='1959Q1', periods=len(data), freq='Q')
+    data.index = dates
+    res = AR(data).fit(maxlag=4)
+    summ = res.summary().as_text()
+    assert 'AR(4)' in summ
+    assert 'L4.cpi' in summ
+    assert '03-31-1959' in summ
+    res = AR(data).fit(maxlag=0)
+    summ = res.summary().as_text()
+    assert 'const' in summ
+    assert 'AR(0)' in summ
+
+
+
 #TODO: likelihood for ARX model?
 #class TestAutolagARX(object):
 #    def setup(self):