Repository: statsmodels/statsmodels

Issue:
Theta deseasonalizing multiplicative method not working
#### Describe the bug

When using the forecasting Theta model I found some strange behavior in the deseasonalizing of the data. There should be three deseasonalize methods: “auto”, “additive” and “multiplicative” (https://www.statsmodels.org/dev/generated/statsmodels.tsa.forecasting.theta.ThetaModel.html#statsmodels.tsa.forecasting.theta.ThetaModel). However, when I use the "auto" method, the output is not equal to the ouput of the “additive” or “multiplicative” method.

I had a look in the source code and suspect that this is caused by the  _deseasonalize_data() function in the Theta model. In this function the following code is used:

        **self._method = (
            "mul" if self._method == "auto" and self._y.min() > 0 else "add"
        )**

The "multiplicative” method is not considered here and is returned as "additive" if I'm not mistaking. This should not be the case if you can give it as input.


<details>

**Note**: As you can see, there are many issues on our GitHub tracker, so it is very possible that your issue has been posted before. Please check first before submitting so that we do not have to handle and close duplicates.

**Note**: Please be sure you are using the latest released version of `statsmodels`, or a recent build of `main`. If your problem has been fixed in an unreleased version, you might be able to use `main` until a new release occurs. 

**Note**: If you are using a released version, have you verified that the bug exists in the main branch of this repository? It helps the limited resources if we know problems exist in the current main branch so that they do not need to check whether the code sample produces a bug in the next release.

</details>


#### Expected Output

Solve the issue. When for deseasonalizing the "multiplicative" method is selected, it should also be used.

#### 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.9.12.final.0
statsmodels
===========
Installed: 0.13.0 (C:\Users\CasRoelants\anaconda3\envs\honeycomb-env\lib\site-packages\statsmodels)
Required Dependencies
=====================
cython: 0.29.24 (C:\Users\CasRoelants\anaconda3\envs\honeycomb-env\lib\site-packages\Cython)
numpy: 1.21.4 (C:\Users\CasRoelants\anaconda3\envs\honeycomb-env\lib\site-packages\numpy)
scipy: 1.5.4 (C:\Users\CasRoelants\anaconda3\envs\honeycomb-env\lib\site-packages\scipy)
pandas: 1.3.4 (C:\Users\CasRoelants\anaconda3\envs\honeycomb-env\lib\site-packages\pandas)
    dateutil: 2.8.2 (C:\Users\CasRoelants\anaconda3\envs\honeycomb-env\lib\site-packages\dateutil)
patsy: 0.5.2 (C:\Users\CasRoelants\anaconda3\envs\honeycomb-env\lib\site-packages\patsy)
Optional Dependencies
=====================
matplotlib: 3.5.2 (C:\Users\CasRoelants\anaconda3\envs\honeycomb-env\lib\site-packages\matplotlib)
Backend TkAgg is interactive backend. Turning interactive mode on.
    backend: TkAgg 
cvxopt: Not installed
joblib: 1.1.0 (C:\Users\CasRoelants\anaconda3\envs\honeycomb-env\lib\site-packages\joblib)
Developer Tools
================
IPython: 8.4.0 (C:\Users\CasRoelants\anaconda3\envs\honeycomb-env\lib\site-packages\IPython)
    jinja2: 3.1.2 (C:\Users\CasRoelants\anaconda3\envs\honeycomb-env\lib\site-packages\jinja2)
sphinx: 4.5.0 (C:\Users\CasRoelants\anaconda3\envs\honeycomb-env\lib\site-packages\sphinx)
    pygments: 2.12.0 (C:\Users\CasRoelants\anaconda3\envs\honeycomb-env\lib\site-packages\pygments)
pytest: 6.2.5 (C:\Users\CasRoelants\anaconda3\envs\honeycomb-env\lib\site-packages\pytest)
virtualenv: 20.16.2 (C:\Users\CasRoelants\anaconda3\envs\honeycomb-env\lib\site-packages\virtualenv)


Discussion:

Patch:
diff --git a/statsmodels/tsa/forecasting/theta.py b/statsmodels/tsa/forecasting/theta.py
index 252fd53cd..84bf12db1 100644
--- a/statsmodels/tsa/forecasting/theta.py
+++ b/statsmodels/tsa/forecasting/theta.py
@@ -151,6 +151,8 @@ class ThetaModel:
             "model",
             options=("auto", "additive", "multiplicative", "mul", "add"),
         )
+        if self._method == "auto":
+            self._method = "mul" if self._y.min() > 0 else "add"
         if self._period is None and self._deseasonalize:
             idx = getattr(endog, "index", None)
             pfreq = None
@@ -183,9 +185,6 @@ class ThetaModel:
         y = self._y
         if not self._has_seasonality:
             return self._y, np.empty(0)
-        self._method = (
-            "mul" if self._method == "auto" and self._y.min() > 0 else "add"
-        )
 
         res = seasonal_decompose(y, model=self._method, period=self._period)
         if res.seasonal.min() <= 0:


Test patch:
diff --git a/statsmodels/tsa/forecasting/tests/test_theta.py b/statsmodels/tsa/forecasting/tests/test_theta.py
index c31790a6d..e6c0b661a 100644
--- a/statsmodels/tsa/forecasting/tests/test_theta.py
+++ b/statsmodels/tsa/forecasting/tests/test_theta.py
@@ -133,3 +133,29 @@ def test_forecast_seasonal_alignment(data, period):
     index = np.arange(data.shape[0], data.shape[0] + comp.shape[0])
     expected = seasonal[index % period]
     np.testing.assert_allclose(comp.seasonal, expected)
+
+
+def test_auto(reset_randomstate):
+    m = 250
+    e = np.random.standard_normal(m)
+    s = 10 * np.sin(np.linspace(0, np.pi, 12))
+    s = np.tile(s, (m // 12 + 1))[:m]
+    idx = pd.period_range("2000-01-01", freq="M", periods=m)
+    x = e + s
+    y = pd.DataFrame(10 + x - x.min(), index=idx)
+
+    tm = ThetaModel(y, method="auto")
+    assert tm.method == "mul"
+    res = tm.fit()
+
+    tm = ThetaModel(y, method="mul")
+    assert tm.method == "mul"
+    res2 = tm.fit()
+
+    np.testing.assert_allclose(res.params, res2.params)
+
+    tm = ThetaModel(y - y.mean(), method="auto")
+    assert tm.method == "add"
+    res3 = tm.fit()
+
+    assert not np.allclose(res.params, res3.params)