We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ENH] VAR and VECM models
@fkiraly update: almost done, all that is missing is `predict_interval` for VECM.

---

@fkiraly's summary of the discussion:

We should interface VAR and VECM from `statsmodels`.

- [x] VAR #1083, #1491
- [x] VECM #1141, #2829

---

Have you considered porting `Vector Autoregressions (VAR)` and `Vector Error Correction Models (VECM)` from [statsmodels](https://www.statsmodels.org/dev/vector_ar.html#)? This would be a great addition. Thank you

--- 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/vecm.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # copyright: sktime developers, BSD-3-Clause License (see LICENSE file)
3 
4 """VECM Forecaster."""
5 
6 __all__ = ["VECM"]
7 __author__ = ["thayeylolu", "AurumnPegasus"]
8 
9 import numpy as np
10 import pandas as pd
11 from statsmodels.tsa.vector_ar.vecm import VECM as _VECM
12 
13 from sktime.forecasting.base.adapters import _StatsModelsAdapter
14 
15 
16 class VECM(_StatsModelsAdapter):
17     r"""
18     A VECM model, or Vector Error Correction Model, is a restricted.
19 
20     VAR model used for nonstationary series that are cointegrated.r
21 
22     Parameters
23     ----------
24     dates : array_like of datetime, optional
25         See :class:`statsmodels.tsa.base.tsa_model.TimeSeriesModel` for more
26         information.
27     freq : str, optional
28         See :class:`statsmodels.tsa.base.tsa_model.TimeSeriesModel` for more
29         information.
30     missing : str, optional
31         See :class:`statsmodels.base.model.Model` for more information.
32     k_ar_diff : int
33         Number of lagged differences in the model. Equals :math:`k_{ar} - 1` in
34         the formula above.
35     coint_rank : int
36         Cointegration rank, equals the rank of the matrix :math:`\\Pi` and the
37         number of columns of :math:`\\alpha` and :math:`\\beta`.
38     deterministic : str {``"n"``, ``"co"``, ``"ci"``, ``"lo"``, ``"li"``}
39         * ``"n"`` - no deterministic terms
40         * ``"co"`` - constant outside the cointegration relation
41         * ``"ci"`` - constant within the cointegration relation
42         * ``"lo"`` - linear trend outside the cointegration relation
43         * ``"li"`` - linear trend within the cointegration relation
44 
45         Combinations of these are possible (e.g. ``"cili"`` or ``"colo"`` for
46         linear trend with intercept). When using a constant term you have to
47         choose whether you want to restrict it to the cointegration relation
48         (i.e. ``"ci"``) or leave it unrestricted (i.e. ``"co"``). Do not use
49         both ``"ci"`` and ``"co"``. The same applies for ``"li"`` and ``"lo"``
50         when using a linear term. See the Notes-section for more information.
51     seasons : int, default: 0
52         Number of periods in a seasonal cycle. 0 means no seasons.
53     first_season : int, default: 0
54         Season of the first observation.
55     method : str {"ml"}, default: "ml"
56         Estimation method to use. "ml" stands for Maximum Likelihood.
57     exog_coint : a scalar (float), 1D ndarray of size nobs,
58         2D ndarray/pd.DataFrame of size (any, neqs)
59         Deterministic terms inside the cointegration relation.
60     exog_coint_fc : a scalar (float), 1D ndarray of size nobs,
61         2D ndarray/pd.DataFrame of size (any, neqs)
62         Forcasted value of exog_coint
63 
64     Example
65     -------
66     >>> from sktime.forecasting.vecm import VECM
67     >>> from sktime.forecasting.model_selection import temporal_train_test_split
68     >>> from sktime.forecasting.base import ForecastingHorizon
69     >>> index = pd.date_range(start="2005", end="2006-12", freq="M")
70     >>> df = pd.DataFrame(np.random.randint(0, 100, size=(23, 2)),
71     ... columns=list("AB"),
72     ... index=pd.PeriodIndex(index))
73     >>> train, test = temporal_train_test_split(df)
74     >>> sktime_model = VECM()
75     >>> fh = ForecastingHorizon([1, 3, 4, 5, 7, 9])
76     >>> _ = sktime_model.fit(train, fh=fh)
77     >>> fc2 = sktime_model.predict(fh=fh)
78     """
79 
80     _tags = {
81         "scitype:y": "multivariate",
82         "y_inner_mtype": "pd.DataFrame",
83         "X_inner_mtype": "pd.DataFrame",
84         "requires-fh-in-fit": False,
85         "univariate-only": False,
86         "ignores-exogeneous-X": False,
87     }
88 
89     def __init__(
90         self,
91         dates=None,
92         freq=None,
93         missing="none",
94         k_ar_diff=1,
95         coint_rank=1,
96         deterministic="n",
97         seasons=0,
98         first_season=0,
99         method="ml",
100         exog_coint=None,
101         exog_coint_fc=None,
102     ):
103 
104         self.dates = dates
105         self.freq = freq
106         self.missing = missing
107         self.k_ar_diff = k_ar_diff
108         self.coint_rank = coint_rank
109         self.deterministic = deterministic
110         self.seasons = seasons
111         self.first_season = first_season
112         self.method = method
113         self.exog_coint = exog_coint
114         self.exog_coint_fc = exog_coint_fc
115 
116         super(VECM, self).__init__()
117 
118     def _fit(self, y, fh=None, X=None):
119         """
120         Fit forecaster to training data.
121 
122         Wrapper for statsmodel's VECM (_VECM) fit method
123 
124         Parameters
125         ----------
126         y : pd.DataFrame, guaranteed to have 2 or more columns
127             Time series to which to fit the forecaster.
128         fh : guaranteed to be ForecastingHorizon
129             The forecasting horizon with the steps ahead to to predict.
130             Required (non-optional) here if self.get_tag("requires-fh-in-fit")==True
131             Otherwise, if not passed in _fit, guaranteed to be passed in _predict
132         X : pd.DataFrame, optional (default=None)
133             Exogeneous time series to fit to.
134 
135         Returns
136         -------
137         self : reference to self
138         """
139         self._forecaster = _VECM(
140             endog=y,
141             exog=X,
142             exog_coint=self.exog_coint,
143             dates=self.dates,
144             freq=self.freq,
145             missing=self.missing,
146             k_ar_diff=self.k_ar_diff,
147             coint_rank=self.coint_rank,
148             deterministic=self.deterministic,
149             seasons=self.seasons,
150             first_season=self.first_season,
151         )
152 
153         self._fitted_forecaster = self._forecaster.fit(method=self.method)
154         return self
155 
156     def _predict(self, fh, X=None):
157         """
158         Forecast time series at future horizon.
159 
160         Wrapper for statsmodel's VECM (_VECM) predict method
161 
162         Parameters
163         ----------
164         fh : guaranteed to be ForecastingHorizon
165             The forecasting horizon with the steps ahead to to predict.
166             If not passed in _fit, guaranteed to be passed here
167         X : optional (default=None)
168             guaranteed to be of a type in self.get_tag("X_inner_mtype")
169             Exogeneous time series for the forecast
170 
171         Returns
172         -------
173         y_pred : pd.Series
174             Point predictions
175         """
176         y_pred_outsample = None
177         y_pred_insample = None
178         exog_fc = X.values if X is not None else None
179         fh_int = fh.to_relative(self.cutoff)
180 
181         # out-sample prediction
182         if fh_int.max() > 0:
183             y_pred_outsample = self._fitted_forecaster.predict(
184                 steps=fh_int[-1],
185                 exog_fc=exog_fc,
186                 exog_coint_fc=self.exog_coint_fc,
187             )
188 
189         # in-sample prediction by means of residuals
190         if fh_int.min() <= 0:
191 
192             # .resid returns np.ndarray
193             # both values need to be pd DataFrame for subtraction
194             y_pred_insample = self._y - pd.DataFrame(self._fitted_forecaster.resid)
195             y_pred_insample = y_pred_insample.values
196 
197         if y_pred_insample is not None and y_pred_outsample is not None:
198             y_pred = np.concatenate([y_pred_outsample, y_pred_insample], axis=0)
199         else:
200             y_pred = (
201                 y_pred_insample if y_pred_insample is not None else y_pred_outsample
202             )
203 
204         index = fh.to_absolute(self.cutoff)
205         index.name = self._y.index.name
206         y_pred = pd.DataFrame(
207             y_pred[fh.to_indexer(self.cutoff), :],
208             index=fh.to_absolute(self.cutoff),
209             columns=self._y.columns,
210         )
211 
212         return y_pred
213
```
--- 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/vecm.py b/sktime/forecasting/vecm.py
--- a/sktime/forecasting/vecm.py
+++ b/sktime/forecasting/vecm.py
@@ -3,6 +3,7 @@
 
 """VECM Forecaster."""
 
+
 __all__ = ["VECM"]
 __author__ = ["thayeylolu", "AurumnPegasus"]
 
@@ -84,6 +85,7 @@
         "requires-fh-in-fit": False,
         "univariate-only": False,
         "ignores-exogeneous-X": False,
+        "capability:pred_int": True,
     }
 
     def __init__(
@@ -210,3 +212,70 @@
         )
 
         return y_pred
+
+    def _predict_interval(self, fh, X=None, coverage=None):
+        """
+        Compute/return prediction quantiles for a forecast.
+
+        private _predict_interval containing the core logic,
+            called from predict_interval and possibly predict_quantiles
+        State required:
+            Requires state to be "fitted".
+        Accesses in self:
+            Fitted model attributes ending in "_"
+            self.cutoff
+
+        Parameters
+        ----------
+        fh : guaranteed to be ForecastingHorizon
+            The forecasting horizon with the steps ahead to to predict.
+        X : optional (default=None)
+            guaranteed to be of a type in self.get_tag("X_inner_mtype")
+            Exogeneous time series for the forecast
+        coverage : list of float (guaranteed not None and floats in [0,1] interval)
+           nominal coverage(s) of predictive interval(s)
+
+        Returns
+        -------
+        pred_int : pd.DataFrame
+            Column has multi-index: first level is variable name from y in fit,
+                second level coverage fractions for which intervals were computed.
+                    in the same order as in input `coverage`.
+                Third level is string "lower" or "upper", for lower/upper interval end.
+            Row index is fh, with additional (upper) levels equal to instance levels,
+                from y seen in fit, if y_inner_mtype is Panel or Hierarchical.
+            Entries are forecasts of lower/upper interval end,
+                for var in col index, at nominal coverage in second col index,
+                lower/upper depending on third col index, for the row index.
+                Upper/lower interval end forecasts are equivalent to
+                quantile forecasts at alpha = 0.5 - c/2, 0.5 + c/2 for c in coverage.
+        """
+        exog_fc = X.values if X is not None else None
+        fh_oos = fh.to_out_of_sample(self.cutoff)
+        var_names = (
+            self._y.index.name
+            if self._y.index.name is not None
+            else self._y.columns.values
+        )
+        int_idx = pd.MultiIndex.from_product([var_names, coverage, ["lower", "upper"]])
+        # pred_int = pd.DataFrame(index=int_idx)
+
+        for c in coverage:
+            alpha = 1 - c
+            _, y_lower, y_upper = self._fitted_forecaster.predict(
+                steps=fh_oos[-1],
+                exog_fc=exog_fc,
+                exog_coint_fc=self.exog_coint_fc,
+                alpha=alpha,
+            )
+            values = []
+            for v_idx in range(len(var_names)):
+                values.append(y_lower[0][v_idx])
+                values.append(y_upper[0][v_idx])
+                # pred_int.loc[(var_names[v_idx], c, "lower"), :] = (y_lower[0][v_idx])
+                # pred_int.loc[(var_names[v_idx], c, "upper"), :] = (y_upper[0][v_idx])
+        pred_int = pd.DataFrame(
+            [values], index=fh.to_absolute(self.cutoff), columns=int_idx
+        )
+
+        return pred_int

{"golden_diff": "diff --git a/sktime/forecasting/vecm.py b/sktime/forecasting/vecm.py\n--- a/sktime/forecasting/vecm.py\n+++ b/sktime/forecasting/vecm.py\n@@ -3,6 +3,7 @@\n \n \"\"\"VECM Forecaster.\"\"\"\n \n+\n __all__ = [\"VECM\"]\n __author__ = [\"thayeylolu\", \"AurumnPegasus\"]\n \n@@ -84,6 +85,7 @@\n         \"requires-fh-in-fit\": False,\n         \"univariate-only\": False,\n         \"ignores-exogeneous-X\": False,\n+        \"capability:pred_int\": True,\n     }\n \n     def __init__(\n@@ -210,3 +212,70 @@\n         )\n \n         return y_pred\n+\n+    def _predict_interval(self, fh, X=None, coverage=None):\n+        \"\"\"\n+        Compute/return prediction quantiles for a forecast.\n+\n+        private _predict_interval containing the core logic,\n+            called from predict_interval and possibly predict_quantiles\n+        State required:\n+            Requires state to be \"fitted\".\n+        Accesses in self:\n+            Fitted model attributes ending in \"_\"\n+            self.cutoff\n+\n+        Parameters\n+        ----------\n+        fh : guaranteed to be ForecastingHorizon\n+            The forecasting horizon with the steps ahead to to predict.\n+        X : optional (default=None)\n+            guaranteed to be of a type in self.get_tag(\"X_inner_mtype\")\n+            Exogeneous time series for the forecast\n+        coverage : list of float (guaranteed not None and floats in [0,1] interval)\n+           nominal coverage(s) of predictive interval(s)\n+\n+        Returns\n+        -------\n+        pred_int : pd.DataFrame\n+            Column has multi-index: first level is variable name from y in fit,\n+                second level coverage fractions for which intervals were computed.\n+                    in the same order as in input `coverage`.\n+                Third level is string \"lower\" or \"upper\", for lower/upper interval end.\n+            Row index is fh, with additional (upper) levels equal to instance levels,\n+                from y seen in fit, if y_inner_mtype is Panel or Hierarchical.\n+            Entries are forecasts of lower/upper interval end,\n+                for var in col index, at nominal coverage in second col index,\n+                lower/upper depending on third col index, for the row index.\n+                Upper/lower interval end forecasts are equivalent to\n+                quantile forecasts at alpha = 0.5 - c/2, 0.5 + c/2 for c in coverage.\n+        \"\"\"\n+        exog_fc = X.values if X is not None else None\n+        fh_oos = fh.to_out_of_sample(self.cutoff)\n+        var_names = (\n+            self._y.index.name\n+            if self._y.index.name is not None\n+            else self._y.columns.values\n+        )\n+        int_idx = pd.MultiIndex.from_product([var_names, coverage, [\"lower\", \"upper\"]])\n+        # pred_int = pd.DataFrame(index=int_idx)\n+\n+        for c in coverage:\n+            alpha = 1 - c\n+            _, y_lower, y_upper = self._fitted_forecaster.predict(\n+                steps=fh_oos[-1],\n+                exog_fc=exog_fc,\n+                exog_coint_fc=self.exog_coint_fc,\n+                alpha=alpha,\n+            )\n+            values = []\n+            for v_idx in range(len(var_names)):\n+                values.append(y_lower[0][v_idx])\n+                values.append(y_upper[0][v_idx])\n+                # pred_int.loc[(var_names[v_idx], c, \"lower\"), :] = (y_lower[0][v_idx])\n+                # pred_int.loc[(var_names[v_idx], c, \"upper\"), :] = (y_upper[0][v_idx])\n+        pred_int = pd.DataFrame(\n+            [values], index=fh.to_absolute(self.cutoff), columns=int_idx\n+        )\n+\n+        return pred_int\n", "issue": "[ENH] VAR and VECM models\n@fkiraly update: almost done, all that is missing is `predict_interval` for VECM.\r\n\r\n---\r\n\r\n@fkiraly's summary of the discussion:\r\n\r\nWe should interface VAR and VECM from `statsmodels`.\r\n\r\n- [x] VAR #1083, #1491\r\n- [x] VECM #1141, #2829\r\n\r\n---\r\n\r\nHave you considered porting `Vector Autoregressions (VAR)` and `Vector Error Correction Models (VECM)` from [statsmodels](https://www.statsmodels.org/dev/vector_ar.html#)? This would be a great addition. Thank you\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# copyright: sktime developers, BSD-3-Clause License (see LICENSE file)\n\n\"\"\"VECM Forecaster.\"\"\"\n\n__all__ = [\"VECM\"]\n__author__ = [\"thayeylolu\", \"AurumnPegasus\"]\n\nimport numpy as np\nimport pandas as pd\nfrom statsmodels.tsa.vector_ar.vecm import VECM as _VECM\n\nfrom sktime.forecasting.base.adapters import _StatsModelsAdapter\n\n\nclass VECM(_StatsModelsAdapter):\n    r\"\"\"\n    A VECM model, or Vector Error Correction Model, is a restricted.\n\n    VAR model used for nonstationary series that are cointegrated.r\n\n    Parameters\n    ----------\n    dates : array_like of datetime, optional\n        See :class:`statsmodels.tsa.base.tsa_model.TimeSeriesModel` for more\n        information.\n    freq : str, optional\n        See :class:`statsmodels.tsa.base.tsa_model.TimeSeriesModel` for more\n        information.\n    missing : str, optional\n        See :class:`statsmodels.base.model.Model` for more information.\n    k_ar_diff : int\n        Number of lagged differences in the model. Equals :math:`k_{ar} - 1` in\n        the formula above.\n    coint_rank : int\n        Cointegration rank, equals the rank of the matrix :math:`\\\\Pi` and the\n        number of columns of :math:`\\\\alpha` and :math:`\\\\beta`.\n    deterministic : str {``\"n\"``, ``\"co\"``, ``\"ci\"``, ``\"lo\"``, ``\"li\"``}\n        * ``\"n\"`` - no deterministic terms\n        * ``\"co\"`` - constant outside the cointegration relation\n        * ``\"ci\"`` - constant within the cointegration relation\n        * ``\"lo\"`` - linear trend outside the cointegration relation\n        * ``\"li\"`` - linear trend within the cointegration relation\n\n        Combinations of these are possible (e.g. ``\"cili\"`` or ``\"colo\"`` for\n        linear trend with intercept). When using a constant term you have to\n        choose whether you want to restrict it to the cointegration relation\n        (i.e. ``\"ci\"``) or leave it unrestricted (i.e. ``\"co\"``). Do not use\n        both ``\"ci\"`` and ``\"co\"``. The same applies for ``\"li\"`` and ``\"lo\"``\n        when using a linear term. See the Notes-section for more information.\n    seasons : int, default: 0\n        Number of periods in a seasonal cycle. 0 means no seasons.\n    first_season : int, default: 0\n        Season of the first observation.\n    method : str {\"ml\"}, default: \"ml\"\n        Estimation method to use. \"ml\" stands for Maximum Likelihood.\n    exog_coint : a scalar (float), 1D ndarray of size nobs,\n        2D ndarray/pd.DataFrame of size (any, neqs)\n        Deterministic terms inside the cointegration relation.\n    exog_coint_fc : a scalar (float), 1D ndarray of size nobs,\n        2D ndarray/pd.DataFrame of size (any, neqs)\n        Forcasted value of exog_coint\n\n    Example\n    -------\n    >>> from sktime.forecasting.vecm import VECM\n    >>> from sktime.forecasting.model_selection import temporal_train_test_split\n    >>> from sktime.forecasting.base import ForecastingHorizon\n    >>> index = pd.date_range(start=\"2005\", end=\"2006-12\", freq=\"M\")\n    >>> df = pd.DataFrame(np.random.randint(0, 100, size=(23, 2)),\n    ... columns=list(\"AB\"),\n    ... index=pd.PeriodIndex(index))\n    >>> train, test = temporal_train_test_split(df)\n    >>> sktime_model = VECM()\n    >>> fh = ForecastingHorizon([1, 3, 4, 5, 7, 9])\n    >>> _ = sktime_model.fit(train, fh=fh)\n    >>> fc2 = sktime_model.predict(fh=fh)\n    \"\"\"\n\n    _tags = {\n        \"scitype:y\": \"multivariate\",\n        \"y_inner_mtype\": \"pd.DataFrame\",\n        \"X_inner_mtype\": \"pd.DataFrame\",\n        \"requires-fh-in-fit\": False,\n        \"univariate-only\": False,\n        \"ignores-exogeneous-X\": False,\n    }\n\n    def __init__(\n        self,\n        dates=None,\n        freq=None,\n        missing=\"none\",\n        k_ar_diff=1,\n        coint_rank=1,\n        deterministic=\"n\",\n        seasons=0,\n        first_season=0,\n        method=\"ml\",\n        exog_coint=None,\n        exog_coint_fc=None,\n    ):\n\n        self.dates = dates\n        self.freq = freq\n        self.missing = missing\n        self.k_ar_diff = k_ar_diff\n        self.coint_rank = coint_rank\n        self.deterministic = deterministic\n        self.seasons = seasons\n        self.first_season = first_season\n        self.method = method\n        self.exog_coint = exog_coint\n        self.exog_coint_fc = exog_coint_fc\n\n        super(VECM, self).__init__()\n\n    def _fit(self, y, fh=None, X=None):\n        \"\"\"\n        Fit forecaster to training data.\n\n        Wrapper for statsmodel's VECM (_VECM) fit method\n\n        Parameters\n        ----------\n        y : pd.DataFrame, guaranteed to have 2 or more columns\n            Time series to which to fit the forecaster.\n        fh : guaranteed to be ForecastingHorizon\n            The forecasting horizon with the steps ahead to to predict.\n            Required (non-optional) here if self.get_tag(\"requires-fh-in-fit\")==True\n            Otherwise, if not passed in _fit, guaranteed to be passed in _predict\n        X : pd.DataFrame, optional (default=None)\n            Exogeneous time series to fit to.\n\n        Returns\n        -------\n        self : reference to self\n        \"\"\"\n        self._forecaster = _VECM(\n            endog=y,\n            exog=X,\n            exog_coint=self.exog_coint,\n            dates=self.dates,\n            freq=self.freq,\n            missing=self.missing,\n            k_ar_diff=self.k_ar_diff,\n            coint_rank=self.coint_rank,\n            deterministic=self.deterministic,\n            seasons=self.seasons,\n            first_season=self.first_season,\n        )\n\n        self._fitted_forecaster = self._forecaster.fit(method=self.method)\n        return self\n\n    def _predict(self, fh, X=None):\n        \"\"\"\n        Forecast time series at future horizon.\n\n        Wrapper for statsmodel's VECM (_VECM) predict method\n\n        Parameters\n        ----------\n        fh : guaranteed to be ForecastingHorizon\n            The forecasting horizon with the steps ahead to to predict.\n            If not passed in _fit, guaranteed to be passed here\n        X : optional (default=None)\n            guaranteed to be of a type in self.get_tag(\"X_inner_mtype\")\n            Exogeneous time series for the forecast\n\n        Returns\n        -------\n        y_pred : pd.Series\n            Point predictions\n        \"\"\"\n        y_pred_outsample = None\n        y_pred_insample = None\n        exog_fc = X.values if X is not None else None\n        fh_int = fh.to_relative(self.cutoff)\n\n        # out-sample prediction\n        if fh_int.max() > 0:\n            y_pred_outsample = self._fitted_forecaster.predict(\n                steps=fh_int[-1],\n                exog_fc=exog_fc,\n                exog_coint_fc=self.exog_coint_fc,\n            )\n\n        # in-sample prediction by means of residuals\n        if fh_int.min() <= 0:\n\n            # .resid returns np.ndarray\n            # both values need to be pd DataFrame for subtraction\n            y_pred_insample = self._y - pd.DataFrame(self._fitted_forecaster.resid)\n            y_pred_insample = y_pred_insample.values\n\n        if y_pred_insample is not None and y_pred_outsample is not None:\n            y_pred = np.concatenate([y_pred_outsample, y_pred_insample], axis=0)\n        else:\n            y_pred = (\n                y_pred_insample if y_pred_insample is not None else y_pred_outsample\n            )\n\n        index = fh.to_absolute(self.cutoff)\n        index.name = self._y.index.name\n        y_pred = pd.DataFrame(\n            y_pred[fh.to_indexer(self.cutoff), :],\n            index=fh.to_absolute(self.cutoff),\n            columns=self._y.columns,\n        )\n\n        return y_pred\n", "path": "sktime/forecasting/vecm.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n# copyright: sktime developers, BSD-3-Clause License (see LICENSE file)\n\n\"\"\"VECM Forecaster.\"\"\"\n\n\n__all__ = [\"VECM\"]\n__author__ = [\"thayeylolu\", \"AurumnPegasus\"]\n\nimport numpy as np\nimport pandas as pd\nfrom statsmodels.tsa.vector_ar.vecm import VECM as _VECM\n\nfrom sktime.forecasting.base.adapters import _StatsModelsAdapter\n\n\nclass VECM(_StatsModelsAdapter):\n    r\"\"\"\n    A VECM model, or Vector Error Correction Model, is a restricted.\n\n    VAR model used for nonstationary series that are cointegrated.r\n\n    Parameters\n    ----------\n    dates : array_like of datetime, optional\n        See :class:`statsmodels.tsa.base.tsa_model.TimeSeriesModel` for more\n        information.\n    freq : str, optional\n        See :class:`statsmodels.tsa.base.tsa_model.TimeSeriesModel` for more\n        information.\n    missing : str, optional\n        See :class:`statsmodels.base.model.Model` for more information.\n    k_ar_diff : int\n        Number of lagged differences in the model. Equals :math:`k_{ar} - 1` in\n        the formula above.\n    coint_rank : int\n        Cointegration rank, equals the rank of the matrix :math:`\\\\Pi` and the\n        number of columns of :math:`\\\\alpha` and :math:`\\\\beta`.\n    deterministic : str {``\"n\"``, ``\"co\"``, ``\"ci\"``, ``\"lo\"``, ``\"li\"``}\n        * ``\"n\"`` - no deterministic terms\n        * ``\"co\"`` - constant outside the cointegration relation\n        * ``\"ci\"`` - constant within the cointegration relation\n        * ``\"lo\"`` - linear trend outside the cointegration relation\n        * ``\"li\"`` - linear trend within the cointegration relation\n\n        Combinations of these are possible (e.g. ``\"cili\"`` or ``\"colo\"`` for\n        linear trend with intercept). When using a constant term you have to\n        choose whether you want to restrict it to the cointegration relation\n        (i.e. ``\"ci\"``) or leave it unrestricted (i.e. ``\"co\"``). Do not use\n        both ``\"ci\"`` and ``\"co\"``. The same applies for ``\"li\"`` and ``\"lo\"``\n        when using a linear term. See the Notes-section for more information.\n    seasons : int, default: 0\n        Number of periods in a seasonal cycle. 0 means no seasons.\n    first_season : int, default: 0\n        Season of the first observation.\n    method : str {\"ml\"}, default: \"ml\"\n        Estimation method to use. \"ml\" stands for Maximum Likelihood.\n    exog_coint : a scalar (float), 1D ndarray of size nobs,\n        2D ndarray/pd.DataFrame of size (any, neqs)\n        Deterministic terms inside the cointegration relation.\n    exog_coint_fc : a scalar (float), 1D ndarray of size nobs,\n        2D ndarray/pd.DataFrame of size (any, neqs)\n        Forcasted value of exog_coint\n\n    Example\n    -------\n    >>> from sktime.forecasting.vecm import VECM\n    >>> from sktime.forecasting.model_selection import temporal_train_test_split\n    >>> from sktime.forecasting.base import ForecastingHorizon\n    >>> index = pd.date_range(start=\"2005\", end=\"2006-12\", freq=\"M\")\n    >>> df = pd.DataFrame(np.random.randint(0, 100, size=(23, 2)),\n    ... columns=list(\"AB\"),\n    ... index=pd.PeriodIndex(index))\n    >>> train, test = temporal_train_test_split(df)\n    >>> sktime_model = VECM()\n    >>> fh = ForecastingHorizon([1, 3, 4, 5, 7, 9])\n    >>> _ = sktime_model.fit(train, fh=fh)\n    >>> fc2 = sktime_model.predict(fh=fh)\n    \"\"\"\n\n    _tags = {\n        \"scitype:y\": \"multivariate\",\n        \"y_inner_mtype\": \"pd.DataFrame\",\n        \"X_inner_mtype\": \"pd.DataFrame\",\n        \"requires-fh-in-fit\": False,\n        \"univariate-only\": False,\n        \"ignores-exogeneous-X\": False,\n        \"capability:pred_int\": True,\n    }\n\n    def __init__(\n        self,\n        dates=None,\n        freq=None,\n        missing=\"none\",\n        k_ar_diff=1,\n        coint_rank=1,\n        deterministic=\"n\",\n        seasons=0,\n        first_season=0,\n        method=\"ml\",\n        exog_coint=None,\n        exog_coint_fc=None,\n    ):\n\n        self.dates = dates\n        self.freq = freq\n        self.missing = missing\n        self.k_ar_diff = k_ar_diff\n        self.coint_rank = coint_rank\n        self.deterministic = deterministic\n        self.seasons = seasons\n        self.first_season = first_season\n        self.method = method\n        self.exog_coint = exog_coint\n        self.exog_coint_fc = exog_coint_fc\n\n        super(VECM, self).__init__()\n\n    def _fit(self, y, fh=None, X=None):\n        \"\"\"\n        Fit forecaster to training data.\n\n        Wrapper for statsmodel's VECM (_VECM) fit method\n\n        Parameters\n        ----------\n        y : pd.DataFrame, guaranteed to have 2 or more columns\n            Time series to which to fit the forecaster.\n        fh : guaranteed to be ForecastingHorizon\n            The forecasting horizon with the steps ahead to to predict.\n            Required (non-optional) here if self.get_tag(\"requires-fh-in-fit\")==True\n            Otherwise, if not passed in _fit, guaranteed to be passed in _predict\n        X : pd.DataFrame, optional (default=None)\n            Exogeneous time series to fit to.\n\n        Returns\n        -------\n        self : reference to self\n        \"\"\"\n        self._forecaster = _VECM(\n            endog=y,\n            exog=X,\n            exog_coint=self.exog_coint,\n            dates=self.dates,\n            freq=self.freq,\n            missing=self.missing,\n            k_ar_diff=self.k_ar_diff,\n            coint_rank=self.coint_rank,\n            deterministic=self.deterministic,\n            seasons=self.seasons,\n            first_season=self.first_season,\n        )\n\n        self._fitted_forecaster = self._forecaster.fit(method=self.method)\n        return self\n\n    def _predict(self, fh, X=None):\n        \"\"\"\n        Forecast time series at future horizon.\n\n        Wrapper for statsmodel's VECM (_VECM) predict method\n\n        Parameters\n        ----------\n        fh : guaranteed to be ForecastingHorizon\n            The forecasting horizon with the steps ahead to to predict.\n            If not passed in _fit, guaranteed to be passed here\n        X : optional (default=None)\n            guaranteed to be of a type in self.get_tag(\"X_inner_mtype\")\n            Exogeneous time series for the forecast\n\n        Returns\n        -------\n        y_pred : pd.Series\n            Point predictions\n        \"\"\"\n        y_pred_outsample = None\n        y_pred_insample = None\n        exog_fc = X.values if X is not None else None\n        fh_int = fh.to_relative(self.cutoff)\n\n        # out-sample prediction\n        if fh_int.max() > 0:\n            y_pred_outsample = self._fitted_forecaster.predict(\n                steps=fh_int[-1],\n                exog_fc=exog_fc,\n                exog_coint_fc=self.exog_coint_fc,\n            )\n\n        # in-sample prediction by means of residuals\n        if fh_int.min() <= 0:\n\n            # .resid returns np.ndarray\n            # both values need to be pd DataFrame for subtraction\n            y_pred_insample = self._y - pd.DataFrame(self._fitted_forecaster.resid)\n            y_pred_insample = y_pred_insample.values\n\n        if y_pred_insample is not None and y_pred_outsample is not None:\n            y_pred = np.concatenate([y_pred_outsample, y_pred_insample], axis=0)\n        else:\n            y_pred = (\n                y_pred_insample if y_pred_insample is not None else y_pred_outsample\n            )\n\n        index = fh.to_absolute(self.cutoff)\n        index.name = self._y.index.name\n        y_pred = pd.DataFrame(\n            y_pred[fh.to_indexer(self.cutoff), :],\n            index=fh.to_absolute(self.cutoff),\n            columns=self._y.columns,\n        )\n\n        return y_pred\n\n    def _predict_interval(self, fh, X=None, coverage=None):\n        \"\"\"\n        Compute/return prediction quantiles for a forecast.\n\n        private _predict_interval containing the core logic,\n            called from predict_interval and possibly predict_quantiles\n        State required:\n            Requires state to be \"fitted\".\n        Accesses in self:\n            Fitted model attributes ending in \"_\"\n            self.cutoff\n\n        Parameters\n        ----------\n        fh : guaranteed to be ForecastingHorizon\n            The forecasting horizon with the steps ahead to to predict.\n        X : optional (default=None)\n            guaranteed to be of a type in self.get_tag(\"X_inner_mtype\")\n            Exogeneous time series for the forecast\n        coverage : list of float (guaranteed not None and floats in [0,1] interval)\n           nominal coverage(s) of predictive interval(s)\n\n        Returns\n        -------\n        pred_int : pd.DataFrame\n            Column has multi-index: first level is variable name from y in fit,\n                second level coverage fractions for which intervals were computed.\n                    in the same order as in input `coverage`.\n                Third level is string \"lower\" or \"upper\", for lower/upper interval end.\n            Row index is fh, with additional (upper) levels equal to instance levels,\n                from y seen in fit, if y_inner_mtype is Panel or Hierarchical.\n            Entries are forecasts of lower/upper interval end,\n                for var in col index, at nominal coverage in second col index,\n                lower/upper depending on third col index, for the row index.\n                Upper/lower interval end forecasts are equivalent to\n                quantile forecasts at alpha = 0.5 - c/2, 0.5 + c/2 for c in coverage.\n        \"\"\"\n        exog_fc = X.values if X is not None else None\n        fh_oos = fh.to_out_of_sample(self.cutoff)\n        var_names = (\n            self._y.index.name\n            if self._y.index.name is not None\n            else self._y.columns.values\n        )\n        int_idx = pd.MultiIndex.from_product([var_names, coverage, [\"lower\", \"upper\"]])\n        # pred_int = pd.DataFrame(index=int_idx)\n\n        for c in coverage:\n            alpha = 1 - c\n            _, y_lower, y_upper = self._fitted_forecaster.predict(\n                steps=fh_oos[-1],\n                exog_fc=exog_fc,\n                exog_coint_fc=self.exog_coint_fc,\n                alpha=alpha,\n            )\n            values = []\n            for v_idx in range(len(var_names)):\n                values.append(y_lower[0][v_idx])\n                values.append(y_upper[0][v_idx])\n                # pred_int.loc[(var_names[v_idx], c, \"lower\"), :] = (y_lower[0][v_idx])\n                # pred_int.loc[(var_names[v_idx], c, \"upper\"), :] = (y_upper[0][v_idx])\n        pred_int = pd.DataFrame(\n            [values], index=fh.to_absolute(self.cutoff), columns=int_idx\n        )\n\n        return pred_int\n", "path": "sktime/forecasting/vecm.py"}]}