Repository: sktime/sktime (python)

Issue:
[BUG] `dask` related failures
Some tests fail with a dask related issue, unclear source, direct at init of tests - FYI @yarnabrina, are these the failures you talked about?

Exampel: https://github.com/sktime/sktime/actions/runs/8613435074/job/23605843798?pr=6278

Traceback:
```
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/_pytest/main.py", line 281, in wrap_session
INTERNALERROR>     config._do_configure()
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/_pytest/config/__init__.py", line 1121, in _do_configure
INTERNALERROR>     self.hook.pytest_configure.call_historic(kwargs=dict(config=self))
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/pluggy/_hooks.py", line 523, in call_historic
INTERNALERROR>     res = self._hookexec(self.name, self._hookimpls.copy(), kwargs, False)
INTERNALERROR>           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/pluggy/_manager.py", line 119, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/pluggy/_callers.py", line 138, in _multicall
INTERNALERROR>     raise exception.with_traceback(exception.__traceback__)
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/pluggy/_callers.py", line 102, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>           ^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/home/runner/work/sktime/sktime/conftest.py", line 51, in pytest_configure
INTERNALERROR>     from sktime.tests import test_all_estimators
INTERNALERROR>   File "/home/runner/work/sktime/sktime/sktime/__init__.py", line 7, in <module>
INTERNALERROR>     from sktime.utils._maint._show_versions import show_versions
INTERNALERROR>   File "/home/runner/work/sktime/sktime/sktime/utils/__init__.py", line 4, in <module>
INTERNALERROR>     from sktime.utils.plotting import plot_series, plot_windows
INTERNALERROR>   File "/home/runner/work/sktime/sktime/sktime/utils/plotting.py", line 14, in <module>
INTERNALERROR>     from sktime.datatypes import convert_to
INTERNALERROR>   File "/home/runner/work/sktime/sktime/sktime/datatypes/__init__.py", line 5, in <module>
INTERNALERROR>     from sktime.datatypes._check import (
INTERNALERROR>   File "/home/runner/work/sktime/sktime/sktime/datatypes/_check.py", line 32, in <module>
INTERNALERROR>     from sktime.datatypes._hierarchical import check_dict_Hierarchical
INTERNALERROR>   File "/home/runner/work/sktime/sktime/sktime/datatypes/_hierarchical/__init__.py", line 3, in <module>
INTERNALERROR>     from sktime.datatypes._hierarchical._check import check_dict as check_dict_Hierarchical
INTERNALERROR>   File "/home/runner/work/sktime/sktime/sktime/datatypes/_hierarchical/_check.py", line 49, in <module>
INTERNALERROR>     from sktime.datatypes._panel._check import check_pdmultiindex_panel
INTERNALERROR>   File "/home/runner/work/sktime/sktime/sktime/datatypes/_panel/__init__.py", line 3, in <module>
INTERNALERROR>     from sktime.datatypes._panel._check import check_dict as check_dict_Panel
INTERNALERROR>   File "/home/runner/work/sktime/sktime/sktime/datatypes/_panel/_check.py", line 50, in <module>
INTERNALERROR>     from sktime.datatypes._series._check import (
INTERNALERROR>   File "/home/runner/work/sktime/sktime/sktime/datatypes/_series/__init__.py", line 5, in <module>
INTERNALERROR>     from sktime.datatypes._series._examples import example_dict as example_dict_Series
INTERNALERROR>   File "/home/runner/work/sktime/sktime/sktime/datatypes/_series/_examples.py", line 70, in <module>
INTERNALERROR>     from dask.dataframe import from_pandas
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/dask/dataframe/__init__.py", line 100, in <module>
INTERNALERROR>     from dask.dataframe import backends, dispatch, rolling
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/dask/dataframe/backends.py", line 15, in <module>
INTERNALERROR>     from dask.dataframe.core import DataFrame, Index, Scalar, Series, _Frame
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/dask/dataframe/core.py", line 36, in <module>
INTERNALERROR>     from dask.dataframe import methods
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/dask/dataframe/methods.py", line 34, in <module>
INTERNALERROR>     from dask.dataframe.utils import is_dataframe_like, is_index_like, is_series_like
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/dask/dataframe/utils.py", line 20, in <module>
INTERNALERROR>     from dask.dataframe import (  # noqa: F401 register pandas extension types
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/dask/dataframe/_dtypes.py", line 9, in <module>
INTERNALERROR>     from dask.dataframe.extensions import make_array_nonempty, make_scalar
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/dask/dataframe/extensions.py", line 8, in <module>
INTERNALERROR>     from dask.dataframe.accessor import (
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/dask/dataframe/accessor.py", line 126, in <module>
INTERNALERROR>     class DatetimeAccessor(Accessor):
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/dask/dataframe/accessor.py", line 81, in __init_subclass__
INTERNALERROR>     _bind_property(cls, pd_cls, attr, min_version)
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/dask/dataframe/accessor.py", line 35, in _bind_property
INTERNALERROR>     setattr(cls, attr, property(derived_from(pd_cls, version=min_version)(func)))
INTERNALERROR>                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/dask/utils.py", line 987, in wrapper
INTERNALERROR>     method.__doc__ = _derived_from(
INTERNALERROR>                      ^^^^^^^^^^^^^^
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/dask/utils.py", line 940, in _derived_from
INTERNALERROR>     method_args = get_named_args(method)
INTERNALERROR>                   ^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/site-packages/dask/utils.py", line 701, in get_named_args
INTERNALERROR>     s = inspect.signature(func)
INTERNALERROR>         ^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/inspect.py", line 3263, in signature
INTERNALERROR>     return Signature.from_callable(obj, follow_wrapped=follow_wrapped,
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/inspect.py", line 3011, in from_callable
INTERNALERROR>     return _signature_from_callable(obj, sigcls=cls,
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/inspect.py", line 2599, in _signature_from_callable
INTERNALERROR>     call = _descriptor_get(call, obj)
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR>   File "/opt/hostedtoolcache/Python/3.11.9/x64/lib/python3.11/inspect.py", line 2432, in _descriptor_get
INTERNALERROR>     return get(descriptor, obj, type(obj))
INTERNALERROR>            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
INTERNALERROR> TypeError: descriptor '__call__' for 'type' objects doesn't apply to a 'property' object
```

Pull request:
[MNT] Update dask requirement from `<2024.2.2` to `<2024.4.2`, add new required `dataframe` extra to `pyproject.toml`.
Fixes #6280 by updating `dask` to the newest version which fixes incompatibility with python 3.11.9

Patch:
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 1ffe451b0..e433f2021 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -2343,7 +2343,9 @@
       "profile": "https://github.com/Ram0nB",
       "contributions": [
         "doc",
-        "code"
+        "code",
+        "bug",
+        "test"
       ]
     },
     {
diff --git a/extension_templates/alignment.py b/extension_templates/alignment.py
index edad36fd8..4b865f455 100644
--- a/extension_templates/alignment.py
+++ b/extension_templates/alignment.py
@@ -82,7 +82,10 @@ class MyAligner(BaseAligner):
         "authors": ["author1", "author2"],  # authors, GitHub handles
         "maintainers": ["maintainer1", "maintainer2"],  # maintainers, GitHub handles
         # author = significant contribution to code at some point
-        # maintainer = algorithm maintainer role, "owner"
+        #     if interfacing a 3rd party estimator, ensure to give credit to the
+        #     authors of the interfaced estimator
+        # maintainer = algorithm maintainer role, "owner" of the sktime class
+        #     for 3rd party interfaces, the scope is the sktime class only
         # specify one or multiple authors and maintainers, only for sktime contribution
         # remove maintainer tag if maintained by sktime core team
         #
diff --git a/extension_templates/classification.py b/extension_templates/classification.py
index bdd23a5ef..5448a4296 100644
--- a/extension_templates/classification.py
+++ b/extension_templates/classification.py
@@ -82,8 +82,11 @@ class MyTimeSeriesClassifier(BaseClassifier):
         "authors": ["author1", "author2"],  # authors, GitHub handles
         "maintainers": ["maintainer1", "maintainer2"],  # maintainers, GitHub handles
         # author = significant contribution to code at some point
-        # maintainer = algorithm maintainer role, "owner"
-        # specify one or multiple authors and maintainers, only for sktime contribution
+        #     if interfacing a 3rd party estimator, ensure to give credit to the
+        #     authors of the interfaced estimator
+        # maintainer = algorithm maintainer role, "owner" of the sktime class
+        #     for 3rd party interfaces, the scope is the sktime class only
+        # specify one or multiple authors and maintainers
         # remove maintainer tag if maintained by sktime core team
         #
         "python_version": None,  # PEP 440 python version specifier to limit versions
diff --git a/extension_templates/clustering.py b/extension_templates/clustering.py
index 8d538d8d1..7e4cdd888 100644
--- a/extension_templates/clustering.py
+++ b/extension_templates/clustering.py
@@ -77,7 +77,10 @@ class MyClusterer(BaseClusterer):
         "authors": ["author1", "author2"],  # authors, GitHub handles
         "maintainers": ["maintainer1", "maintainer2"],  # maintainers, GitHub handles
         # author = significant contribution to code at some point
-        # maintainer = algorithm maintainer role, "owner"
+        #     if interfacing a 3rd party estimator, ensure to give credit to the
+        #     authors of the interfaced estimator
+        # maintainer = algorithm maintainer role, "owner" of the sktime class
+        #     for 3rd party interfaces, the scope is the sktime class only
         # specify one or multiple authors and maintainers, only for sktime contribution
         # remove maintainer tag if maintained by sktime core team
         #
diff --git a/extension_templates/dist_kern_panel.py b/extension_templates/dist_kern_panel.py
index b23d729eb..7d7400df3 100644
--- a/extension_templates/dist_kern_panel.py
+++ b/extension_templates/dist_kern_panel.py
@@ -62,7 +62,10 @@ class MyTrafoPwPanel(BasePairwiseTransformerPanel):
         "authors": ["author1", "author2"],  # authors, GitHub handles
         "maintainers": ["maintainer1", "maintainer2"],  # maintainers, GitHub handles
         # author = significant contribution to code at some point
-        # maintainer = algorithm maintainer role, "owner"
+        #     if interfacing a 3rd party estimator, ensure to give credit to the
+        #     authors of the interfaced estimator
+        # maintainer = algorithm maintainer role, "owner" of the sktime class
+        #     for 3rd party interfaces, the scope is the sktime class only
         # remove maintainer tag if maintained by sktime core team
     }
     # in case of inheritance, concrete class should typically set tags
diff --git a/extension_templates/dist_kern_tab.py b/extension_templates/dist_kern_tab.py
index 66f76ebe4..f82d26c6f 100644
--- a/extension_templates/dist_kern_tab.py
+++ b/extension_templates/dist_kern_tab.py
@@ -62,7 +62,10 @@ class MyTrafoPw(BasePairwiseTransformer):
         "authors": ["author1", "author2"],  # authors, GitHub handles
         "maintainers": ["maintainer1", "maintainer2"],  # maintainers, GitHub handles
         # author = significant contribution to code at some point
-        # maintainer = algorithm maintainer role, "owner"
+        #     if interfacing a 3rd party estimator, ensure to give credit to the
+        #     authors of the interfaced estimator
+        # maintainer = algorithm maintainer role, "owner" of the sktime class
+        #     for 3rd party interfaces, the scope is the sktime class only
         # remove maintainer tag if maintained by sktime core team
     }
     # in case of inheritance, concrete class should typically set tags
diff --git a/extension_templates/forecasting.py b/extension_templates/forecasting.py
index 3b7e9f6c8..e27c88cf5 100644
--- a/extension_templates/forecasting.py
+++ b/extension_templates/forecasting.py
@@ -165,10 +165,13 @@ class MyForecaster(BaseForecaster):
         # valid values: str or list of str, should be GitHub handles
         # this should follow best scientific contribution practices
         # scope is the code, not the methodology (method is per paper citation)
+        # if interfacing a 3rd party estimator, ensure to give credit to the
+        # authors of the interfaced estimator
         #
         # maintainer = current maintainer(s) of the estimator
         # per algorithm maintainer role, see governance document
         # this is an "owner" type role, with rights and maintenance duties
+        # for 3rd party interfaces, the scope is the sktime class only
         "maintainers": ["maintainer1", "maintainer2"],
         # valid values: str or list of str, should be GitHub handles
         # remove tag if maintained by sktime core team
diff --git a/extension_templates/forecasting_simple.py b/extension_templates/forecasting_simple.py
index 33b44610b..418ef40ab 100644
--- a/extension_templates/forecasting_simple.py
+++ b/extension_templates/forecasting_simple.py
@@ -117,10 +117,13 @@ class MyForecaster(BaseForecaster):
         # valid values: str or list of str, should be GitHub handles
         # this should follow best scientific contribution practices
         # scope is the code, not the methodology (method is per paper citation)
+        # if interfacing a 3rd party estimator, ensure to give credit to the
+        # authors of the interfaced estimator
         #
         # maintainer = current maintainer(s) of the estimator
         # per algorithm maintainer role, see governance document
         # this is an "owner" type role, with rights and maintenance duties
+        # for 3rd party interfaces, the scope is the sktime class only
         "maintainers": ["maintainer1", "maintainer2"],
         # valid values: str or list of str, should be GitHub handles
         # remove tag if maintained by sktime core team
diff --git a/extension_templates/forecasting_supersimple.py b/extension_templates/forecasting_supersimple.py
index bcd48692f..a13745188 100644
--- a/extension_templates/forecasting_supersimple.py
+++ b/extension_templates/forecasting_supersimple.py
@@ -76,7 +76,10 @@ class MyForecaster(BaseForecaster):
         "authors": ["author1", "author2"],  # authors, GitHub handles
         "maintainers": ["maintainer1", "maintainer2"],  # maintainers, GitHub handles
         # author = significant contribution to code at some point
-        # maintainer = algorithm maintainer role, "owner"
+        #     if interfacing a 3rd party estimator, ensure to give credit to the
+        #     authors of the interfaced estimator
+        # maintainer = algorithm maintainer role, "owner" of the sktime class
+        #     for 3rd party interfaces, the scope is the sktime class only
         # remove maintainer tag if maintained by sktime core team
         #
         # do not change these:
diff --git a/extension_templates/split.py b/extension_templates/split.py
index e6cf3475b..785fb811c 100644
--- a/extension_templates/split.py
+++ b/extension_templates/split.py
@@ -101,10 +101,13 @@ class MySplitter(BaseSplitter):
         # valid values: str or list of str, should be GitHub handles
         # this should follow best scientific contribution practices
         # scope is the code, not the methodology (method is per paper citation)
+        # if interfacing a 3rd party estimator, ensure to give credit to the
+        # authors of the interfaced estimator
         #
         # maintainer = current maintainer(s) of the estimator
         # per algorithm maintainer role, see governance document
         # this is an "owner" type role, with rights and maintenance duties
+        # for 3rd party interfaces, the scope is the sktime class only
         "maintainers": ["maintainer1", "maintainer2"],
         # valid values: str or list of str, should be GitHub handles
         # remove tag if maintained by sktime core team
diff --git a/extension_templates/transformer.py b/extension_templates/transformer.py
index 85feab21b..33d563170 100644
--- a/extension_templates/transformer.py
+++ b/extension_templates/transformer.py
@@ -257,10 +257,13 @@ class MyTransformer(BaseTransformer):
         # valid values: str or list of str, should be GitHub handles
         # this should follow best scientific contribution practices
         # scope is the code, not the methodology (method is per paper citation)
+        # if interfacing a 3rd party estimator, ensure to give credit to the
+        # authors of the interfaced estimator
         #
         # maintainer = current maintainer(s) of the estimator
         # per algorithm maintainer role, see governance document
         # this is an "owner" type role, with rights and maintenance duties
+        # for 3rd party interfaces, the scope is the sktime class only
         "maintainers": ["maintainer1", "maintainer2"],
         # valid values: str or list of str, should be GitHub handles
         # remove tag if maintained by sktime core team
diff --git a/extension_templates/transformer_simple.py b/extension_templates/transformer_simple.py
index 887642e1b..78e8e899a 100644
--- a/extension_templates/transformer_simple.py
+++ b/extension_templates/transformer_simple.py
@@ -182,10 +182,13 @@ class MyTransformer(BaseTransformer):
         # valid values: str or list of str, should be GitHub handles
         # this should follow best scientific contribution practices
         # scope is the code, not the methodology (method is per paper citation)
+        # if interfacing a 3rd party estimator, ensure to give credit to the
+        # authors of the interfaced estimator
         #
         # maintainer = current maintainer(s) of the estimator
         # per algorithm maintainer role, see governance document
         # this is an "owner" type role, with rights and maintenance duties
+        # for 3rd party interfaces, the scope is the sktime class only
         "maintainers": ["maintainer1", "maintainer2"],
         # valid values: str or list of str, should be GitHub handles
         # remove tag if maintained by sktime core team
diff --git a/extension_templates/transformer_supersimple.py b/extension_templates/transformer_supersimple.py
index 8bb10dd5a..9d42432c8 100644
--- a/extension_templates/transformer_supersimple.py
+++ b/extension_templates/transformer_supersimple.py
@@ -79,7 +79,10 @@ class MyTransformer(BaseTransformer):
         "authors": ["author1", "author2"],  # authors, GitHub handles
         "maintainers": ["maintainer1", "maintainer2"],  # maintainers, GitHub handles
         # author = significant contribution to code at some point
-        # maintainer = algorithm maintainer role, "owner"
+        #     if interfacing a 3rd party estimator, ensure to give credit to the
+        #     authors of the interfaced estimator
+        # maintainer = algorithm maintainer role, "owner" of the sktime class
+        #     for 3rd party interfaces, the scope is the sktime class only
         # remove maintainer tag if maintained by sktime core team
         #
         # do not change these:
diff --git a/pyproject.toml b/pyproject.toml
index ac520cc7c..306802c43 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -80,7 +80,7 @@ all_extras = [
   "arch>=5.6,<6.4.0",
   "cloudpickle",
   "dash!=2.9.0",
-  "dask<2024.2.2",
+  "dask<2024.4.2; extra == 'dataframe'",
   "dtw-python",
   'esig==0.9.7; python_version < "3.10"',
   'filterpy>=1.4.5; python_version < "3.11"',
@@ -121,7 +121,7 @@ all_extras_pandas2 = [
   "arch>=5.6,<6.4.0",
   "cloudpickle",
   "dash!=2.9.0",
-  "dask<2024.2.2",
+  "dask<2024.4.2; extra == 'dataframe'",
   "dtw-python",
   'esig==0.9.7; python_version < "3.10"',
   'filterpy>=1.4.5; python_version < "3.11"',
diff --git a/sktime/transformations/series/impute.py b/sktime/transformations/series/impute.py
index 28cc37723..8089b8092 100644
--- a/sktime/transformations/series/impute.py
+++ b/sktime/transformations/series/impute.py
@@ -23,7 +23,9 @@ class Imputer(BaseTransformer):
     Parameters
     ----------
     method : str, default="drift"
-        Method to fill the missing values.
+        Method to fill the missing values. Not all methods can extrapolate, so after
+        ``method`` is applied the remaining missing values are filled with ``ffill``
+        then ``bfill``.
 
         * "drift" : drift/trend values by sktime.PolynomialTrendForecaster(degree=1)
           first, X in transform() is filled with ffill then bfill
@@ -231,22 +233,26 @@ class Imputer(BaseTransformer):
         elif self.method == "constant":
             return X.fillna(value=self.value)
         elif isinstance(index, pd.MultiIndex):
-            X_grouped = X.groupby(level=list(range(index.nlevels - 1)))
+            X_group_levels = list(range(index.nlevels - 1))
 
             if self.method in ["backfill", "bfill"]:
-                X = X_grouped.bfill()
-                # fill trailing NAs of panel instances with reverse method
-                return X.ffill()
+                X = X.groupby(level=X_group_levels).bfill()
             elif self.method in ["pad", "ffill"]:
-                X = X_grouped.ffill()
-                # fill leading NAs of panel instances with reverse method
-                return X.bfill()
+                X = X.groupby(level=X_group_levels).ffill()
             elif self.method == "mean":
-                return X_grouped.fillna(value=self._mean)
+                X = X.groupby(level=X_group_levels).fillna(value=self._mean)
             elif self.method == "median":
-                return X_grouped.fillna(value=self._median)
+                X = X.groupby(level=X_group_levels).fillna(value=self._median)
             else:
                 raise AssertionError("Code should not be reached")
+
+            # fill first/last elements of series,
+            # as some methods can't impute those
+            X = X.groupby(level=X_group_levels).ffill()
+            X = X.groupby(level=X_group_levels).bfill()
+
+            return X
+
         else:
             if self.method in ["backfill", "bfill"]:
                 X = X.bfill()


Test patch:
diff --git a/sktime/transformations/series/tests/test_imputer.py b/sktime/transformations/series/tests/test_imputer.py
index 05b958d10..7d7c1ba97 100644
--- a/sktime/transformations/series/tests/test_imputer.py
+++ b/sktime/transformations/series/tests/test_imputer.py
@@ -8,7 +8,9 @@ __all__ = []
 import numpy as np
 import pytest
 
+from sktime.datatypes import get_examples
 from sktime.forecasting.naive import NaiveForecaster
+from sktime.transformations.compose import TransformByLevel
 from sktime.transformations.series.impute import Imputer
 from sktime.utils._testing.forecasting import make_forecasting_problem
 from sktime.utils._testing.hierarchical import _make_hierarchical
@@ -58,6 +60,44 @@ def test_imputer(method, Z, value, forecaster):
     assert not y_hat.isnull().to_numpy().any()
 
 
+@pytest.mark.parametrize(
+    "method",
+    [
+        "linear",
+        "nearest",
+        "mean",
+        "median",
+        "backfill",
+        "pad",
+    ],
+)
+def test_impute_multiindex(method):
+    """Test for data leakage in case of pd-multiindex data.
+
+    Failure case in bug #6224
+    """
+
+    df = get_examples(mtype="pd-multiindex")[0].copy()
+    df.iloc[:3, :] = np.nan  # instance 0 entirely missing
+    df.iloc[3:4, :] = np.nan  # instance 1 first timepoint missing
+    df.iloc[8:, :] = np.nan  # instance 2 last timepoint missing
+
+    imp = Imputer(method=method)
+    df_imp = imp.fit_transform(df)
+
+    # instance 0 entirely missing, so it should remain missing
+    assert np.array_equal(df.iloc[:3, :], df_imp.iloc[:3, :], equal_nan=True)
+
+    # instance 1 and 2 should not have any missing values
+    assert not df_imp.iloc[3:, :].isna().any().any()
+
+    # test consistency between applying the imputer to every instance separately,
+    # vs applying them to the panel
+    imp_tbl = TransformByLevel(Imputer(method=method))
+    df_imp_tbl = imp_tbl.fit_transform(df)
+    assert np.array_equal(df_imp, df_imp_tbl, equal_nan=True)
+
+
 def test_imputer_forecaster_y():
     """Test that forecaster imputer works with y.