We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
ThetaForecaster does not work with "initial_level" different from None
**Describe the bug**
When calling
`forecaster = ThetaForecaster(initial_level=0.5, deseasonalize=True, sp=1)` then fitting via `forecaster.fit(y_train)` leads to the following error:

```python
`Traceback (most recent call last):

  File "<ipython-input-362-6ef348c52370>", line 1, in <module>
    forecaster.fit(y_train)

  File "/Users/muhlbach/opt/anaconda3/envs/experimental/lib/python3.8/site-packages/sktime/forecasting/theta.py", line 131, in fit
    super(ThetaForecaster, self).fit(y, fh=fh)

  File "/Users/muhlbach/opt/anaconda3/envs/experimental/lib/python3.8/site-packages/sktime/forecasting/base/adapters/_statsmodels.py", line 47, in fit
    self._fit_forecaster(y, X)

  File "/Users/muhlbach/opt/anaconda3/envs/experimental/lib/python3.8/site-packages/sktime/forecasting/exp_smoothing.py", line 79, in _fit_forecaster
    self._forecaster = _ExponentialSmoothing(

  File "/Users/muhlbach/opt/anaconda3/envs/experimental/lib/python3.8/site-packages/pandas/util/_decorators.py", line 199, in wrapper
    return func(*args, **kwargs)

  File "/Users/muhlbach/opt/anaconda3/envs/experimental/lib/python3.8/site-packages/statsmodels/tsa/holtwinters/model.py", line 291, in __init__
    self._initialize()

  File "/Users/muhlbach/opt/anaconda3/envs/experimental/lib/python3.8/site-packages/statsmodels/tsa/holtwinters/model.py", line 439, in _initialize
    raise ValueError(msg.format("level"))

ValueError: initialization method is estimated but initial_level has been set.`
```

**To Reproduce**

```python
from sktime.forecasting.theta import ThetaForecaster
from sktime.datasets import load_airline
y = load_airline()
forecaster = ThetaForecaster(initial_level=0.5).fit(y)
```

**Expected behavior**
It should estimate Theta with initial smoothing level.

**Additional context**
I think the problem relates to the class ExponentialSmoothing and the fact that users cannot provide the `initialization_method` argument. See https://github.com/alan-turing-institute/sktime/blob/060af89907d135e41491d61f0966e285289a805b/sktime/forecasting/exp_smoothing.py#L10 


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sktime/forecasting/theta.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 __all__ = ["ThetaForecaster"]
3 __author__ = ["@big-o", "Markus Löning"]
4 
5 from warnings import warn
6 
7 import numpy as np
8 import pandas as pd
9 from scipy.stats import norm
10 
11 from sktime.forecasting.base._base import DEFAULT_ALPHA
12 from sktime.forecasting.exp_smoothing import ExponentialSmoothing
13 from sktime.transformations.series.detrend import Deseasonalizer
14 from sktime.utils.slope_and_trend import _fit_trend
15 from sktime.utils.validation.forecasting import check_sp
16 from sktime.utils.validation.forecasting import check_y_X
17 
18 
19 class ThetaForecaster(ExponentialSmoothing):
20     """
21     Theta method of forecasting.
22 
23     The theta method as defined in [1]_ is equivalent to simple exponential
24     smoothing
25     (SES) with drift. This is demonstrated in [2]_.
26 
27     The series is tested for seasonality using the test outlined in A&N. If
28     deemed
29     seasonal, the series is seasonally adjusted using a classical
30     multiplicative
31     decomposition before applying the theta method. The resulting forecasts
32     are then
33     reseasonalised.
34 
35     In cases where SES results in a constant forecast, the theta forecaster
36     will revert
37     to predicting the SES constant plus a linear trend derived from the
38     training data.
39 
40     Prediction intervals are computed using the underlying state space model.
41 
42     Parameters
43     ----------
44 
45     initial_level : float, optional
46         The alpha value of the simple exponential smoothing, if the value is
47         set then
48         this will be used, otherwise it will be estimated from the data.
49 
50     deseasonalize : bool, optional (default=True)
51         If True, data is seasonally adjusted.
52 
53     sp : int, optional (default=1)
54         The number of observations that constitute a seasonal period for a
55         multiplicative deseasonaliser, which is used if seasonality is
56         detected in the
57         training data. Ignored if a deseasonaliser transformer is provided.
58         Default is
59         1 (no seasonality).
60 
61     Attributes
62     ----------
63 
64     initial_level_ : float
65         The estimated alpha value of the SES fit.
66 
67     drift_ : float
68         The estimated drift of the fitted model.
69 
70     se_ : float
71         The standard error of the predictions. Used to calculate prediction
72         intervals.
73 
74     References
75     ----------
76 
77     .. [1] `Assimakopoulos, V. and Nikolopoulos, K. The theta model: a
78     decomposition
79            approach to forecasting. International Journal of Forecasting 16,
80            521-530,
81            2000.
82            <https://www.sciencedirect.com/science/article/pii
83            /S0169207000000662>`_
84 
85     .. [2] `Hyndman, Rob J., and Billah, Baki. Unmasking the Theta method.
86            International J. Forecasting, 19, 287-290, 2003.
87            <https://www.sciencedirect.com/science/article/pii
88            /S0169207001001431>`_
89     """
90 
91     _fitted_param_names = ("initial_level", "smoothing_level")
92 
93     def __init__(self, initial_level=None, deseasonalize=True, sp=1):
94 
95         self.sp = sp
96         self.deseasonalize = deseasonalize
97 
98         self.deseasonalizer_ = None
99         self.trend_ = None
100         self.initial_level_ = None
101         self.drift_ = None
102         self.se_ = None
103         super(ThetaForecaster, self).__init__(initial_level=initial_level, sp=sp)
104 
105     def fit(self, y, X=None, fh=None):
106         """Fit to training data.
107 
108         Parameters
109         ----------
110         y : pd.Series
111             Target time series to which to fit the forecaster.
112         fh : int, list or np.array, optional (default=None)
113             The forecasters horizon with the steps ahead to to predict.
114         X : pd.DataFrame, optional (default=None)
115             Exogenous variables are ignored
116         Returns
117         -------
118         self : returns an instance of self.
119         """
120         y, _ = check_y_X(y, X)
121         sp = check_sp(self.sp)
122         if sp > 1 and not self.deseasonalize:
123             warn("`sp` is ignored when `deseasonalise`=False")
124 
125         if self.deseasonalize:
126             self.deseasonalizer_ = Deseasonalizer(sp=self.sp, model="multiplicative")
127             y = self.deseasonalizer_.fit_transform(y)
128 
129         # fit exponential smoothing forecaster
130         # find theta lines: Theta lines are just SES + drift
131         super(ThetaForecaster, self).fit(y, fh=fh)
132         self.initial_level_ = self._fitted_forecaster.params["smoothing_level"]
133 
134         # compute trend
135         self.trend_ = self._compute_trend(y)
136         self._is_fitted = True
137         return self
138 
139     def _predict(self, fh, X=None, return_pred_int=False, alpha=DEFAULT_ALPHA):
140         """
141         Make forecasts.
142 
143         Parameters
144         ----------
145 
146         fh : array-like
147             The forecasters horizon with the steps ahead to to predict.
148             Default is
149             one-step ahead forecast, i.e. np.array([1]).
150 
151         Returns
152         -------
153 
154         y_pred : pandas.Series
155             Returns series of predicted values.
156         """
157         y_pred = super(ThetaForecaster, self)._predict(
158             fh, X, return_pred_int=False, alpha=alpha
159         )
160 
161         # Add drift.
162         drift = self._compute_drift()
163         y_pred += drift
164 
165         if self.deseasonalize:
166             y_pred = self.deseasonalizer_.inverse_transform(y_pred)
167 
168         if return_pred_int:
169             pred_int = self.compute_pred_int(y_pred=y_pred, alpha=alpha)
170             return y_pred, pred_int
171 
172         return y_pred
173 
174     @staticmethod
175     def _compute_trend(y):
176         # Trend calculated through least squares regression.
177         coefs = _fit_trend(y.values.reshape(1, -1), order=1)
178         return coefs[0, 0] / 2
179 
180     def _compute_drift(self):
181         fh = self.fh.to_relative(self.cutoff)
182         if np.isclose(self.initial_level_, 0.0):
183             # SES was constant, so revert to simple trend
184             drift = self.trend_ * fh
185         else:
186             # Calculate drift from SES parameters
187             n_timepoints = len(self._y)
188             drift = self.trend_ * (
189                 fh
190                 + (1 - (1 - self.initial_level_) ** n_timepoints) / self.initial_level_
191             )
192 
193         return drift
194 
195     def _compute_pred_err(self, alphas):
196         """
197         Get the prediction errors for the forecast.
198         """
199         self.check_is_fitted()
200 
201         n_timepoints = len(self._y)
202 
203         self.sigma_ = np.sqrt(self._fitted_forecaster.sse / (n_timepoints - 1))
204         sem = self.sigma_ * np.sqrt(
205             self.fh.to_relative(self.cutoff) * self.initial_level_ ** 2 + 1
206         )
207 
208         errors = []
209         for alpha in alphas:
210             z = _zscore(1 - alpha)
211             error = z * sem
212             errors.append(pd.Series(error, index=self.fh.to_absolute(self.cutoff)))
213 
214         return errors
215 
216     def update(self, y, X=None, update_params=True):
217         super(ThetaForecaster, self).update(
218             y, X, update_params=False
219         )  # use custom update_params routine
220         if update_params:
221             if self.deseasonalize:
222                 y = self.deseasonalizer_.transform(self._y)  # use updated y
223             self.initial_level_ = self._fitted_forecaster.params["smoothing_level"]
224             self.trend_ = self._compute_trend(y)
225         return self
226 
227 
228 def _zscore(level: float, two_tailed: bool = True) -> float:
229     """
230     Calculate a z-score from a confidence level.
231 
232     Parameters
233     ----------
234 
235     level : float
236         A confidence level, in the open interval (0, 1).
237 
238     two_tailed : bool (default=True)
239         If True, return the two-tailed z score.
240 
241     Returns
242     -------
243 
244     z : float
245         The z score.
246     """
247     alpha = 1 - level
248     if two_tailed:
249         alpha /= 2
250 
251     return -norm.ppf(alpha)
252
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/sktime/forecasting/theta.py b/sktime/forecasting/theta.py
--- a/sktime/forecasting/theta.py
+++ b/sktime/forecasting/theta.py
@@ -94,7 +94,6 @@
 
         self.sp = sp
         self.deseasonalize = deseasonalize
-
         self.deseasonalizer_ = None
         self.trend_ = None
         self.initial_level_ = None
@@ -126,6 +125,7 @@
             self.deseasonalizer_ = Deseasonalizer(sp=self.sp, model="multiplicative")
             y = self.deseasonalizer_.fit_transform(y)
 
+        self.initialization_method = "known" if self.initial_level else "estimated"
         # fit exponential smoothing forecaster
         # find theta lines: Theta lines are just SES + drift
         super(ThetaForecaster, self).fit(y, fh=fh)

{"golden_diff": "diff --git a/sktime/forecasting/theta.py b/sktime/forecasting/theta.py\n--- a/sktime/forecasting/theta.py\n+++ b/sktime/forecasting/theta.py\n@@ -94,7 +94,6 @@\n \n         self.sp = sp\n         self.deseasonalize = deseasonalize\n-\n         self.deseasonalizer_ = None\n         self.trend_ = None\n         self.initial_level_ = None\n@@ -126,6 +125,7 @@\n             self.deseasonalizer_ = Deseasonalizer(sp=self.sp, model=\"multiplicative\")\n             y = self.deseasonalizer_.fit_transform(y)\n \n+        self.initialization_method = \"known\" if self.initial_level else \"estimated\"\n         # fit exponential smoothing forecaster\n         # find theta lines: Theta lines are just SES + drift\n         super(ThetaForecaster, self).fit(y, fh=fh)\n", "issue": "ThetaForecaster does not work with \"initial_level\" different from None\n**Describe the bug**\r\nWhen calling\r\n`forecaster = ThetaForecaster(initial_level=0.5, deseasonalize=True, sp=1)` then fitting via `forecaster.fit(y_train)` leads to the following error:\r\n\r\n```python\r\n`Traceback (most recent call last):\r\n\r\n  File \"<ipython-input-362-6ef348c52370>\", line 1, in <module>\r\n    forecaster.fit(y_train)\r\n\r\n  File \"/Users/muhlbach/opt/anaconda3/envs/experimental/lib/python3.8/site-packages/sktime/forecasting/theta.py\", line 131, in fit\r\n    super(ThetaForecaster, self).fit(y, fh=fh)\r\n\r\n  File \"/Users/muhlbach/opt/anaconda3/envs/experimental/lib/python3.8/site-packages/sktime/forecasting/base/adapters/_statsmodels.py\", line 47, in fit\r\n    self._fit_forecaster(y, X)\r\n\r\n  File \"/Users/muhlbach/opt/anaconda3/envs/experimental/lib/python3.8/site-packages/sktime/forecasting/exp_smoothing.py\", line 79, in _fit_forecaster\r\n    self._forecaster = _ExponentialSmoothing(\r\n\r\n  File \"/Users/muhlbach/opt/anaconda3/envs/experimental/lib/python3.8/site-packages/pandas/util/_decorators.py\", line 199, in wrapper\r\n    return func(*args, **kwargs)\r\n\r\n  File \"/Users/muhlbach/opt/anaconda3/envs/experimental/lib/python3.8/site-packages/statsmodels/tsa/holtwinters/model.py\", line 291, in __init__\r\n    self._initialize()\r\n\r\n  File \"/Users/muhlbach/opt/anaconda3/envs/experimental/lib/python3.8/site-packages/statsmodels/tsa/holtwinters/model.py\", line 439, in _initialize\r\n    raise ValueError(msg.format(\"level\"))\r\n\r\nValueError: initialization method is estimated but initial_level has been set.`\r\n```\r\n\r\n**To Reproduce**\r\n\r\n```python\r\nfrom sktime.forecasting.theta import ThetaForecaster\r\nfrom sktime.datasets import load_airline\r\ny = load_airline()\r\nforecaster = ThetaForecaster(initial_level=0.5).fit(y)\r\n```\r\n\r\n**Expected behavior**\r\nIt should estimate Theta with initial smoothing level.\r\n\r\n**Additional context**\r\nI think the problem relates to the class ExponentialSmoothing and the fact that users cannot provide the `initialization_method` argument. See https://github.com/alan-turing-institute/sktime/blob/060af89907d135e41491d61f0966e285289a805b/sktime/forecasting/exp_smoothing.py#L10 \r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n__all__ = [\"ThetaForecaster\"]\n__author__ = [\"@big-o\", \"Markus L\u00f6ning\"]\n\nfrom warnings import warn\n\nimport numpy as np\nimport pandas as pd\nfrom scipy.stats import norm\n\nfrom sktime.forecasting.base._base import DEFAULT_ALPHA\nfrom sktime.forecasting.exp_smoothing import ExponentialSmoothing\nfrom sktime.transformations.series.detrend import Deseasonalizer\nfrom sktime.utils.slope_and_trend import _fit_trend\nfrom sktime.utils.validation.forecasting import check_sp\nfrom sktime.utils.validation.forecasting import check_y_X\n\n\nclass ThetaForecaster(ExponentialSmoothing):\n    \"\"\"\n    Theta method of forecasting.\n\n    The theta method as defined in [1]_ is equivalent to simple exponential\n    smoothing\n    (SES) with drift. This is demonstrated in [2]_.\n\n    The series is tested for seasonality using the test outlined in A&N. If\n    deemed\n    seasonal, the series is seasonally adjusted using a classical\n    multiplicative\n    decomposition before applying the theta method. The resulting forecasts\n    are then\n    reseasonalised.\n\n    In cases where SES results in a constant forecast, the theta forecaster\n    will revert\n    to predicting the SES constant plus a linear trend derived from the\n    training data.\n\n    Prediction intervals are computed using the underlying state space model.\n\n    Parameters\n    ----------\n\n    initial_level : float, optional\n        The alpha value of the simple exponential smoothing, if the value is\n        set then\n        this will be used, otherwise it will be estimated from the data.\n\n    deseasonalize : bool, optional (default=True)\n        If True, data is seasonally adjusted.\n\n    sp : int, optional (default=1)\n        The number of observations that constitute a seasonal period for a\n        multiplicative deseasonaliser, which is used if seasonality is\n        detected in the\n        training data. Ignored if a deseasonaliser transformer is provided.\n        Default is\n        1 (no seasonality).\n\n    Attributes\n    ----------\n\n    initial_level_ : float\n        The estimated alpha value of the SES fit.\n\n    drift_ : float\n        The estimated drift of the fitted model.\n\n    se_ : float\n        The standard error of the predictions. Used to calculate prediction\n        intervals.\n\n    References\n    ----------\n\n    .. [1] `Assimakopoulos, V. and Nikolopoulos, K. The theta model: a\n    decomposition\n           approach to forecasting. International Journal of Forecasting 16,\n           521-530,\n           2000.\n           <https://www.sciencedirect.com/science/article/pii\n           /S0169207000000662>`_\n\n    .. [2] `Hyndman, Rob J., and Billah, Baki. Unmasking the Theta method.\n           International J. Forecasting, 19, 287-290, 2003.\n           <https://www.sciencedirect.com/science/article/pii\n           /S0169207001001431>`_\n    \"\"\"\n\n    _fitted_param_names = (\"initial_level\", \"smoothing_level\")\n\n    def __init__(self, initial_level=None, deseasonalize=True, sp=1):\n\n        self.sp = sp\n        self.deseasonalize = deseasonalize\n\n        self.deseasonalizer_ = None\n        self.trend_ = None\n        self.initial_level_ = None\n        self.drift_ = None\n        self.se_ = None\n        super(ThetaForecaster, self).__init__(initial_level=initial_level, sp=sp)\n\n    def fit(self, y, X=None, fh=None):\n        \"\"\"Fit to training data.\n\n        Parameters\n        ----------\n        y : pd.Series\n            Target time series to which to fit the forecaster.\n        fh : int, list or np.array, optional (default=None)\n            The forecasters horizon with the steps ahead to to predict.\n        X : pd.DataFrame, optional (default=None)\n            Exogenous variables are ignored\n        Returns\n        -------\n        self : returns an instance of self.\n        \"\"\"\n        y, _ = check_y_X(y, X)\n        sp = check_sp(self.sp)\n        if sp > 1 and not self.deseasonalize:\n            warn(\"`sp` is ignored when `deseasonalise`=False\")\n\n        if self.deseasonalize:\n            self.deseasonalizer_ = Deseasonalizer(sp=self.sp, model=\"multiplicative\")\n            y = self.deseasonalizer_.fit_transform(y)\n\n        # fit exponential smoothing forecaster\n        # find theta lines: Theta lines are just SES + drift\n        super(ThetaForecaster, self).fit(y, fh=fh)\n        self.initial_level_ = self._fitted_forecaster.params[\"smoothing_level\"]\n\n        # compute trend\n        self.trend_ = self._compute_trend(y)\n        self._is_fitted = True\n        return self\n\n    def _predict(self, fh, X=None, return_pred_int=False, alpha=DEFAULT_ALPHA):\n        \"\"\"\n        Make forecasts.\n\n        Parameters\n        ----------\n\n        fh : array-like\n            The forecasters horizon with the steps ahead to to predict.\n            Default is\n            one-step ahead forecast, i.e. np.array([1]).\n\n        Returns\n        -------\n\n        y_pred : pandas.Series\n            Returns series of predicted values.\n        \"\"\"\n        y_pred = super(ThetaForecaster, self)._predict(\n            fh, X, return_pred_int=False, alpha=alpha\n        )\n\n        # Add drift.\n        drift = self._compute_drift()\n        y_pred += drift\n\n        if self.deseasonalize:\n            y_pred = self.deseasonalizer_.inverse_transform(y_pred)\n\n        if return_pred_int:\n            pred_int = self.compute_pred_int(y_pred=y_pred, alpha=alpha)\n            return y_pred, pred_int\n\n        return y_pred\n\n    @staticmethod\n    def _compute_trend(y):\n        # Trend calculated through least squares regression.\n        coefs = _fit_trend(y.values.reshape(1, -1), order=1)\n        return coefs[0, 0] / 2\n\n    def _compute_drift(self):\n        fh = self.fh.to_relative(self.cutoff)\n        if np.isclose(self.initial_level_, 0.0):\n            # SES was constant, so revert to simple trend\n            drift = self.trend_ * fh\n        else:\n            # Calculate drift from SES parameters\n            n_timepoints = len(self._y)\n            drift = self.trend_ * (\n                fh\n                + (1 - (1 - self.initial_level_) ** n_timepoints) / self.initial_level_\n            )\n\n        return drift\n\n    def _compute_pred_err(self, alphas):\n        \"\"\"\n        Get the prediction errors for the forecast.\n        \"\"\"\n        self.check_is_fitted()\n\n        n_timepoints = len(self._y)\n\n        self.sigma_ = np.sqrt(self._fitted_forecaster.sse / (n_timepoints - 1))\n        sem = self.sigma_ * np.sqrt(\n            self.fh.to_relative(self.cutoff) * self.initial_level_ ** 2 + 1\n        )\n\n        errors = []\n        for alpha in alphas:\n            z = _zscore(1 - alpha)\n            error = z * sem\n            errors.append(pd.Series(error, index=self.fh.to_absolute(self.cutoff)))\n\n        return errors\n\n    def update(self, y, X=None, update_params=True):\n        super(ThetaForecaster, self).update(\n            y, X, update_params=False\n        )  # use custom update_params routine\n        if update_params:\n            if self.deseasonalize:\n                y = self.deseasonalizer_.transform(self._y)  # use updated y\n            self.initial_level_ = self._fitted_forecaster.params[\"smoothing_level\"]\n            self.trend_ = self._compute_trend(y)\n        return self\n\n\ndef _zscore(level: float, two_tailed: bool = True) -> float:\n    \"\"\"\n    Calculate a z-score from a confidence level.\n\n    Parameters\n    ----------\n\n    level : float\n        A confidence level, in the open interval (0, 1).\n\n    two_tailed : bool (default=True)\n        If True, return the two-tailed z score.\n\n    Returns\n    -------\n\n    z : float\n        The z score.\n    \"\"\"\n    alpha = 1 - level\n    if two_tailed:\n        alpha /= 2\n\n    return -norm.ppf(alpha)\n", "path": "sktime/forecasting/theta.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n__all__ = [\"ThetaForecaster\"]\n__author__ = [\"@big-o\", \"Markus L\u00f6ning\"]\n\nfrom warnings import warn\n\nimport numpy as np\nimport pandas as pd\nfrom scipy.stats import norm\n\nfrom sktime.forecasting.base._base import DEFAULT_ALPHA\nfrom sktime.forecasting.exp_smoothing import ExponentialSmoothing\nfrom sktime.transformations.series.detrend import Deseasonalizer\nfrom sktime.utils.slope_and_trend import _fit_trend\nfrom sktime.utils.validation.forecasting import check_sp\nfrom sktime.utils.validation.forecasting import check_y_X\n\n\nclass ThetaForecaster(ExponentialSmoothing):\n    \"\"\"\n    Theta method of forecasting.\n\n    The theta method as defined in [1]_ is equivalent to simple exponential\n    smoothing\n    (SES) with drift. This is demonstrated in [2]_.\n\n    The series is tested for seasonality using the test outlined in A&N. If\n    deemed\n    seasonal, the series is seasonally adjusted using a classical\n    multiplicative\n    decomposition before applying the theta method. The resulting forecasts\n    are then\n    reseasonalised.\n\n    In cases where SES results in a constant forecast, the theta forecaster\n    will revert\n    to predicting the SES constant plus a linear trend derived from the\n    training data.\n\n    Prediction intervals are computed using the underlying state space model.\n\n    Parameters\n    ----------\n\n    initial_level : float, optional\n        The alpha value of the simple exponential smoothing, if the value is\n        set then\n        this will be used, otherwise it will be estimated from the data.\n\n    deseasonalize : bool, optional (default=True)\n        If True, data is seasonally adjusted.\n\n    sp : int, optional (default=1)\n        The number of observations that constitute a seasonal period for a\n        multiplicative deseasonaliser, which is used if seasonality is\n        detected in the\n        training data. Ignored if a deseasonaliser transformer is provided.\n        Default is\n        1 (no seasonality).\n\n    Attributes\n    ----------\n\n    initial_level_ : float\n        The estimated alpha value of the SES fit.\n\n    drift_ : float\n        The estimated drift of the fitted model.\n\n    se_ : float\n        The standard error of the predictions. Used to calculate prediction\n        intervals.\n\n    References\n    ----------\n\n    .. [1] `Assimakopoulos, V. and Nikolopoulos, K. The theta model: a\n    decomposition\n           approach to forecasting. International Journal of Forecasting 16,\n           521-530,\n           2000.\n           <https://www.sciencedirect.com/science/article/pii\n           /S0169207000000662>`_\n\n    .. [2] `Hyndman, Rob J., and Billah, Baki. Unmasking the Theta method.\n           International J. Forecasting, 19, 287-290, 2003.\n           <https://www.sciencedirect.com/science/article/pii\n           /S0169207001001431>`_\n    \"\"\"\n\n    _fitted_param_names = (\"initial_level\", \"smoothing_level\")\n\n    def __init__(self, initial_level=None, deseasonalize=True, sp=1):\n\n        self.sp = sp\n        self.deseasonalize = deseasonalize\n        self.deseasonalizer_ = None\n        self.trend_ = None\n        self.initial_level_ = None\n        self.drift_ = None\n        self.se_ = None\n        super(ThetaForecaster, self).__init__(initial_level=initial_level, sp=sp)\n\n    def fit(self, y, X=None, fh=None):\n        \"\"\"Fit to training data.\n\n        Parameters\n        ----------\n        y : pd.Series\n            Target time series to which to fit the forecaster.\n        fh : int, list or np.array, optional (default=None)\n            The forecasters horizon with the steps ahead to to predict.\n        X : pd.DataFrame, optional (default=None)\n            Exogenous variables are ignored\n        Returns\n        -------\n        self : returns an instance of self.\n        \"\"\"\n        y, _ = check_y_X(y, X)\n        sp = check_sp(self.sp)\n        if sp > 1 and not self.deseasonalize:\n            warn(\"`sp` is ignored when `deseasonalise`=False\")\n\n        if self.deseasonalize:\n            self.deseasonalizer_ = Deseasonalizer(sp=self.sp, model=\"multiplicative\")\n            y = self.deseasonalizer_.fit_transform(y)\n\n        self.initialization_method = \"known\" if self.initial_level else \"estimated\"\n        # fit exponential smoothing forecaster\n        # find theta lines: Theta lines are just SES + drift\n        super(ThetaForecaster, self).fit(y, fh=fh)\n        self.initial_level_ = self._fitted_forecaster.params[\"smoothing_level\"]\n\n        # compute trend\n        self.trend_ = self._compute_trend(y)\n        self._is_fitted = True\n        return self\n\n    def _predict(self, fh, X=None, return_pred_int=False, alpha=DEFAULT_ALPHA):\n        \"\"\"\n        Make forecasts.\n\n        Parameters\n        ----------\n\n        fh : array-like\n            The forecasters horizon with the steps ahead to to predict.\n            Default is\n            one-step ahead forecast, i.e. np.array([1]).\n\n        Returns\n        -------\n\n        y_pred : pandas.Series\n            Returns series of predicted values.\n        \"\"\"\n        y_pred = super(ThetaForecaster, self)._predict(\n            fh, X, return_pred_int=False, alpha=alpha\n        )\n\n        # Add drift.\n        drift = self._compute_drift()\n        y_pred += drift\n\n        if self.deseasonalize:\n            y_pred = self.deseasonalizer_.inverse_transform(y_pred)\n\n        if return_pred_int:\n            pred_int = self.compute_pred_int(y_pred=y_pred, alpha=alpha)\n            return y_pred, pred_int\n\n        return y_pred\n\n    @staticmethod\n    def _compute_trend(y):\n        # Trend calculated through least squares regression.\n        coefs = _fit_trend(y.values.reshape(1, -1), order=1)\n        return coefs[0, 0] / 2\n\n    def _compute_drift(self):\n        fh = self.fh.to_relative(self.cutoff)\n        if np.isclose(self.initial_level_, 0.0):\n            # SES was constant, so revert to simple trend\n            drift = self.trend_ * fh\n        else:\n            # Calculate drift from SES parameters\n            n_timepoints = len(self._y)\n            drift = self.trend_ * (\n                fh\n                + (1 - (1 - self.initial_level_) ** n_timepoints) / self.initial_level_\n            )\n\n        return drift\n\n    def _compute_pred_err(self, alphas):\n        \"\"\"\n        Get the prediction errors for the forecast.\n        \"\"\"\n        self.check_is_fitted()\n\n        n_timepoints = len(self._y)\n\n        self.sigma_ = np.sqrt(self._fitted_forecaster.sse / (n_timepoints - 1))\n        sem = self.sigma_ * np.sqrt(\n            self.fh.to_relative(self.cutoff) * self.initial_level_ ** 2 + 1\n        )\n\n        errors = []\n        for alpha in alphas:\n            z = _zscore(1 - alpha)\n            error = z * sem\n            errors.append(pd.Series(error, index=self.fh.to_absolute(self.cutoff)))\n\n        return errors\n\n    def update(self, y, X=None, update_params=True):\n        super(ThetaForecaster, self).update(\n            y, X, update_params=False\n        )  # use custom update_params routine\n        if update_params:\n            if self.deseasonalize:\n                y = self.deseasonalizer_.transform(self._y)  # use updated y\n            self.initial_level_ = self._fitted_forecaster.params[\"smoothing_level\"]\n            self.trend_ = self._compute_trend(y)\n        return self\n\n\ndef _zscore(level: float, two_tailed: bool = True) -> float:\n    \"\"\"\n    Calculate a z-score from a confidence level.\n\n    Parameters\n    ----------\n\n    level : float\n        A confidence level, in the open interval (0, 1).\n\n    two_tailed : bool (default=True)\n        If True, return the two-tailed z score.\n\n    Returns\n    -------\n\n    z : float\n        The z score.\n    \"\"\"\n    alpha = 1 - level\n    if two_tailed:\n        alpha /= 2\n\n    return -norm.ppf(alpha)\n", "path": "sktime/forecasting/theta.py"}]}