Repository: statsmodels/statsmodels

Issue:
arma_order_select_ic function throw "IndexError: index 0 is out of bounds for axis 0 with size 0"
Hi, I got a problem when I run the code `sm.tsa.arma_order_select_ic(ts,max_ar=6,max_ma=4,ic='aic')['aic_min_order']  # AIC` with my dataset. 

The problem showed below: 
```
~/anaconda3/lib/python3.6/site-packages/statsmodels/tsa/stattools.py in arma_order_select_ic(y, max_ar, max_ma, ic, trend, model_kw, fit_kw)
   1149     for i, result in iteritems(res):
   1150         mins = np.where(result.min().min() == result)
-> 1151         min_res.update({i + '_min_order' : (mins[0][0], mins[1][0])})
   1152     res.update(min_res)
   1153 

IndexError: index 0 is out of bounds for axis 0 with size 0
```

However, I just cannot figure what is going on. And When I run the sample code, there is no problem. So what caused this problem? Is there something wrong with my dataset?


Discussion:
For `ts`, after run `ts.tail()`, the printed information is:
```
index
20174332     98.437500
20174333    101.250000
20174334     98.703125
20174335     99.812500
20174336    100.328125
Name: pm25, dtype: float64
```
which version of pandas are you using?

Can you use pdb to check what `result` and `mins` is?
Result is a pandas.DataFrame, but I don't see why `mins` should be empty or not a tuple.

i.e. somthing like

```
result = pd.DataFrame(np.arange(12).reshape(4, 3))

np.where(result.min().min() == result)
Out[19]: (array([0], dtype=int64), array([0], dtype=int64))
```
unless all results are nan
```
result = pd.DataFrame(np.nan * np.arange(12).reshape(4, 3))
np.where(result.min().min() == result)
Out[21]: (array([], dtype=int64), array([], dtype=int64))

np.where(result.min().min() == result)[0][0]
Traceback (most recent call last):

  File "<ipython-input-23-83c722093758>", line 1, in <module>
    np.where(result.min().min() == result)[0][0]

IndexError: index 0 is out of bounds for axis 0 with size 0
```
Hi, josef-pkt, thanks very much for your response. I just find the error is because the parameter that arma_order_select_ic need to be `numpy.ndarray`. However, the `ts` is `Series` type. 

So when I changed the code to `sm.tsa.arma_order_select_ic(ts.values,max_ar=6,max_ma=4,ic='aic')['aic_min_order'] # AIC`. Everything is fine. Thanks again~
I added bug label

There is something strange
y goes directly into ARIMA, so it should be fine.
Most likely there is something in the results wrapper that changes things,
in many other cases we get the `_results` below the results wrapper for further computation.
However, AFAICS only the `ic` are taken from the results instance.

Whatever the reason, we don't need pandas in the order search, so we can just put an np.asarray into arma_order_select_ic

Resolving patch:
diff --git a/statsmodels/tsa/stattools.py b/statsmodels/tsa/stattools.py
--- a/statsmodels/tsa/stattools.py
+++ b/statsmodels/tsa/stattools.py
@@ -1,22 +1,20 @@
 """
 Statistical tools for time series analysis
 """
-from statsmodels.compat.python import (iteritems, range, lrange, string_types,
-                                       lzip, zip, long)
-from statsmodels.compat.scipy import _next_regular
-
 import numpy as np
 from numpy.linalg import LinAlgError
 from scipy import stats
 
+from statsmodels.compat.python import (iteritems, range, lrange, string_types,
+                                       lzip, zip, long)
+from statsmodels.compat.scipy import _next_regular
 from statsmodels.regression.linear_model import OLS, yule_walker
+from statsmodels.tools.sm_exceptions import InterpolationWarning, MissingDataError
 from statsmodels.tools.tools import add_constant, Bunch
-from statsmodels.tsa.tsatools import lagmat, lagmat2ds, add_trend
-from statsmodels.tsa.adfvalues import mackinnonp, mackinnoncrit
 from statsmodels.tsa._bds import bds
+from statsmodels.tsa.adfvalues import mackinnonp, mackinnoncrit
 from statsmodels.tsa.arima_model import ARMA
-from statsmodels.tools.sm_exceptions import InterpolationWarning, MissingDataError
-
+from statsmodels.tsa.tsatools import lagmat, lagmat2ds, add_trend
 
 __all__ = ['acovf', 'acf', 'pacf', 'pacf_yw', 'pacf_ols', 'ccovf', 'ccf',
            'periodogram', 'q_stat', 'coint', 'arma_order_select_ic',
@@ -1073,7 +1071,7 @@ def _safe_arma_fit(y, order, model_kw, trend, fit_kw, start_params=None):
 
 
 def arma_order_select_ic(y, max_ar=4, max_ma=2, ic='bic', trend='c',
-                         model_kw={}, fit_kw={}):
+                         model_kw=None, fit_kw=None):
     """
     Returns information criteria for many ARMA models
 
@@ -1139,14 +1137,16 @@ def arma_order_select_ic(y, max_ar=4, max_ma=2, ic='bic', trend='c',
         raise ValueError("Need a list or a tuple for ic if not a string.")
 
     results = np.zeros((len(ic), max_ar + 1, max_ma + 1))
-
+    model_kw = {} if model_kw is None else model_kw
+    fit_kw = {} if fit_kw is None else fit_kw
+    y_arr = np.asarray(y)
     for ar in ar_range:
         for ma in ma_range:
             if ar == 0 and ma == 0 and trend == 'nc':
                 results[:, ar, ma] = np.nan
                 continue
 
-            mod = _safe_arma_fit(y, (ar, ma), model_kw, trend, fit_kw)
+            mod = _safe_arma_fit(y_arr, (ar, ma), model_kw, trend, fit_kw)
             if mod is None:
                 results[:, ar, ma] = np.nan
                 continue
@@ -1162,7 +1162,7 @@ def arma_order_select_ic(y, max_ar=4, max_ma=2, ic='bic', trend='c',
     min_res = {}
     for i, result in iteritems(res):
         mins = np.where(result.min().min() == result)
-        min_res.update({i + '_min_order' : (mins[0][0], mins[1][0])})
+        min_res.update({i + '_min_order': (mins[0][0], mins[1][0])})
     res.update(min_res)
 
     return Bunch(**res)


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
@@ -18,6 +18,7 @@
                                        coint, acovf, kpss,
                                        arma_order_select_ic, levinson_durbin)
 
+
 DECIMAL_8 = 8
 DECIMAL_6 = 6
 DECIMAL_5 = 5
@@ -536,8 +537,8 @@ def test_arma_order_select_ic():
                       [ 517.61019619,  496.99650196,  499.52656493],
                       [ 498.12580329,  499.75598491,  504.99255506],
                       [ 499.49225249,  504.96650341,  510.48779255]])
-    aic = DataFrame(aic_x , index=lrange(5), columns=lrange(3))
-    bic = DataFrame(bic_x , index=lrange(5), columns=lrange(3))
+    aic = DataFrame(aic_x, index=lrange(5), columns=lrange(3))
+    bic = DataFrame(bic_x, index=lrange(5), columns=lrange(3))
     assert_almost_equal(res.aic.values, aic.values, 5)
     assert_almost_equal(res.bic.values, bic.values, 5)
     assert_equal(res.aic_min_order, (1, 2))
@@ -547,6 +548,15 @@ def test_arma_order_select_ic():
     assert_(res.bic.index.equals(bic.index))
     assert_(res.bic.columns.equals(bic.columns))
 
+    index = pd.date_range('2000-1-1', freq='M', periods=len(y))
+    y_series = pd.Series(y, index=index)
+    res_pd = arma_order_select_ic(y_series, max_ar=2, max_ma=1,
+                                  ic=['aic', 'bic'], trend='nc')
+    assert_almost_equal(res_pd.aic.values, aic.values[:3, :2], 5)
+    assert_almost_equal(res_pd.bic.values, bic.values[:3, :2], 5)
+    assert_equal(res_pd.aic_min_order, (2, 1))
+    assert_equal(res_pd.bic_min_order, (1, 1))
+
     res = arma_order_select_ic(y, ic='aic', trend='nc')
     assert_almost_equal(res.aic.values, aic.values, 5)
     assert_(res.aic.index.equals(aic.index))