Repository: statsmodels/statsmodels

Issue:
Request: Improved indication in OLS summary that R^2 is calculated differently for models with and without constant term
This is a minor feature request:

I suggest to improve the summary output for an OLS regression (and maybe elsewhere, if this applies (e.g. GLS?)). In particular, it should be indicated more clearly that the coefficient of determination R^2 is computed differently for a linear regression model WITH intercept than for model WITHOUT intercept. 

It took me a while to figure this out. The details are explained in [this thread](https://stats.stackexchange.com/questions/26176).

While it's possible that this is basic textbook knowledge, I'd definitely distinguish between R^2 and R0^2. However, the summary output of an OLS fit (see below for an example) gives no indication of such a difference.

This is problematic if unexperienced users (like me) compare models based on R^2 (or R^2 adjusted). Switching from a model without a constant term may increase R^2 drastically, which could be interpreted as an improvement by a naive user if she/he compares it to a model with constant term. 

More concretely, I would suggest (for a model WITHOUT intercept)

- to introduce an extra line `R0 squared` (R0^2) in the right column of the summary
- to add a comment at the bottom of the summary
- to still compute `R squared` (R^2) for a model without intercept (for better comparison with models that make use of an intercept, I consider R^2 a useful metric also for a model without constant term)
- to drop a note in the documentation
- to expose a property `r0squared` (or similar) in the object returned by OLS.fit

I hope you can follow my concerns. Let me know what you think! :)


```
                            OLS Regression Results
==============================================================================
Dep. Variable:           irregularity   R-squared:                       0.973
Model:                            OLS   Adj. R-squared:                  0.971
Method:                 Least Squares   F-statistic:                     762.1
Date:                Wed, 27 Mar 2019   Prob (F-statistic):           1.42e-97
Time:                        16:25:44   Log-Likelihood:                -566.47
No. Observations:                 134   AIC:                             1145.
Df Residuals:                     128   BIC:                             1162.
Df Model:                           6
Covariance Type:            nonrobust
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
prop1         92.7449      9.935      9.336      0.000      73.088     112.402
prop2         32.1069      6.596      4.867      0.000      19.055      45.159
prop3         28.2132      7.736      3.647      0.000      12.907      43.519
prop4          4.4903      9.531      0.471      0.638     -14.368      23.349
prop5        126.9571      5.759     22.046      0.000     115.563     138.352
prop6         45.6639      6.345      7.197      0.000      33.110      58.218
==============================================================================
Omnibus:                        3.998   Durbin-Watson:                   2.194
Prob(Omnibus):                  0.135   Jarque-Bera (JB):                4.049
Skew:                          -0.403   Prob(JB):                        0.132
Kurtosis:                       2.724   Cond. No.                         8.14
==============================================================================
```


Discussion:
The simplest first cut would be to add a note when a model doesn't include a constant that the R2 is uncentered. This is the correct R2 for a model w/o a constant since it is the only version that satisfies the sanity requirement that it is 0<=R2<=1 for both definitions of R2. 

After this, one could add two methods `rsquared_centered` and `rsquared_uncentered` (which are the correct names), and then `rsquared` would simply return the correct default for the model.

Finally, and I'm less clear this is a good idea, one could add R-squared (centered) to a summary when a model does not include a constant.  If a model includes a constant then I would not add R-squared (uncentered) since this measure makes no sense. 


Resolving patch:
diff --git a/statsmodels/regression/linear_model.py b/statsmodels/regression/linear_model.py
--- a/statsmodels/regression/linear_model.py
+++ b/statsmodels/regression/linear_model.py
@@ -2671,6 +2671,11 @@ def summary(self, yname=None, xname=None, title=None, alpha=.05):
 
         # add warnings/notes, added to text format only
         etext = []
+        if not self.k_constant:
+            etext.append(
+                "R² is computed without centering (uncentered) since the "
+                "model does not contain a constant."
+            )
         if hasattr(self, 'cov_type'):
             etext.append(self.cov_kwds['description'])
         if self.model.exog.shape[0] < self.model.exog.shape[1]:


Test patch:
diff --git a/statsmodels/regression/tests/test_regression.py b/statsmodels/regression/tests/test_regression.py
--- a/statsmodels/regression/tests/test_regression.py
+++ b/statsmodels/regression/tests/test_regression.py
@@ -1396,3 +1396,11 @@ def test_ols_constant(reset_randomstate):
         assert np.isnan(res.fvalue)
         assert np.isnan(res.f_pvalue)
     assert len(recording) == 0
+
+
+def test_summary_no_constant():
+    rs = np.random.RandomState(0)
+    x = rs.standard_normal((100,2))
+    y = rs.standard_normal(100)
+    summary = OLS(y, x).fit().summary()
+    assert "R² is computed " in summary.as_text()