Repository: statsmodels/statsmodels

Issue:
Cannot cast ufunc subtract output from dtype('float64') to dtype('int64') with casting rule 'same_kind'
# Summary
It seems that statsmodels should do some explicitly conversion, while it is not.

# Error Trace
In lastest statsmodels, there are an error when using ARIMA

```
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-51-964a74d33f5a> in <module>()
      5 
      6 model = sm.tsa.arima_model.ARIMA(ts, order=(0, 2, 0))
----> 7 fitted = model.fit(disp=-1)
      8 
      9 

/usr/local/lib/python3.5/dist-packages/statsmodels/tsa/arima_model.py in fit(self, start_params, trend, method, transparams, solver, maxiter, full_output, disp, callback, start_ar_lags, **kwargs)
   1149                                            method, transparams, solver,
   1150                                            maxiter, full_output, disp,
-> 1151                                            callback, start_ar_lags, **kwargs)
   1152         normalized_cov_params = None  # TODO: fix this?
   1153         arima_fit = ARIMAResults(self, mlefit._results.params,

/usr/local/lib/python3.5/dist-packages/statsmodels/tsa/arima_model.py in fit(self, start_params, trend, method, transparams, solver, maxiter, full_output, disp, callback, start_ar_lags, **kwargs)
    954         else:  # estimate starting parameters
    955             start_params = self._fit_start_params((k_ar, k_ma, k), method,
--> 956                                                   start_ar_lags)
    957 
    958         if transparams:  # transform initial parameters to ensure invertibility

/usr/local/lib/python3.5/dist-packages/statsmodels/tsa/arima_model.py in _fit_start_params(self, order, method, start_ar_lags)
    572     def _fit_start_params(self, order, method, start_ar_lags=None):
    573         if method != 'css-mle':  # use Hannan-Rissanen to get start params
--> 574             start_params = self._fit_start_params_hr(order, start_ar_lags)
    575         else:  # use CSS to get start params
    576             func = lambda params: -self.loglike_css(params)

/usr/local/lib/python3.5/dist-packages/statsmodels/tsa/arima_model.py in _fit_start_params_hr(self, order, start_ar_lags)
    506             ols_params = GLS(endog, exog).fit().params
    507             start_params[:k] = ols_params
--> 508             endog -= np.dot(exog, ols_params).squeeze()
    509         if q != 0:
    510             if p != 0:

TypeError: Cannot cast ufunc subtract output from dtype('float64') to dtype('int64') with casting rule 'same_kind'

```

# Environment:
- Python: 3.5.2
- Statsmodels: 0.8.0


# Step to reproduce the issue:

## Data Prepare:
Use the data from: https://www.analyticsvidhya.com/wp-content/uploads/2016/02/AirPassengers.csv

## Code
```python

import pandas as pd
import statsmodels as sm

dateparse = lambda dates: pd.datetime.strptime(dates, '%Y-%m')
data = pd.read_csv('data/AirPassengers.csv', parse_dates=['Month'], index_col='Month',date_parser=dateparse)
ts = data['#Passengers']

model = sm.tsa.arima_model.ARIMA(ts, order=(0, 2, 0))
fitted = model.fit(disp=-1)

```




Discussion:
does it work if ts is converted to float, np.float64?

Looks like a missing cast to float of endog if ts is integer.

@josef-pkt 

If I try to convert data to float, statsmodels will work well. 
But maybe the statsmodels need to be improved by adding that conversion.

Yes, that's a bug, thanks for the report

endog conversion is model specific, so this is not handled by the generic data handling, and needs to be added to ARMA/ARIMA directly.
Glad to help : )
I am getting this same error..
can you please post the revised code.

It may be a numpy/broadcasting issue in python, came across a similar problem in Week 2 assignment forum of Andrew Ng's MOOC on Deep Learning:

Regarding some optimization function:
"it returns correct results if I use w = w - a*b, but it returns the following error if I do w -= a*b: TypeError: Cannot cast ufunc subtract output from dtype('float64') to dtype('int64') with casting rule 'same_kind'

I defined all variables as float and have no idea why "-=" wouldn't work. Interestingly, it would also work if I use np.add function by setting casting to "unsafe". Very odd."

The workaround is to use np.add(with "casting=unsafe" argument), stack overflow showed a similar problem with multiplication (similar workaround to use np.multiply(etc.)). Though this slows the code down.

Resolving patch:
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
@@ -21,7 +21,7 @@
                                           resettable_cache)
 import statsmodels.tsa.base.tsa_model as tsbase
 import statsmodels.base.wrapper as wrap
-from statsmodels.regression.linear_model import yule_walker, GLS
+from statsmodels.regression.linear_model import yule_walker, OLS
 from statsmodels.tsa.tsatools import (lagmat, add_trend,
                                       _ar_transparams, _ar_invtransparams,
                                       _ma_transparams, _ma_invtransparams,
@@ -483,10 +483,11 @@ def _fit_start_params_hr(self, order, start_ar_lags=None):
         """
         p, q, k = order
         start_params = zeros((p+q+k))
-        endog = self.endog.copy()  # copy because overwritten
+        # make copy of endog because overwritten
+        endog = np.array(self.endog, np.float64)
         exog = self.exog
         if k != 0:
-            ols_params = GLS(endog, exog).fit().params
+            ols_params = OLS(endog, exog).fit().params
             start_params[:k] = ols_params
             endog -= np.dot(exog, ols_params).squeeze()
         if q != 0:
@@ -526,7 +527,7 @@ def _fit_start_params_hr(self, order, start_ar_lags=None):
                 lag_resid = lagmat(resid, q, 'both')[resid_start:]
                 # stack ar lags and resids
                 X = np.column_stack((lag_endog, lag_resid))
-                coefs = GLS(endog[max(p_tmp + q, p):], X).fit().params
+                coefs = OLS(endog[max(p_tmp + q, p):], X).fit().params
                 start_params[k:k+p+q] = coefs
             else:
                 start_params[k+p:k+p+q] = yule_walker(endog, order=q)[0]


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
@@ -17,7 +17,7 @@
 import statsmodels.sandbox.tsa.fftarma as fa
 from statsmodels.tools.testing import assert_equal
 from statsmodels.tsa.arma_mle import Arma
-from statsmodels.tsa.arima_model import ARMA, ARIMA
+from statsmodels.tsa.arima_model import AR, ARMA, ARIMA
 from statsmodels.regression.linear_model import OLS
 from statsmodels.tsa.tests.results import results_arma, results_arima
 from statsmodels.tsa.arima_process import arma_generate_sample
@@ -2344,6 +2344,24 @@ def test_arima_not_implemented():
     assert_raises(NotImplementedError, ARIMA.from_formula, formula, data)
 
 
-if __name__ == "__main__":
-    import pytest
-    pytest.main([__file__, '-vvs', '-x', '--pdb'])
+def test_endog_int():
+    # int endog should produce same result as float, #3504
+
+    np.random.seed(123987)
+    y = np.random.random_integers(0, 15, size=100)
+    yf = y.astype(np.float64)
+
+    res = AR(y).fit(5)
+    resf = AR(yf).fit(5)
+    assert_allclose(res.params, resf.params, atol=1e-6)
+    assert_allclose(res.bse, resf.bse, atol=1e-6)
+
+    res = ARMA(y, order=(2, 1)).fit(disp=0)
+    resf = ARMA(yf, order=(2, 1)).fit(disp=0)
+    assert_allclose(res.params, resf.params, atol=1e-6)
+    assert_allclose(res.bse, resf.bse, atol=1e-6)
+
+    res = ARIMA(y.cumsum(), order=(1,1,1)).fit(disp=0)
+    resf = ARIMA(yf.cumsum(), order=(1,1,1)).fit(disp=0)
+    assert_allclose(res.params, resf.params, atol=1e-6)
+    assert_allclose(res.bse, resf.bse, atol=1e-6)