Repository: statsmodels/statsmodels (Python)

Issue:
BUG: Check `freq` only when useful in forecasting.
#### Describe the bug

I'm getting above TypeError while executing line 23 (forcast()) even though my frequency is not 'str'. 

#### Code Sample, a copy-pastable example if possible


```python
from statsmodels.tsa.holtwinters import ExponentialSmoothing as HWES

#read the data file. the date column is expected to be in the mm-dd-yyyy format.
df_train_y = pd.DataFrame(data = tsne_train_output)
df_train_y.index.freq = 'd'

df_test_y = pd.DataFrame(data = tsne_test_output)
df_test_y.index.freq = 'd'

#plot the data
df_train_y.plot()
plt.show()


#build and train the model on the training data
model = HWES(df_train_y, seasonal_periods=144, trend='add', seasonal='add')
fitted = model.fit(optimized=True, use_brute=True)

#print out the training summary
print(fitted.summary())

#create an out of sample forcast for the next 12 steps beyond the final data point in the training data set
trend_forecast = fitted.forecast(steps= 157200)

#plot the training data, the test data and the forecast on the same plot
fig = plt.figure()
fig.suptitle('Actual #picups Vs Predicted #pickups')
past, = plt.plot(df_train_y.index, df_train_y, 'b.-', label='Actual #Pickups')
future, = plt.plot(df_test_y.index, df_test_y, 'r.-', label='Predicted #pickup')
predicted_future, = plt.plot(df_test_y.index, trend_forecast, 'g.-', label='#pickups forcasted')
plt.legend(handles=[past, future, predicted_future])
plt.show()
```

### Error Message 

```
TypeError                                 Traceback (most recent call last)
<ipython-input-153-3c04122733a1> in <module>()
     21 
     22 #create an out of sample forcast for the next 12 steps beyond the final data point in the training data set
---> 23 trend_forecast = fitted.forecast(steps= 157200)
     24 
     25 #plot the training data, the test data and the forecast on the same plot

1 frames
/usr/local/lib/python3.7/dist-packages/statsmodels/tsa/holtwinters.py in forecast(self, steps)
    344         try:
    345             freq = getattr(self.model._index, 'freq', 1)
--> 346             start = self.model._index[-1] + freq
    347             end = self.model._index[-1] + steps * freq
    348             return self.model.predict(self.params, start=start, end=end)

TypeError: unsupported operand type(s) for +: 'int' and 'str'

```

<details>

#### Expected Output

I would like to get forcast values in trend_forcast

#### Output of ``import statsmodels.api as sm; sm.show_versions()``

<details>

[paste the output of ``import statsmodels.api as sm; sm.show_versions()`` here below this line]


INSTALLED VERSIONS
------------------
Python: 3.7.10.final.0
OS: Linux 5.4.104+ #1 SMP Sat Jun 5 09:50:34 PDT 2021 x86_64
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8

Statsmodels
===========

Installed: 0.10.2 (/usr/local/lib/python3.7/dist-packages/statsmodels)

Required Dependencies
=====================

cython: 0.29.23 (/usr/local/lib/python3.7/dist-packages/Cython)
numpy: 1.19.5 (/usr/local/lib/python3.7/dist-packages/numpy)
scipy: 1.4.1 (/usr/local/lib/python3.7/dist-packages/scipy)
pandas: 1.1.5 (/usr/local/lib/python3.7/dist-packages/pandas)
    dateutil: 2.8.1 (/usr/local/lib/python3.7/dist-packages/dateutil)
patsy: 0.5.1 (/usr/local/lib/python3.7/dist-packages/patsy)

Optional Dependencies
=====================

matplotlib: 3.2.2 (/usr/local/lib/python3.7/dist-packages/matplotlib)
    backend: module://ipykernel.pylab.backend_inline 
cvxopt: 1.2.6 (/usr/local/lib/python3.7/dist-packages/cvxopt)
joblib: 1.0.1 (/usr/local/lib/python3.7/dist-packages/joblib)

Developer Tools
================

IPython: 5.5.0 (/usr/local/lib/python3.7/dist-packages/IPython)
    jinja2: 2.11.3 (/usr/local/lib/python3.7/dist-packages/jinja2)
sphinx: 1.8.5 (/usr/local/lib/python3.7/dist-packages/sphinx)
    pygments: 2.6.1 (/usr/local/lib/python3.7/dist-packages/pygments)
pytest: 3.6.4 (/usr/local/lib/python3.7/dist-packages)
virtualenv: Not installed

</details>



Discussion:
Running the code below on master produces no errors.

```python
from statsmodels.tsa.holtwinters import ExponentialSmoothing as HWES

import numpy as np

y = np.random.standard_normal(144*1000)

#build and train the model on the training data
model = HWES(y, seasonal_periods=144, trend='add', seasonal='add')
fitted = model.fit(optimized=True, use_brute=True)

#print out the training summary
print(fitted.summary())

#create an out of sample forcast for the next 12 steps beyond the final data point in the training data set
trend_forecast = fitted.forecast(steps= 157200)
```

If you run this and see an error, please upgrade to master. If you upgrade to master and see an error in your code, it is likely something with the dataset you are using. 
You might reset the index to be an integer index.  We really only support integer, DateTime or Period indices.  We might not check this enough. 
@bashtage Thank you for the reply!
I ran the code provided by you to check if that is working or not, that worked without any errors.

As suggested I also tried to reset index for the datafram and reran the code, it is showing the same error.
Also, when i'm trying to run `type(fitted.model._index[-1])` on the model fitted on my dataset, the output is `int`.

This is how my dataframe looks like, for your reference:
![image](https://user-images.githubusercontent.com/52621752/125169237-e2379600-e1c6-11eb-9288-f2a3b7c02fa9.png)

Kindly help!


Do you see the bug on master?  Which version of statsmodels are you using?

The solution is to not set `.freq`.  Leave this as `None`.
> The solution is to not set `.freq`. Leave this as `None`.

This helped to get rid of keyError, Thanks a ton!



Patch:
diff --git a/statsmodels/tsa/holtwinters/results.py b/statsmodels/tsa/holtwinters/results.py
index a534880ace0..d446db542d8 100644
--- a/statsmodels/tsa/holtwinters/results.py
+++ b/statsmodels/tsa/holtwinters/results.py
@@ -283,14 +283,16 @@ def forecast(self, steps=1):
         """
         try:
             freq = getattr(self.model._index, "freq", 1)
-            if isinstance(freq, int):
-                start = self.model._index.shape[0]
-                end = start + steps - 1
-            else:
+            if not isinstance(freq, int) and isinstance(
+                self.model._index, (pd.DatetimeIndex, pd.PeriodIndex)
+            ):
                 start = self.model._index[-1] + freq
                 end = self.model._index[-1] + steps * freq
+            else:
+                start = self.model._index.shape[0]
+                end = start + steps - 1
             return self.model.predict(self.params, start=start, end=end)
-        except (AttributeError, ValueError):
+        except AttributeError:
             # May occur when the index does not have a freq
             return self.model._predict(h=steps, **self.params).fcastvalues
 


Test patch:
diff --git a/statsmodels/tsa/holtwinters/tests/test_holtwinters.py b/statsmodels/tsa/holtwinters/tests/test_holtwinters.py
index 1e571cc159c..63e4b8a26ff 100644
--- a/statsmodels/tsa/holtwinters/tests/test_holtwinters.py
+++ b/statsmodels/tsa/holtwinters/tests/test_holtwinters.py
@@ -808,7 +808,9 @@ def test_invalid_seasonal(seasonal):
 
 def test_2d_data():
     with pytest.raises(ValueError):
-        ExponentialSmoothing(pd.concat([housing_data, housing_data], axis=1)).fit()
+        ExponentialSmoothing(
+            pd.concat([housing_data, housing_data], axis=1)
+        ).fit()
 
 
 def test_infer_freq():
@@ -2034,3 +2036,41 @@ def test_estimated_initialization_short_data(ses, trend, seasonal, nobs):
         initialization_method="estimated",
     ).fit()
     assert res.mle_retvals.success
+
+
+def test_invalid_index(reset_randomstate):
+    y = np.random.standard_normal(12 * 200)
+    df_y = pd.DataFrame(data=y)
+    # Can't have a freq here
+    df_y.index.freq = "d"
+
+    model = ExponentialSmoothing(
+        df_y,
+        seasonal_periods=12,
+        trend="add",
+        seasonal="add",
+        initialization_method="heuristic",
+    )
+    fitted = model.fit(optimized=True, use_brute=True)
+
+    fcast = fitted.forecast(steps=157200)
+    assert fcast.shape[0] == 157200
+
+    index = pd.date_range("2020-01-01", periods=2 * y.shape[0])
+    index = np.random.choice(index, size=df_y.shape[0], replace=False)
+    index = sorted(index)
+    df_y.index = index
+    assert isinstance(df_y.index, pd.DatetimeIndex)
+    assert df_y.index.freq is None
+    assert df_y.index.inferred_freq is None
+    with pytest.warns(ValueWarning, match="A date index has been provided"):
+        model = ExponentialSmoothing(
+            df_y,
+            seasonal_periods=12,
+            trend="add",
+            seasonal="add",
+            initialization_method="heuristic",
+        )
+    fitted = model.fit(optimized=True, use_brute=True)
+    with pytest.warns(ValueWarning, match="No supported"):
+        fitted.forecast(steps=157200)