Repository: statsmodels/statsmodels

Issue:
Poisson predict breaks on list
running an example with Poisson
`mod = sm.Poisson(count, ex)`

```
>>> res.predict(exog=[1, 1, 0, 0], linear=False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "e:\josef\eclipsegworkspace\statsmodels-git\statsmodels-all-new2\statsmodels\statsmodels\base\model.py", line 880, in predict
    return self.model.predict(self.params, exog, *args, **kwargs)
  File "e:\josef\eclipsegworkspace\statsmodels-git\statsmodels-all-new2\statsmodels\statsmodels\discrete\discrete_model.py", line 682, in predict
    return np.exp(np.dot(exog, params[:exog.shape[1]]) + exposure + offset) # not cdf
AttributeError: 'list' object has no attribute 'shape'
```



Discussion:

Resolving patch:
diff --git a/statsmodels/base/model.py b/statsmodels/base/model.py
--- a/statsmodels/base/model.py
+++ b/statsmodels/base/model.py
@@ -995,6 +995,14 @@ def predict(self, exog=None, transform=True, *args, **kwargs):
             from patsy import dmatrix
             exog = dmatrix(self.model.data.orig_exog.design_info.builder,
                     exog)
+
+        if exog is not None:
+            exog = np.asarray(exog)
+            if exog.ndim == 1 and (self.model.exog.ndim == 1 or
+                                   self.model.exog.shape[1] == 1):
+                exog = exog[:, None]
+            exog = np.atleast_2d(exog) # needed in count model shape[1]
+
         return self.model.predict(self.params, exog, *args, **kwargs)
 
 


Test patch:
diff --git a/statsmodels/base/tests/test_generic_methods.py b/statsmodels/base/tests/test_generic_methods.py
--- a/statsmodels/base/tests/test_generic_methods.py
+++ b/statsmodels/base/tests/test_generic_methods.py
@@ -50,8 +50,9 @@ def test_ttest_tvalues(self):
         tt = res.t_test(mat)
 
         assert_allclose(tt.effect, res.params, rtol=1e-12)
-        assert_allclose(tt.sd, res.bse, rtol=1e-10)
-        assert_allclose(tt.tvalue, res.tvalues, rtol=1e-12)
+        # TODO: tt.sd and tt.tvalue are 2d also for single regressor, squeeze
+        assert_allclose(np.squeeze(tt.sd), res.bse, rtol=1e-10)
+        assert_allclose(np.squeeze(tt.tvalue), res.tvalues, rtol=1e-12)
         assert_allclose(tt.pvalue, res.pvalues, rtol=5e-10)
         assert_allclose(tt.conf_int(), res.conf_int(), rtol=1e-10)
 
@@ -99,6 +100,39 @@ def test_fitted(self):
         assert_allclose(res.model.endog - fitted, res.resid, rtol=1e-12)
         assert_allclose(fitted, res.predict(), rtol=1e-12)
 
+    def test_predict_types(self):
+        res = self.results
+        # squeeze to make 1d for single regressor test case
+        p_exog = np.squeeze(np.asarray(res.model.exog[:2]))
+
+        # ignore wrapper for isinstance check
+        from statsmodels.genmod.generalized_linear_model import GLMResults
+        from statsmodels.discrete.discrete_model import DiscreteResults
+        results = self.results._results
+        if (isinstance(results, GLMResults) or
+            isinstance(results, DiscreteResults)):
+            # SMOKE test only  TODO
+            res.predict(p_exog)
+            res.predict(p_exog.tolist())
+            res.predict(p_exog[0].tolist())
+        else:
+            fitted = res.fittedvalues[:2]
+            assert_allclose(fitted, res.predict(p_exog), rtol=1e-12)
+            # this needs reshape to column-vector:
+            assert_allclose(fitted, res.predict(np.squeeze(p_exog).tolist()),
+                            rtol=1e-12)
+            # only one prediction:
+            assert_allclose(fitted[:1], res.predict(p_exog[0].tolist()),
+                            rtol=1e-12)
+            assert_allclose(fitted[:1], res.predict(p_exog[0]),
+                            rtol=1e-12)
+
+            # predict doesn't preserve DataFrame, e.g. dot converts to ndarray
+#             import pandas
+#             predicted = res.predict(pandas.DataFrame(p_exog))
+#             assert_(isinstance(predicted, pandas.DataFrame))
+#             assert_allclose(predicted, fitted, rtol=1e-12)
+
 
 #########  subclasses for individual models, unchanged from test_shrink_pickle
 # TODO: check if setup_class is faster than setup
@@ -113,6 +147,17 @@ def setup(self):
         self.results = sm.OLS(y, self.exog).fit()
 
 
+class TestGenericOLSOneExog(CheckGenericMixin):
+    # check with single regressor (no constant)
+
+    def setup(self):
+        #fit for each test, because results will be changed by test
+        x = self.exog[:, 1]
+        np.random.seed(987689)
+        y = x + np.random.randn(x.shape[0])
+        self.results = sm.OLS(y, x).fit()
+
+
 class TestGenericWLS(CheckGenericMixin):
 
     def setup(self):
@@ -147,7 +192,12 @@ def setup(self):
         data = sm.datasets.randhie.load()
         exog = sm.add_constant(data.exog, prepend=False)
         mod = sm.NegativeBinomial(data.endog, data.exog)
-        self.results = mod.fit(disp=0)
+        start_params = np.array([-0.0565406 , -0.21213599,  0.08783076,
+                                 -0.02991835,  0.22901974,  0.0621026,
+                                  0.06799283,  0.08406688,  0.18530969,
+                                  1.36645452])
+        self.results = mod.fit(start_params=start_params, disp=0)
+
 
 class TestGenericLogit(CheckGenericMixin):