Repository: statsmodels/statsmodels

Issue:
BUG: coint with colinear variables sets the wrong value to zero
based on a quick check for https://github.com/statsmodels/statsmodels/issues/4222#issuecomment-361267866 the results after the warning for the colinear case is wrong

I think #3414 should have set the p-value to zero and not the test statistic.





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
@@ -22,6 +22,7 @@
            'periodogram', 'q_stat', 'coint', 'arma_order_select_ic',
            'adfuller', 'kpss', 'bds']
 
+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.
@@ -979,6 +980,11 @@ def coint(y0, y1, trend='c', method='aeg', maxlag=None, autolag='aic',
     P-values and critical values are obtained through regression surface
     approximation from MacKinnon 1994 and 2010.
 
+    If the two series are almost perfectly collinear, then computing the
+    test is numerically unstable. However, the two series will be cointegrated
+    under the maintained assumption that they are integrated. In this case
+    the t-statistic will be set to -inf and the pvalue to zero.
+
     TODO: We could handle gaps in data by dropping rows with nans in the
     auxiliary regressions. Not implemented yet, currently assumes no nans
     and no gaps in time series.
@@ -1010,15 +1016,15 @@ def coint(y0, y1, trend='c', method='aeg', maxlag=None, autolag='aic',
 
     res_co = OLS(y0, xx).fit()
 
-    if res_co.rsquared < 1 - np.sqrt(np.finfo(np.double).eps):
+    if res_co.rsquared < 1 - 100 * SQRTEPS:
         res_adf = adfuller(res_co.resid, maxlag=maxlag, autolag=None,
                            regression='nc')
     else:
         import warnings
-        warnings.warn("y0 and y1 are perfectly colinear.  Cointegration test "
-                      "is not reliable in this case.")
+        warnings.warn("y0 and y1 are (almost) perfectly colinear."
+                      "Cointegration test is not reliable in this case.")
         # Edge case where series are too similar
-        res_adf = (0,)
+        res_adf = (-np.inf,)
 
     # no constant or trend, see egranger in Stata and MacKinnon
     if trend == 'nc':


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
@@ -359,23 +359,22 @@ def test_coint_identical_series():
     with warnings.catch_warnings(record=True) as w:
         c = coint(y, y, trend="c", maxlag=0, autolag=None)
     assert_equal(len(w), 1)
-    assert_equal(c[0], 0.0)
-    # Limit of table
-    assert_(c[1] > .98)
+    assert_equal(c[1], 0.0)
+    assert_(np.isneginf(c[0]))
 
 
 def test_coint_perfect_collinearity():
+    # test uses nearly perfect collinearity
     nobs = 200
     scale_e = 1
     np.random.seed(123)
     x = scale_e * np.random.randn(nobs, 2)
-    y = 1 + x.sum(axis=1)
+    y = 1 + x.sum(axis=1) + 1e-7 * np.random.randn(nobs)
     warnings.simplefilter('always', ColinearityWarning)
     with warnings.catch_warnings(record=True) as w:
         c = coint(y, x, trend="c", maxlag=0, autolag=None)
-    assert_equal(c[0], 0.0)
-    # Limit of table
-    assert_(c[1] > .98)
+    assert_equal(c[1], 0.0)
+    assert_(np.isneginf(c[0]))
 
 
 class TestGrangerCausality(object):