Repository: statsmodels/statsmodels

Issue:
BUG/ENH: ARMA predict dynamic with 1d exog raises exception
see example in #2587

if dynamic is False, then there is not problem.
If dynamic is True, then `predict` has a concatenation error with 1d exog (pandas.Series)

BUG/ENH: ARMA predict dynamic with 1d exog raises exception
see example in #2587

if dynamic is False, then there is not problem.
If dynamic is True, then `predict` has a concatenation error with 1d exog (pandas.Series)



Discussion:

Resolving patch:
diff --git a/statsmodels/base/optimizer.py b/statsmodels/base/optimizer.py
--- a/statsmodels/base/optimizer.py
+++ b/statsmodels/base/optimizer.py
@@ -323,6 +323,7 @@ def _fit_lbfgs(f, score, start_params, fargs, kwargs, disp=True,
 
     # Use unconstrained optimization by default.
     bounds = kwargs.setdefault('bounds', [(None, None)] * len(start_params))
+    kwargs.setdefault('iprint', 0)
 
     # Pass the following keyword argument names through to fmin_l_bfgs_b
     # if they are present in kwargs, otherwise use the fmin_l_bfgs_b
diff --git a/statsmodels/tsa/arima_model.py b/statsmodels/tsa/arima_model.py
--- a/statsmodels/tsa/arima_model.py
+++ b/statsmodels/tsa/arima_model.py
@@ -725,11 +725,14 @@ def predict(self, params, start=None, end=None, exog=None, dynamic=False):
         resid = self.geterrors(params)
         k_ar = self.k_ar
 
-        if out_of_sample != 0 and self.k_exog > 0:
+        if exog is not None:
+            # Note: we ignore currently the index of exog if it is available
             exog = np.asarray(exog)
             if self.k_exog == 1 and exog.ndim == 1:
                 exog = exog[:, None]
-                # we need the last k_ar exog for the lag-polynomial
+
+        if out_of_sample != 0 and self.k_exog > 0:
+            # we need the last k_ar exog for the lag-polynomial
             if self.k_exog > 0 and k_ar > 0 and not dynamic:
                 # need the last k_ar exog for the lag-polynomial
                 exog = np.vstack((self.exog[-k_ar:, self.k_trend:], exog))
diff --git a/statsmodels/tsa/base/tsa_model.py b/statsmodels/tsa/base/tsa_model.py
--- a/statsmodels/tsa/base/tsa_model.py
+++ b/statsmodels/tsa/base/tsa_model.py
@@ -145,12 +145,18 @@ def _get_predict_end(self, end):
         dates = self.data.dates
         freq = self.data.freq
 
-        if isinstance(end, str):
+        if isinstance(end, str) or (dates is not None
+                                    and isinstance(end, type(dates[0]))):
             if dates is None:
-                raise ValueError("Got a string for end and dates is None")
-            try:
+                raise ValueError("Got a string or date for `end` and `dates` is None")
+
+            if isinstance(end, str):
                 dtend = self._str_to_date(end)
-                self.data.predict_end = dtend
+            else:
+                dtend = end  # end could be a pandas TimeStamp not a datetime
+
+            self.data.predict_end = dtend
+            try:
                 end = self._get_dates_loc(dates, dtend)
             except KeyError as err: # end is greater than dates[-1]...probably
                 if dtend > self.data.dates[-1]:
@@ -204,6 +210,9 @@ def _get_predict_end(self, end):
             raise ValueError("When freq is None, you must give an integer "
                              "index for end.")
 
+        else:
+            raise ValueError("no rule for interpreting end")
+
         return end, out_of_sample
 
     def _make_predict_dates(self):


Test patch:
diff --git a/statsmodels/tsa/tests/test_arima.py b/statsmodels/tsa/tests/test_arima.py
--- a/statsmodels/tsa/tests/test_arima.py
+++ b/statsmodels/tsa/tests/test_arima.py
@@ -1585,6 +1585,17 @@ def test_1dexog():
     with warnings.catch_warnings():
         warnings.simplefilter("ignore")
         mod = ARMA(endog, (1,1), exog).fit(disp=-1)
+        mod.predict(193, 203, exog[-10:])
+
+        # check for dynamic is true and pandas Series  see #2589
+        mod.predict(193, 202, exog[-10:], dynamic=True)
+
+        dta.index = pandas.Index(cpi_dates)
+        mod = ARMA(dta['realcons'], (1,1), dta['m1']).fit(disp=-1)
+        mod.predict(dta.index[-10], dta.index[-1], exog=dta['m1'][-10:], dynamic=True)
+
+        mod = ARMA(dta['realcons'], (1,1), dta['m1']).fit(trend='nc', disp=-1)
+        mod.predict(dta.index[-10], dta.index[-1], exog=dta['m1'][-10:], dynamic=True)
 
 
 def test_arima_predict_bug():
@@ -1595,6 +1606,17 @@ def test_arima_predict_bug():
     arma_mod20 = ARMA(dta, (2,0)).fit(disp=-1)
     arma_mod20.predict(None, None)
 
+    # test prediction with time stamp, see #2587
+    predict = arma_mod20.predict(dta.index[-20], dta.index[-1])
+    assert_(predict.index.equals(dta.index[-20:]))
+    predict = arma_mod20.predict(dta.index[-20], dta.index[-1], dynamic=True)
+    assert_(predict.index.equals(dta.index[-20:]))
+    # partially out of sample
+    predict_dates = pandas.Index(dates_from_range('2000', '2015'))
+    predict = arma_mod20.predict(predict_dates[0], predict_dates[-1])
+    assert_(predict.index.equals(predict_dates))
+    #assert_(1 == 0)
+
 
 def test_arima_predict_q2():
     # bug with q > 1 for arima predict
@@ -1685,7 +1707,6 @@ def test_arima_predict_exog():
     # check 626
     assert_(len(arma_res.model.exog_names) == 5)
 
-
     # exog for out-of-sample and in-sample dynamic
     predict = arma_res.model.predict(params, end=124, exog=X[100:])
     assert_almost_equal(predict, predict_expected.values, 6)
@@ -2223,9 +2244,9 @@ def test_arima_fit_mutliple_calls():
     mod = ARIMA(y, (1, 0, 2))
     # Make multiple calls to fit
     mod.fit(disp=0, start_params=[np.mean(y), .1, .1, .1])
-    assert_equal(mod.exog_names,  ['const', 'ar.L1.y', 'ma.L1.y', 'ma.L2.y']) 
+    assert_equal(mod.exog_names,  ['const', 'ar.L1.y', 'ma.L1.y', 'ma.L2.y'])
     mod.fit(disp=0, start_params=[np.mean(y), .1, .1, .1])
-    assert_equal(mod.exog_names,  ['const', 'ar.L1.y', 'ma.L1.y', 'ma.L2.y']) 
+    assert_equal(mod.exog_names,  ['const', 'ar.L1.y', 'ma.L1.y', 'ma.L2.y'])
 
 if __name__ == "__main__":
     import nose