We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[BUG] odd failure in `fh._coerce_to_period` that occurs only on windows, in context of hierarchical forecast
When making hierarchical forecasts on default output of `_make_hierarchical`, `fh.coerce_to_period` fails, on a windows run:
https://github.com/alan-turing-institute/sktime/runs/5503723513

This is quite strange, and I cannot reproduce the behaviour locally on my windows machine (python 3.8 or 3.9).

It looks like `freq` is not correctly preserved in subsetting from a hierarchical multi-index ... but only under specific conditions on a windows system???

Expected behaviour: the test does not fail, just like on linux/max and as on my local system.

--- 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/datatypes/_vectorize.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # copyright: sktime developers, BSD-3-Clause License (see LICENSE file)
3 """Wrapper for easy vectorization/iteration of time series data.
4 
5 Contains VectorizedDF class.
6 """
7 
8 import pandas as pd
9 
10 from sktime.datatypes._check import check_is_scitype, mtype
11 from sktime.datatypes._convert import convert_to
12 
13 
14 class VectorizedDF:
15     """Wrapper for easy vectorization/iteration over instances.
16 
17     VectorizedDF is an iterable that returns pandas.DataFrame
18         in sktime Series or Panel format.
19     Elements are all Series or Panels in X, these are iterated over.
20 
21     Parameters
22     ----------
23     X : object in sktime compatible Panel or Hierarchical format
24         the data container to vectorize over
25     y : placeholder argument, not used currently
26     is_scitype : str ("Panel", "Hierarchical") or None, default = "Panel"
27         scitype of X, if known; if None, will be inferred
28         provide to constructor if known to avoid superfluous checks
29             Caution: will not conduct checks if provided, assumes checks done
30     iterate_as : str ("Series", "Panel")
31         scitype of the iteration
32         for instance, if X is Panel and iterate_as is "Series"
33             then the class will iterate over individual Series in X
34         or, if X is Hierarchical and iterate_as is "Panel"
35             then the class will iterate over individual Panels in X
36                 (Panel = flat/non-hierarchical collection of Series)
37 
38     Methods
39     -------
40     self[i] or self.__getitem__(i)
41         Returns i-th Series/Panel (depending on iterate_as) in X
42         as pandas.DataFrame with Index or MultiIndex (in sktime pandas format)
43     len(self) or self.__len__
44         returns number of Series/Panel in X
45     get_iter_indices()
46         Returns pandas.(Multi)Index that are iterated over
47     reconstruct(self, df_list, convert_back=False)
48         Takes iterable df_list and returns as an object of is_scitype.
49         Used to obtain original format after applying operations to self iterated
50     """
51 
52     def __init__(self, X, y=None, iterate_as="Series", is_scitype="Panel"):
53 
54         self.X = X
55 
56         if is_scitype is None:
57             possible_scitypes = ["Panel", "Hierarchical"]
58             _, _, metadata = check_is_scitype(
59                 X, scitype=possible_scitypes, return_metadata=True
60             )
61             is_scitype = metadata["scitype"]
62             X_orig_mtype = metadata["mtype"]
63         else:
64             X_orig_mtype = None
65 
66         if is_scitype is not None and is_scitype not in ["Hierarchical", "Panel"]:
67             raise ValueError(
68                 'is_scitype must be None, "Hierarchical" or "Panel", ',
69                 f"found {is_scitype}",
70             )
71         self.iterate_as = iterate_as
72 
73         self.is_scitype = is_scitype
74         self.X_orig_mtype = X_orig_mtype
75 
76         if iterate_as not in ["Series", "Panel"]:
77             raise ValueError(
78                 f'iterate_as must be "Series" or "Panel", found {iterate_as}'
79             )
80         self.iterate_as = iterate_as
81 
82         if iterate_as == "Panel" and is_scitype == "Panel":
83             raise ValueError(
84                 'If is_scitype is "Panel", then iterate_as must be "Series"'
85             )
86 
87         self.converter_store = dict()
88 
89         self.X_multiindex = self._init_conversion(X)
90         self.iter_indices = self._init_iter_indices()
91 
92     def _init_conversion(self, X):
93         """Convert X to a pandas multiindex format."""
94         is_scitype = self.is_scitype
95 
96         if is_scitype == "Panel":
97             return convert_to(
98                 X,
99                 to_type="pd-multiindex",
100                 as_scitype="Panel",
101                 store=self.converter_store,
102             )
103         elif is_scitype == "Hierarchical":
104             return convert_to(
105                 X,
106                 to_type="pd_multiindex_hier",
107                 as_scitype="Hierarchical",
108                 store=self.converter_store,
109             )
110         else:
111             raise RuntimeError(
112                 f"unexpected value found for attribute self.is_scitype: {is_scitype}"
113                 'must be "Panel" or "Hierarchical"'
114             )
115 
116     def _init_iter_indices(self):
117         """Initialize indices that are iterated over in vectorization."""
118         iterate_as = self.iterate_as
119         X = self.X_multiindex
120 
121         if iterate_as == "Series":
122             ix = X.index.droplevel(-1).unique()
123             return ix
124         elif iterate_as == "Panel":
125             ix = X.index.droplevel([-1, -2]).unique()
126             return ix
127         else:
128             raise RuntimeError(
129                 f"unexpected value found for attribute self.iterate_as: {iterate_as}"
130                 'must be "Series" or "Panel"'
131             )
132 
133     def get_iter_indices(self):
134         """Get indices that are iterated over in vectorization.
135 
136         Returns
137         -------
138         pandas.Index or pandas.MultiIndex
139             index with unique indices that are iterated over
140             use to reconstruct data frame after iteration
141         """
142         return self.iter_indices
143 
144     def __len__(self):
145         """Return number of indices to iterate over."""
146         return len(self.get_iter_indices())
147 
148     def __getitem__(self, i: int):
149         """Return the i-th element iterated over in vectorization."""
150         X = self.X_multiindex
151         ind = self.get_iter_indices()[i]
152         item = X.loc[ind]
153         # pd-multiindex type (Panel case) expects these index names:
154         if self.iterate_as == "Panel":
155             item.index.set_names(["instances", "timepoints"], inplace=True)
156         return item
157 
158     def as_list(self):
159         """Shorthand to retrieve self (iterator) as list."""
160         return list(self)
161 
162     def reconstruct(self, df_list, convert_back=False, overwrite_index=True):
163         """Reconstruct original format from iterable of vectorization instances.
164 
165         Parameters
166         ----------
167         df_list : iterable of objects of same type as __getitem__ returns.
168             can be self, but will in general be another object to be useful.
169             Example: [some_operation(df) for df in self] that leaves types the same
170         convert_back : bool, default = False
171             whether to convert output back to mtype of X in __init__
172             if False, the return will be a pandas.DataFrame with Index or multiIndex
173             if True, the return is converted to the mtype of X in __init__
174         overwrite_index : bool, default = True
175             if True, the resulting return will have index overwritten by that of X
176                 only if applies, i.e., overwrite is possible and X had an index
177             if False, no index overwrite will happen
178 
179         Returns
180         -------
181         X_reconstructed_orig_format : row-concatenation of df-list,
182             with keys and additional level from self.get_iter_indices
183             if convert_back=False, always a pd.DataFrame in a sktime MultiIndex format
184                 (pd-multiindex mtype for Panel, or pd_multiindex_hier for Hierarchical)
185             if convert_back=True, will have same format and mtype as X input to __init__
186         """
187         ix = self.get_iter_indices()
188         X_mi_reconstructed = pd.concat(df_list, keys=ix)
189 
190         X_mi_index = X_mi_reconstructed.index
191         X_orig_index = self.X_multiindex.index
192         if overwrite_index and len(X_mi_index.names) == len(X_orig_index.names):
193             X_mi_reconstructed.index.set_names(X_orig_index.names)
194 
195         if not convert_back:
196             return X_mi_reconstructed
197         else:
198             X_orig_mtype = self.X_orig_mtype
199             is_scitype = self.is_scitype
200             if X_orig_mtype is None:
201                 X_orig_mtype = mtype(self.X, as_scitype=self.is_scitype)
202 
203             X_reconstructed_orig_format = convert_to(
204                 X_mi_reconstructed,
205                 to_type=X_orig_mtype,
206                 as_scitype=is_scitype,
207                 store=self.converter_store,
208             )
209 
210             return X_reconstructed_orig_format
211
```
--- 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/datatypes/_vectorize.py b/sktime/datatypes/_vectorize.py
--- a/sktime/datatypes/_vectorize.py
+++ b/sktime/datatypes/_vectorize.py
@@ -4,7 +4,6 @@
 
 Contains VectorizedDF class.
 """
-
 import pandas as pd
 
 from sktime.datatypes._check import check_is_scitype, mtype
@@ -150,6 +149,7 @@
         X = self.X_multiindex
         ind = self.get_iter_indices()[i]
         item = X.loc[ind]
+        item = _enforce_index_freq(item)
         # pd-multiindex type (Panel case) expects these index names:
         if self.iterate_as == "Panel":
             item.index.set_names(["instances", "timepoints"], inplace=True)
@@ -208,3 +208,20 @@
             )
 
             return X_reconstructed_orig_format
+
+
+def _enforce_index_freq(item: pd.Series) -> pd.Series:
+    """Enforce the frequency of a Series index using pd.infer_freq.
+
+    Parameters
+    ----------
+    item : pd.Series
+    Returns
+    -------
+    pd.Series
+        Pandas series with the inferred frequency. If the frequency cannot be inferred
+        it will stay None
+    """
+    if hasattr(item.index, "freq") and item.index.freq is None:
+        item.index.freq = pd.infer_freq(item.index)
+    return item

{"golden_diff": "diff --git a/sktime/datatypes/_vectorize.py b/sktime/datatypes/_vectorize.py\n--- a/sktime/datatypes/_vectorize.py\n+++ b/sktime/datatypes/_vectorize.py\n@@ -4,7 +4,6 @@\n \n Contains VectorizedDF class.\n \"\"\"\n-\n import pandas as pd\n \n from sktime.datatypes._check import check_is_scitype, mtype\n@@ -150,6 +149,7 @@\n         X = self.X_multiindex\n         ind = self.get_iter_indices()[i]\n         item = X.loc[ind]\n+        item = _enforce_index_freq(item)\n         # pd-multiindex type (Panel case) expects these index names:\n         if self.iterate_as == \"Panel\":\n             item.index.set_names([\"instances\", \"timepoints\"], inplace=True)\n@@ -208,3 +208,20 @@\n             )\n \n             return X_reconstructed_orig_format\n+\n+\n+def _enforce_index_freq(item: pd.Series) -> pd.Series:\n+    \"\"\"Enforce the frequency of a Series index using pd.infer_freq.\n+\n+    Parameters\n+    ----------\n+    item : pd.Series\n+    Returns\n+    -------\n+    pd.Series\n+        Pandas series with the inferred frequency. If the frequency cannot be inferred\n+        it will stay None\n+    \"\"\"\n+    if hasattr(item.index, \"freq\") and item.index.freq is None:\n+        item.index.freq = pd.infer_freq(item.index)\n+    return item\n", "issue": "[BUG] odd failure in `fh._coerce_to_period` that occurs only on windows, in context of hierarchical forecast\nWhen making hierarchical forecasts on default output of `_make_hierarchical`, `fh.coerce_to_period` fails, on a windows run:\r\nhttps://github.com/alan-turing-institute/sktime/runs/5503723513\r\n\r\nThis is quite strange, and I cannot reproduce the behaviour locally on my windows machine (python 3.8 or 3.9).\r\n\r\nIt looks like `freq` is not correctly preserved in subsetting from a hierarchical multi-index ... but only under specific conditions on a windows system???\r\n\r\nExpected behaviour: the test does not fail, just like on linux/max and as on my local system.\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# copyright: sktime developers, BSD-3-Clause License (see LICENSE file)\n\"\"\"Wrapper for easy vectorization/iteration of time series data.\n\nContains VectorizedDF class.\n\"\"\"\n\nimport pandas as pd\n\nfrom sktime.datatypes._check import check_is_scitype, mtype\nfrom sktime.datatypes._convert import convert_to\n\n\nclass VectorizedDF:\n    \"\"\"Wrapper for easy vectorization/iteration over instances.\n\n    VectorizedDF is an iterable that returns pandas.DataFrame\n        in sktime Series or Panel format.\n    Elements are all Series or Panels in X, these are iterated over.\n\n    Parameters\n    ----------\n    X : object in sktime compatible Panel or Hierarchical format\n        the data container to vectorize over\n    y : placeholder argument, not used currently\n    is_scitype : str (\"Panel\", \"Hierarchical\") or None, default = \"Panel\"\n        scitype of X, if known; if None, will be inferred\n        provide to constructor if known to avoid superfluous checks\n            Caution: will not conduct checks if provided, assumes checks done\n    iterate_as : str (\"Series\", \"Panel\")\n        scitype of the iteration\n        for instance, if X is Panel and iterate_as is \"Series\"\n            then the class will iterate over individual Series in X\n        or, if X is Hierarchical and iterate_as is \"Panel\"\n            then the class will iterate over individual Panels in X\n                (Panel = flat/non-hierarchical collection of Series)\n\n    Methods\n    -------\n    self[i] or self.__getitem__(i)\n        Returns i-th Series/Panel (depending on iterate_as) in X\n        as pandas.DataFrame with Index or MultiIndex (in sktime pandas format)\n    len(self) or self.__len__\n        returns number of Series/Panel in X\n    get_iter_indices()\n        Returns pandas.(Multi)Index that are iterated over\n    reconstruct(self, df_list, convert_back=False)\n        Takes iterable df_list and returns as an object of is_scitype.\n        Used to obtain original format after applying operations to self iterated\n    \"\"\"\n\n    def __init__(self, X, y=None, iterate_as=\"Series\", is_scitype=\"Panel\"):\n\n        self.X = X\n\n        if is_scitype is None:\n            possible_scitypes = [\"Panel\", \"Hierarchical\"]\n            _, _, metadata = check_is_scitype(\n                X, scitype=possible_scitypes, return_metadata=True\n            )\n            is_scitype = metadata[\"scitype\"]\n            X_orig_mtype = metadata[\"mtype\"]\n        else:\n            X_orig_mtype = None\n\n        if is_scitype is not None and is_scitype not in [\"Hierarchical\", \"Panel\"]:\n            raise ValueError(\n                'is_scitype must be None, \"Hierarchical\" or \"Panel\", ',\n                f\"found {is_scitype}\",\n            )\n        self.iterate_as = iterate_as\n\n        self.is_scitype = is_scitype\n        self.X_orig_mtype = X_orig_mtype\n\n        if iterate_as not in [\"Series\", \"Panel\"]:\n            raise ValueError(\n                f'iterate_as must be \"Series\" or \"Panel\", found {iterate_as}'\n            )\n        self.iterate_as = iterate_as\n\n        if iterate_as == \"Panel\" and is_scitype == \"Panel\":\n            raise ValueError(\n                'If is_scitype is \"Panel\", then iterate_as must be \"Series\"'\n            )\n\n        self.converter_store = dict()\n\n        self.X_multiindex = self._init_conversion(X)\n        self.iter_indices = self._init_iter_indices()\n\n    def _init_conversion(self, X):\n        \"\"\"Convert X to a pandas multiindex format.\"\"\"\n        is_scitype = self.is_scitype\n\n        if is_scitype == \"Panel\":\n            return convert_to(\n                X,\n                to_type=\"pd-multiindex\",\n                as_scitype=\"Panel\",\n                store=self.converter_store,\n            )\n        elif is_scitype == \"Hierarchical\":\n            return convert_to(\n                X,\n                to_type=\"pd_multiindex_hier\",\n                as_scitype=\"Hierarchical\",\n                store=self.converter_store,\n            )\n        else:\n            raise RuntimeError(\n                f\"unexpected value found for attribute self.is_scitype: {is_scitype}\"\n                'must be \"Panel\" or \"Hierarchical\"'\n            )\n\n    def _init_iter_indices(self):\n        \"\"\"Initialize indices that are iterated over in vectorization.\"\"\"\n        iterate_as = self.iterate_as\n        X = self.X_multiindex\n\n        if iterate_as == \"Series\":\n            ix = X.index.droplevel(-1).unique()\n            return ix\n        elif iterate_as == \"Panel\":\n            ix = X.index.droplevel([-1, -2]).unique()\n            return ix\n        else:\n            raise RuntimeError(\n                f\"unexpected value found for attribute self.iterate_as: {iterate_as}\"\n                'must be \"Series\" or \"Panel\"'\n            )\n\n    def get_iter_indices(self):\n        \"\"\"Get indices that are iterated over in vectorization.\n\n        Returns\n        -------\n        pandas.Index or pandas.MultiIndex\n            index with unique indices that are iterated over\n            use to reconstruct data frame after iteration\n        \"\"\"\n        return self.iter_indices\n\n    def __len__(self):\n        \"\"\"Return number of indices to iterate over.\"\"\"\n        return len(self.get_iter_indices())\n\n    def __getitem__(self, i: int):\n        \"\"\"Return the i-th element iterated over in vectorization.\"\"\"\n        X = self.X_multiindex\n        ind = self.get_iter_indices()[i]\n        item = X.loc[ind]\n        # pd-multiindex type (Panel case) expects these index names:\n        if self.iterate_as == \"Panel\":\n            item.index.set_names([\"instances\", \"timepoints\"], inplace=True)\n        return item\n\n    def as_list(self):\n        \"\"\"Shorthand to retrieve self (iterator) as list.\"\"\"\n        return list(self)\n\n    def reconstruct(self, df_list, convert_back=False, overwrite_index=True):\n        \"\"\"Reconstruct original format from iterable of vectorization instances.\n\n        Parameters\n        ----------\n        df_list : iterable of objects of same type as __getitem__ returns.\n            can be self, but will in general be another object to be useful.\n            Example: [some_operation(df) for df in self] that leaves types the same\n        convert_back : bool, default = False\n            whether to convert output back to mtype of X in __init__\n            if False, the return will be a pandas.DataFrame with Index or multiIndex\n            if True, the return is converted to the mtype of X in __init__\n        overwrite_index : bool, default = True\n            if True, the resulting return will have index overwritten by that of X\n                only if applies, i.e., overwrite is possible and X had an index\n            if False, no index overwrite will happen\n\n        Returns\n        -------\n        X_reconstructed_orig_format : row-concatenation of df-list,\n            with keys and additional level from self.get_iter_indices\n            if convert_back=False, always a pd.DataFrame in a sktime MultiIndex format\n                (pd-multiindex mtype for Panel, or pd_multiindex_hier for Hierarchical)\n            if convert_back=True, will have same format and mtype as X input to __init__\n        \"\"\"\n        ix = self.get_iter_indices()\n        X_mi_reconstructed = pd.concat(df_list, keys=ix)\n\n        X_mi_index = X_mi_reconstructed.index\n        X_orig_index = self.X_multiindex.index\n        if overwrite_index and len(X_mi_index.names) == len(X_orig_index.names):\n            X_mi_reconstructed.index.set_names(X_orig_index.names)\n\n        if not convert_back:\n            return X_mi_reconstructed\n        else:\n            X_orig_mtype = self.X_orig_mtype\n            is_scitype = self.is_scitype\n            if X_orig_mtype is None:\n                X_orig_mtype = mtype(self.X, as_scitype=self.is_scitype)\n\n            X_reconstructed_orig_format = convert_to(\n                X_mi_reconstructed,\n                to_type=X_orig_mtype,\n                as_scitype=is_scitype,\n                store=self.converter_store,\n            )\n\n            return X_reconstructed_orig_format\n", "path": "sktime/datatypes/_vectorize.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n# copyright: sktime developers, BSD-3-Clause License (see LICENSE file)\n\"\"\"Wrapper for easy vectorization/iteration of time series data.\n\nContains VectorizedDF class.\n\"\"\"\nimport pandas as pd\n\nfrom sktime.datatypes._check import check_is_scitype, mtype\nfrom sktime.datatypes._convert import convert_to\n\n\nclass VectorizedDF:\n    \"\"\"Wrapper for easy vectorization/iteration over instances.\n\n    VectorizedDF is an iterable that returns pandas.DataFrame\n        in sktime Series or Panel format.\n    Elements are all Series or Panels in X, these are iterated over.\n\n    Parameters\n    ----------\n    X : object in sktime compatible Panel or Hierarchical format\n        the data container to vectorize over\n    y : placeholder argument, not used currently\n    is_scitype : str (\"Panel\", \"Hierarchical\") or None, default = \"Panel\"\n        scitype of X, if known; if None, will be inferred\n        provide to constructor if known to avoid superfluous checks\n            Caution: will not conduct checks if provided, assumes checks done\n    iterate_as : str (\"Series\", \"Panel\")\n        scitype of the iteration\n        for instance, if X is Panel and iterate_as is \"Series\"\n            then the class will iterate over individual Series in X\n        or, if X is Hierarchical and iterate_as is \"Panel\"\n            then the class will iterate over individual Panels in X\n                (Panel = flat/non-hierarchical collection of Series)\n\n    Methods\n    -------\n    self[i] or self.__getitem__(i)\n        Returns i-th Series/Panel (depending on iterate_as) in X\n        as pandas.DataFrame with Index or MultiIndex (in sktime pandas format)\n    len(self) or self.__len__\n        returns number of Series/Panel in X\n    get_iter_indices()\n        Returns pandas.(Multi)Index that are iterated over\n    reconstruct(self, df_list, convert_back=False)\n        Takes iterable df_list and returns as an object of is_scitype.\n        Used to obtain original format after applying operations to self iterated\n    \"\"\"\n\n    def __init__(self, X, y=None, iterate_as=\"Series\", is_scitype=\"Panel\"):\n\n        self.X = X\n\n        if is_scitype is None:\n            possible_scitypes = [\"Panel\", \"Hierarchical\"]\n            _, _, metadata = check_is_scitype(\n                X, scitype=possible_scitypes, return_metadata=True\n            )\n            is_scitype = metadata[\"scitype\"]\n            X_orig_mtype = metadata[\"mtype\"]\n        else:\n            X_orig_mtype = None\n\n        if is_scitype is not None and is_scitype not in [\"Hierarchical\", \"Panel\"]:\n            raise ValueError(\n                'is_scitype must be None, \"Hierarchical\" or \"Panel\", ',\n                f\"found {is_scitype}\",\n            )\n        self.iterate_as = iterate_as\n\n        self.is_scitype = is_scitype\n        self.X_orig_mtype = X_orig_mtype\n\n        if iterate_as not in [\"Series\", \"Panel\"]:\n            raise ValueError(\n                f'iterate_as must be \"Series\" or \"Panel\", found {iterate_as}'\n            )\n        self.iterate_as = iterate_as\n\n        if iterate_as == \"Panel\" and is_scitype == \"Panel\":\n            raise ValueError(\n                'If is_scitype is \"Panel\", then iterate_as must be \"Series\"'\n            )\n\n        self.converter_store = dict()\n\n        self.X_multiindex = self._init_conversion(X)\n        self.iter_indices = self._init_iter_indices()\n\n    def _init_conversion(self, X):\n        \"\"\"Convert X to a pandas multiindex format.\"\"\"\n        is_scitype = self.is_scitype\n\n        if is_scitype == \"Panel\":\n            return convert_to(\n                X,\n                to_type=\"pd-multiindex\",\n                as_scitype=\"Panel\",\n                store=self.converter_store,\n            )\n        elif is_scitype == \"Hierarchical\":\n            return convert_to(\n                X,\n                to_type=\"pd_multiindex_hier\",\n                as_scitype=\"Hierarchical\",\n                store=self.converter_store,\n            )\n        else:\n            raise RuntimeError(\n                f\"unexpected value found for attribute self.is_scitype: {is_scitype}\"\n                'must be \"Panel\" or \"Hierarchical\"'\n            )\n\n    def _init_iter_indices(self):\n        \"\"\"Initialize indices that are iterated over in vectorization.\"\"\"\n        iterate_as = self.iterate_as\n        X = self.X_multiindex\n\n        if iterate_as == \"Series\":\n            ix = X.index.droplevel(-1).unique()\n            return ix\n        elif iterate_as == \"Panel\":\n            ix = X.index.droplevel([-1, -2]).unique()\n            return ix\n        else:\n            raise RuntimeError(\n                f\"unexpected value found for attribute self.iterate_as: {iterate_as}\"\n                'must be \"Series\" or \"Panel\"'\n            )\n\n    def get_iter_indices(self):\n        \"\"\"Get indices that are iterated over in vectorization.\n\n        Returns\n        -------\n        pandas.Index or pandas.MultiIndex\n            index with unique indices that are iterated over\n            use to reconstruct data frame after iteration\n        \"\"\"\n        return self.iter_indices\n\n    def __len__(self):\n        \"\"\"Return number of indices to iterate over.\"\"\"\n        return len(self.get_iter_indices())\n\n    def __getitem__(self, i: int):\n        \"\"\"Return the i-th element iterated over in vectorization.\"\"\"\n        X = self.X_multiindex\n        ind = self.get_iter_indices()[i]\n        item = X.loc[ind]\n        item = _enforce_index_freq(item)\n        # pd-multiindex type (Panel case) expects these index names:\n        if self.iterate_as == \"Panel\":\n            item.index.set_names([\"instances\", \"timepoints\"], inplace=True)\n        return item\n\n    def as_list(self):\n        \"\"\"Shorthand to retrieve self (iterator) as list.\"\"\"\n        return list(self)\n\n    def reconstruct(self, df_list, convert_back=False, overwrite_index=True):\n        \"\"\"Reconstruct original format from iterable of vectorization instances.\n\n        Parameters\n        ----------\n        df_list : iterable of objects of same type as __getitem__ returns.\n            can be self, but will in general be another object to be useful.\n            Example: [some_operation(df) for df in self] that leaves types the same\n        convert_back : bool, default = False\n            whether to convert output back to mtype of X in __init__\n            if False, the return will be a pandas.DataFrame with Index or multiIndex\n            if True, the return is converted to the mtype of X in __init__\n        overwrite_index : bool, default = True\n            if True, the resulting return will have index overwritten by that of X\n                only if applies, i.e., overwrite is possible and X had an index\n            if False, no index overwrite will happen\n\n        Returns\n        -------\n        X_reconstructed_orig_format : row-concatenation of df-list,\n            with keys and additional level from self.get_iter_indices\n            if convert_back=False, always a pd.DataFrame in a sktime MultiIndex format\n                (pd-multiindex mtype for Panel, or pd_multiindex_hier for Hierarchical)\n            if convert_back=True, will have same format and mtype as X input to __init__\n        \"\"\"\n        ix = self.get_iter_indices()\n        X_mi_reconstructed = pd.concat(df_list, keys=ix)\n\n        X_mi_index = X_mi_reconstructed.index\n        X_orig_index = self.X_multiindex.index\n        if overwrite_index and len(X_mi_index.names) == len(X_orig_index.names):\n            X_mi_reconstructed.index.set_names(X_orig_index.names)\n\n        if not convert_back:\n            return X_mi_reconstructed\n        else:\n            X_orig_mtype = self.X_orig_mtype\n            is_scitype = self.is_scitype\n            if X_orig_mtype is None:\n                X_orig_mtype = mtype(self.X, as_scitype=self.is_scitype)\n\n            X_reconstructed_orig_format = convert_to(\n                X_mi_reconstructed,\n                to_type=X_orig_mtype,\n                as_scitype=is_scitype,\n                store=self.converter_store,\n            )\n\n            return X_reconstructed_orig_format\n\n\ndef _enforce_index_freq(item: pd.Series) -> pd.Series:\n    \"\"\"Enforce the frequency of a Series index using pd.infer_freq.\n\n    Parameters\n    ----------\n    item : pd.Series\n    Returns\n    -------\n    pd.Series\n        Pandas series with the inferred frequency. If the frequency cannot be inferred\n        it will stay None\n    \"\"\"\n    if hasattr(item.index, \"freq\") and item.index.freq is None:\n        item.index.freq = pd.infer_freq(item.index)\n    return item\n", "path": "sktime/datatypes/_vectorize.py"}]}