Repository: statsmodels/statsmodels

Issue:
BUG/ENH: StratifiedTable.test_null_odds fails with integer data 
example from meta-analysis PR

`st = smstats.StratifiedTable(ctables.astype(np.float64))`

without converting to float, data is int64 and raises the following exception in summary and test_null_odds()

test_equal_odds() works correctly with integers

```
st.summary()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-49-bf722b7cb8e1> in <module>
----> 1 st.summary()

...\statsmodels\stats\contingency_tables.py in summary(self, alpha, float_format, method)
   1270         headers = ["Statistic", "P-value", ""]
   1271         stubs = ["Test of OR=1", "Test constant OR"]
-> 1272         rslt1 = self.test_null_odds()
   1273         rslt2 = self.test_equal_odds()
   1274         data = [[fmt(x) for x in [rslt1.statistic, rslt1.pvalue, ""]],

...\statsmodels\stats\contingency_tables.py in test_null_odds(self, correction)
   1045         statistic = statistic**2
   1046         denom = self._apb * self._apc * self._bpd * self._cpd
-> 1047         denom /= (self._n**2 * (self._n - 1))
   1048         denom = np.sum(denom)
   1049         statistic /= denom

TypeError: No loop matching the specified signature and casting
was found for ufunc true_divide
```


Discussion:
aside: the hypothesis test methods could have a better repr,
Also it could use a generic Bunch instance, e.g. from stats testing tools (to which I added repr and str in my meta-analysis PR, AFAIR, not yet merged )

I get this in notebook

```
st.test_null_odds()
<bunch containing results, print to see contents>
```
checking this again.
The unit tests use list of int arrays which do not raise.
If I provide tables as an np.array with dtype int, then it raises.

The path for non arrays, forces float64: `table = np.dstack(tables).astype(np.float64)`


Resolving patch:
diff --git a/statsmodels/stats/contingency_tables.py b/statsmodels/stats/contingency_tables.py
--- a/statsmodels/stats/contingency_tables.py
+++ b/statsmodels/stats/contingency_tables.py
@@ -939,7 +939,7 @@ def __init__(self, tables, shift_zeros=False):
             sp = tables.shape
             if (len(sp) != 3) or (sp[0] != 2) or (sp[1] != 2):
                 raise ValueError("If an ndarray, argument must be 2x2xn")
-            table = tables
+            table = tables * 1.  # use atleast float dtype
         else:
             if any([np.asarray(x).shape != (2, 2) for x in tables]):
                 m = "If `tables` is a list, all of its elements should be 2x2"


Test patch:
diff --git a/statsmodels/stats/tests/test_contingency_tables.py b/statsmodels/stats/tests/test_contingency_tables.py
--- a/statsmodels/stats/tests/test_contingency_tables.py
+++ b/statsmodels/stats/tests/test_contingency_tables.py
@@ -2,11 +2,13 @@
 Tests for contingency table analyses.
 """
 
+import os
+import warnings
+
 import numpy as np
 import statsmodels.stats.contingency_tables as ctab
 import pandas as pd
 from numpy.testing import assert_allclose, assert_equal
-import os
 import statsmodels.api as sm
 
 cur_dir = os.path.dirname(os.path.abspath(__file__))
@@ -324,8 +326,9 @@ def test_cochranq():
 class CheckStratifiedMixin(object):
 
     @classmethod
-    def initialize(cls, tables):
-        cls.rslt = ctab.StratifiedTable(tables)
+    def initialize(cls, tables, use_arr=False):
+        tables1 = tables if not use_arr else np.dstack(tables)
+        cls.rslt = ctab.StratifiedTable(tables1)
         cls.rslt_0 = ctab.StratifiedTable(tables, shift_zeros=True)
         tables_pandas = [pd.DataFrame(x) for x in tables]
         cls.rslt_pandas = ctab.StratifiedTable(tables_pandas)
@@ -377,8 +380,10 @@ def test_equal_odds(self):
 
     def test_pandas(self):
 
-        assert_equal(self.rslt.summary().as_text(),
-                     self.rslt_pandas.summary().as_text())
+        with warnings.catch_warnings():
+            warnings.simplefilter("ignore", RuntimeWarning)
+            assert_equal(self.rslt.summary().as_text(),
+                         self.rslt_pandas.summary().as_text())
 
 
     def test_from_data(self):
@@ -453,7 +458,8 @@ def setup_class(cls):
         tables[3] = np.array([[12, 3], [7, 5]])
         tables[4] = np.array([[1, 0], [3, 2]])
 
-        cls.initialize(tables)
+        # check array of int
+        cls.initialize(tables, use_arr=True)
 
         cls.oddsratio_pooled = 3.5912
         cls.logodds_pooled = np.log(3.5912)