Repository: sktime/sktime
Pull request #6140 (2024-03-16 21:59:08)

[BUG] fix network construction in `InceptionTimeRegressor`
Fixes an unreported network construction bug in `InceptionTimeRegressor`.

A `self.n_classes_` attribute was used internally, which neither the estimator nor the network had.

Previously undetedted since the estimator was excepted from testing, see https://github.com/sktime/sktime/pull/6138


Patch:
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 81384dc23..e9ae4e968 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -2607,6 +2607,17 @@
         "code"
       ]
     },
+    {
+      "login": "ShreeshaM07",
+      "name": "Shreesha M",
+      "avatar_url": "https://avatars.githubusercontent.com/u/120820143?s=400&v=4",
+      "profile": "https://github.com/ShreeshaM07",
+      "contributions": [
+        "bug",
+        "code",
+        "test"
+      ]
+    },
     {
       "login": "geetu040",
       "name": "Armaghan",
@@ -2645,6 +2656,26 @@
         "maintenance"
       ]
     },
+    {
+      "login": "ianspektor",
+      "name": "Ian Spektor",
+      "avatar_url": "https://avatars.githubusercontent.com/u/49082859?v=4",
+      "profile": "https://github.com/ianspektor",
+      "contributions": [
+        "code",
+        "doc"
+      ]
+    },
+    {
+      "login": "javiber",
+      "name": "Javier Berneche",
+      "avatar_url": "https://avatars.githubusercontent.com/u/3588715?v=4",
+      "profile": "https://github.com/javiber",
+      "contributions": [
+        "code",
+        "doc"
+      ]
+    },
     {
       "login": "fnhirwa",
       "name": "Felix Hirwa Nshuti",
@@ -2654,6 +2685,15 @@
         "code",
         "maintenance"
       ]
+    },
+    {
+      "login": "vandit98",
+      "name": "Vandit Tyagi",
+      "avatar_url": "https://avatars.githubusercontent.com/u/91458535?v=4",
+      "profile": "https://github.com/vandit98",
+      "contributions": [
+        "doc"
+      ]
     }
   ]
 }
diff --git a/.github/workflows/update_contributors.yml b/.github/workflows/update_contributors.yml
index 9f9a91c2d..be2743678 100644
--- a/.github/workflows/update_contributors.yml
+++ b/.github/workflows/update_contributors.yml
@@ -1,7 +1,9 @@
 name: Update Contributors
 
 on:
-  push:
+  pull_request:
+    branches:
+      - main
     paths:
       - '.all-contributorsrc'
 
diff --git a/docs/source/api_reference/transformations.rst b/docs/source/api_reference/transformations.rst
index 569762e95..1a2388973 100644
--- a/docs/source/api_reference/transformations.rst
+++ b/docs/source/api_reference/transformations.rst
@@ -148,6 +148,7 @@ Shapelets, wavelets, and convolution
 
     ShapeletTransform
     RandomShapeletTransform
+    ShapeletTransformPyts
 
 .. currentmodule:: sktime.transformations.panel.rocket
 
@@ -631,6 +632,20 @@ These transformers subset `X` by time points (`pandas` index or index level) or
     ColumnSelect
     IndexSubset
 
+Adapters to other frameworks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Generic framework adapters that expose other frameworks in the ``sktime`` interface.
+
+.. currentmodule:: sktime.transformations.series.temporian
+
+.. autosummary::
+    :toctree: auto_generated/
+    :template: class.rst
+
+    TemporianTransformer
+
+
 Panel transformers
 ------------------
 
diff --git a/docs/source/developer_guide.rst b/docs/source/developer_guide.rst
index 2b3cbaea7..90ef47026 100644
--- a/docs/source/developer_guide.rst
+++ b/docs/source/developer_guide.rst
@@ -14,7 +14,7 @@ Welcome to sktime's developer guide!
 
 New developers should:
 
-* sign up to the developer Discord (see link in README) and say hello in the ``#contributors`` channel
+* sign up to the developer Discord (see link in README) and say hello in the ``#intro`` channel
 * install a development version of ``sktime``, see :ref:`installation`
 * set up CI tests locally and ensure they know how to check them remotely, see :ref:`continuous_integration`
 * get familiar with the git workflow (:ref:`git_workflow`) and coding standards (:ref:`coding_standards`)
diff --git a/docs/source/get_involved/contributing.rst b/docs/source/get_involved/contributing.rst
index 705e81dfe..e7eb30c94 100644
--- a/docs/source/get_involved/contributing.rst
+++ b/docs/source/get_involved/contributing.rst
@@ -24,7 +24,7 @@ and people who are looking to learn and develop their skills.
 
 Recommended steps for first time contributors, or to get started with regular contributions:
 
-1. Say hello (in the lobby on `Discord`_)!
+1. Say hello (in the ``#intro`` channel on `Discord`_)!
 2. Get set up for development, see `instructions in the developer guide <https://www.sktime.net/en/stable/developer_guide.html>`_.
 3. Pick a good first issue to work on, see a collection `in this summary issue <https://github.com/sktime/sktime/issues/1147>`_ , or from `this list <https://github.com/sktime/sktime/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22>`_
    suggestion: pick something small with simple content to learn the "process"
diff --git a/pyproject.toml b/pyproject.toml
index d8897bac4..7fdcce890 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -108,6 +108,7 @@ all_extras = [
   "statsmodels>=0.12.1",
   'stumpy>=1.5.1; python_version < "3.11"',
   'tbats>=1.1; python_version < "3.12"',
+  'temporian>=0.7.0; python_version < "3.12" and sys_platform != "win32"',
   'tensorflow<2.17,>=2; python_version < "3.12"',
   'tsfresh>=0.17; python_version < "3.12"',
   'tslearn<0.7.0,!=0.6.0,>=0.5.2; python_version < "3.11"',
@@ -145,6 +146,7 @@ all_extras_pandas2 = [
   "statsmodels>=0.12.1",
   'stumpy>=1.5.1; python_version < "3.11"',
   'tbats>=1.1; python_version < "3.12"',
+  'temporian>=0.7.0; python_version < "3.12" and sys_platform != "win32"',
   'tensorflow<2.17,>=2; python_version < "3.12"',
   'tsfresh>=0.17; python_version < "3.12"',
   'tslearn<0.7.0,!=0.6.0,>=0.5.2; python_version < "3.11"',
@@ -161,7 +163,7 @@ all_extras_pandas2 = [
 # users can install via "pip install sktime[forecasting,transformations]" etc
 #
 alignment = [
-  "dtw-python<1.4,>=1.3",
+  "dtw-python>=1.3,<1.5",
   'numba<0.60,>=0.53',
 ]
 annotation = [
@@ -203,13 +205,14 @@ regression = [
 transformations = [
   'esig<0.10,>=0.9.7; python_version < "3.11"',
   "filterpy<1.5,>=1.4.5",
-  "holidays>=0.29,<0.45",
+  "holidays>=0.29,<0.46",
   "mne>=1.5,<1.7",
   'numba<0.60,>=0.53',
   "pycatch22>=0.4,<0.4.4",
   "pykalman-bardo<0.10,>=0.9.7",
   "statsmodels<0.15,>=0.12.1",
   'stumpy<1.13,>=1.5.1; python_version < "3.12"',
+  'temporian>=0.7.0; python_version < "3.12" and sys_platform != "win32"',
   'tsfresh<0.21,>=0.17; python_version < "3.12"',
 ]
 
diff --git a/sktime/annotation/base/_base.py b/sktime/annotation/base/_base.py
index 4acc304cc..4d14b50f6 100644
--- a/sktime/annotation/base/_base.py
+++ b/sktime/annotation/base/_base.py
@@ -36,11 +36,13 @@ class BaseSeriesAnnotator(BaseEstimator):
         Annotation output format:
         * If "sparse", a sub-series of labels for only the outliers in X is returned,
         * If "dense", a series of labels for all values in X is returned.
-    labels : str {"indicator", "score"}, optional (default="indicator")
+    labels : str {"indicator", "score", "int_label"}, optional (default="indicator")
         Annotation output labels:
         * If "indicator", returned values are boolean, indicating whether a value is an
         outlier,
         * If "score", returned values are floats, giving the outlier score.
+        * If "int_label", returned values are integers indicating which segment the
+        value belongs to.
 
     Notes
     -----
diff --git a/sktime/classification/deep_learning/base.py b/sktime/classification/deep_learning/base.py
index 22c2bc455..1c049d686 100644
--- a/sktime/classification/deep_learning/base.py
+++ b/sktime/classification/deep_learning/base.py
@@ -41,13 +41,6 @@ class BaseDeepClassifier(BaseClassifier, ABC):
         "python_dependencies": "tensorflow",
     }
 
-    def __init__(self, batch_size=40, random_state=None):
-        super().__init__()
-
-        self.batch_size = batch_size
-        self.random_state = random_state
-        self.model_ = None
-
     @abstractmethod
     def build_model(self, input_shape, n_classes, **kwargs):
         """Construct a compiled, un-trained, keras model that is ready for training.
diff --git a/sktime/classification/deep_learning/cnn.py b/sktime/classification/deep_learning/cnn.py
index cd693a922..2c4b4349c 100644
--- a/sktime/classification/deep_learning/cnn.py
+++ b/sktime/classification/deep_learning/cnn.py
@@ -91,7 +91,8 @@ class CNNClassifier(BaseDeepClassifier):
         optimizer=None,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__()
+
+        self.batch_size = batch_size
         self.n_conv_layers = n_conv_layers
         self.avg_pool_size = avg_pool_size
         self.kernel_size = kernel_size
@@ -106,6 +107,9 @@ class CNNClassifier(BaseDeepClassifier):
         self.use_bias = use_bias
         self.optimizer = optimizer
         self.history = None
+
+        super().__init__()
+
         self._network = CNNNetwork(
             kernel_size=self.kernel_size,
             avg_pool_size=self.avg_pool_size,
diff --git a/sktime/classification/deep_learning/cntc.py b/sktime/classification/deep_learning/cntc.py
index 900e98613..18ce61e18 100644
--- a/sktime/classification/deep_learning/cntc.py
+++ b/sktime/classification/deep_learning/cntc.py
@@ -107,9 +107,10 @@ class CNTCClassifier(BaseDeepClassifier):
         self.loss = loss
         self.metrics = metrics
         self.random_state = random_state
-        self._network = CNTCNetwork()
 
-        super().__init__(batch_size=batch_size, random_state=random_state)
+        super().__init__()
+
+        self._network = CNTCNetwork()
 
     def build_model(self, input_shape, n_classes, **kwargs):
         """Construct a compiled, un-trained, keras model that is ready for training.
diff --git a/sktime/classification/deep_learning/fcn.py b/sktime/classification/deep_learning/fcn.py
index fff7bfbb2..d27c8d6ec 100644
--- a/sktime/classification/deep_learning/fcn.py
+++ b/sktime/classification/deep_learning/fcn.py
@@ -82,7 +82,7 @@ class FCNClassifier(BaseDeepClassifier):
         optimizer=None,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__()
+
         self.callbacks = callbacks
         self.n_epochs = n_epochs
         self.batch_size = batch_size
@@ -94,9 +94,10 @@ class FCNClassifier(BaseDeepClassifier):
         self.use_bias = use_bias
         self.optimizer = optimizer
         self.history = None
-        self._network = FCNNetwork(
-            random_state=self.random_state,
-        )
+
+        super().__init__()
+
+        self._network = FCNNetwork(random_state=self.random_state)
 
     def build_model(self, input_shape, n_classes, **kwargs):
         """Construct a compiled, un-trained, keras model that is ready for training.
diff --git a/sktime/classification/deep_learning/inceptiontime.py b/sktime/classification/deep_learning/inceptiontime.py
index 5e4e8c900..03a94fcc0 100644
--- a/sktime/classification/deep_learning/inceptiontime.py
+++ b/sktime/classification/deep_learning/inceptiontime.py
@@ -68,9 +68,6 @@ class InceptionTimeClassifier(BaseDeepClassifier):
         metrics=None,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__()
-
-        self.verbose = verbose
 
         # predefined
         self.batch_size = batch_size
@@ -86,7 +83,8 @@ class InceptionTimeClassifier(BaseDeepClassifier):
         self.use_bottleneck = use_bottleneck
         self.use_residual = use_residual
         self.verbose = verbose
-        self._is_fitted = False
+
+        super().__init__()
 
         network_params = {
             "n_filters": n_filters,
diff --git a/sktime/classification/deep_learning/lstmfcn.py b/sktime/classification/deep_learning/lstmfcn.py
index c016408bd..3f6bcad88 100644
--- a/sktime/classification/deep_learning/lstmfcn.py
+++ b/sktime/classification/deep_learning/lstmfcn.py
@@ -76,13 +76,6 @@ class LSTMFCNClassifier(BaseDeepClassifier):
         random_state=None,
         verbose=0,
     ):
-        super().__init__()
-
-        self.classes_ = None
-        self.input_shape = None
-        self.model_ = None
-        self.history = None
-
         # predefined
         self.n_epochs = n_epochs
         self.batch_size = batch_size
@@ -96,6 +89,8 @@ class LSTMFCNClassifier(BaseDeepClassifier):
         self.random_state = random_state
         self.verbose = verbose
 
+        super().__init__()
+
         self._network = LSTMFCNNetwork(
             kernel_sizes=self.kernel_sizes,
             filter_sizes=self.filter_sizes,
@@ -104,7 +99,6 @@ class LSTMFCNClassifier(BaseDeepClassifier):
             dropout=self.dropout,
             attention=self.attention,
         )
-        self._is_fitted = False
 
     def build_model(self, input_shape, n_classes, **kwargs):
         """
diff --git a/sktime/classification/deep_learning/macnn.py b/sktime/classification/deep_learning/macnn.py
index ab638fb6a..270b7c864 100644
--- a/sktime/classification/deep_learning/macnn.py
+++ b/sktime/classification/deep_learning/macnn.py
@@ -107,7 +107,6 @@ class MACNNClassifier(BaseDeepClassifier):
         verbose=False,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__()
 
         self.n_epochs = n_epochs
         self.batch_size = batch_size
@@ -126,6 +125,9 @@ class MACNNClassifier(BaseDeepClassifier):
         self.callbacks = callbacks
         self.random_state = random_state
         self.verbose = verbose
+
+        super().__init__()
+
         self.history = None
         self._network = MACNNNetwork(
             padding=self.padding,
diff --git a/sktime/classification/deep_learning/mcdcnn.py b/sktime/classification/deep_learning/mcdcnn.py
index 79ff7892a..4e4d2998b 100644
--- a/sktime/classification/deep_learning/mcdcnn.py
+++ b/sktime/classification/deep_learning/mcdcnn.py
@@ -107,7 +107,6 @@ class MCDCNNClassifier(BaseDeepClassifier):
         random_state=0,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__()
 
         self.n_epochs = n_epochs
         self.batch_size = batch_size
@@ -125,6 +124,9 @@ class MCDCNNClassifier(BaseDeepClassifier):
         self.optimizer = optimizer
         self.verbose = verbose
         self.random_state = random_state
+
+        super().__init__()
+
         self.history = None
         self._network = MCDCNNNetwork(
             kernel_size=self.kernel_size,
diff --git a/sktime/classification/deep_learning/mlp.py b/sktime/classification/deep_learning/mlp.py
index 71f36a2bd..0d3659c2a 100644
--- a/sktime/classification/deep_learning/mlp.py
+++ b/sktime/classification/deep_learning/mlp.py
@@ -82,7 +82,7 @@ class MLPClassifier(BaseDeepClassifier):
         optimizer=None,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__()
+
         self.callbacks = callbacks
         self.n_epochs = n_epochs
         self.batch_size = batch_size
@@ -93,6 +93,9 @@ class MLPClassifier(BaseDeepClassifier):
         self.activation = activation
         self.use_bias = use_bias
         self.optimizer = optimizer
+
+        super().__init__()
+
         self.history = None
         self._network = MLPNetwork(
             random_state=self.random_state,
diff --git a/sktime/classification/deep_learning/resnet.py b/sktime/classification/deep_learning/resnet.py
index f85fcf7f0..d15bd4b3a 100644
--- a/sktime/classification/deep_learning/resnet.py
+++ b/sktime/classification/deep_learning/resnet.py
@@ -55,8 +55,8 @@ class ResNetClassifier(BaseDeepClassifier):
     >>> from sktime.classification.deep_learning.resnet import ResNetClassifier
     >>> from sktime.datasets import load_unit_test
     >>> X_train, y_train = load_unit_test(split="train")
-    >>> clf = ResNetClassifier(n_epochs=20, bacth_size=4) # doctest: +SKIP
-    >>> clf.fit(X_train, Y_train) # doctest: +SKIP
+    >>> clf = ResNetClassifier(n_epochs=20) # doctest: +SKIP
+    >>> clf.fit(X_train, y_train) # doctest: +SKIP
     ResNetClassifier(...)
     """
 
@@ -83,7 +83,7 @@ class ResNetClassifier(BaseDeepClassifier):
         optimizer=None,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__()
+
         self.n_epochs = n_epochs
         self.callbacks = callbacks
         self.verbose = verbose
@@ -94,6 +94,9 @@ class ResNetClassifier(BaseDeepClassifier):
         self.activation = activation
         self.use_bias = use_bias
         self.optimizer = optimizer
+
+        super().__init__()
+
         self.history = None
         self._network = ResNetNetwork(random_state=random_state)
 
diff --git a/sktime/classification/deep_learning/rnn.py b/sktime/classification/deep_learning/rnn.py
index ab651853f..3f89323a6 100644
--- a/sktime/classification/deep_learning/rnn.py
+++ b/sktime/classification/deep_learning/rnn.py
@@ -47,6 +47,15 @@ class SimpleRNNClassifier(BaseDeepClassifier):
     ----------
     ..[1] benchmark forecaster in M4 forecasting competition:
     https://github.com/Mcompetitions/M4-methods
+
+    Examples
+    --------
+    >>> from sktime.classification.deep_learning.rnn import SimpleRNNClassifier
+    >>> from sktime.datasets import load_unit_test
+    >>> X_train, y_train = load_unit_test(split="train")
+    >>> clf = SimpleRNNClassifier(n_epochs=20,batch_size=20) # doctest: +SKIP
+    >>> clf.fit(X_train, y_train) # doctest: +SKIP
+    ResNetClassifier(...)
     """
 
     _tags = {
@@ -73,9 +82,8 @@ class SimpleRNNClassifier(BaseDeepClassifier):
     ):
         _check_dl_dependencies(severity="error")
 
-        super().__init__()
-
         self.batch_size = batch_size
+        self.n_epochs = n_epochs
         self.verbose = verbose
         self.units = units
         self.callbacks = callbacks
@@ -86,9 +94,11 @@ class SimpleRNNClassifier(BaseDeepClassifier):
         self.activation = activation
         self.use_bias = use_bias
         self.optimizer = optimizer
+
+        super().__init__()
+
         self.history = None
         self._network = RNNNetwork(random_state=random_state, units=units)
-        self.n_epochs = n_epochs
 
     def build_model(self, input_shape, n_classes, **kwargs):
         """Construct a compiled, un-trained, keras model that is ready for training.
@@ -121,7 +131,7 @@ class SimpleRNNClassifier(BaseDeepClassifier):
         )(output_layer)
 
         self.optimizer_ = (
-            keras.optimizers.RMSprop(lr=0.001)
+            keras.optimizers.RMSprop(learning_rate=0.001)
             if self.optimizer is None
             else self.optimizer
         )
diff --git a/sktime/classification/deep_learning/tapnet.py b/sktime/classification/deep_learning/tapnet.py
index ee7c53592..4ff4b4ee6 100644
--- a/sktime/classification/deep_learning/tapnet.py
+++ b/sktime/classification/deep_learning/tapnet.py
@@ -119,7 +119,6 @@ class TapNetClassifier(BaseDeepClassifier):
         verbose=False,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__()
 
         self.batch_size = batch_size
         self.random_state = random_state
@@ -148,6 +147,8 @@ class TapNetClassifier(BaseDeepClassifier):
         self.use_rp = use_rp
         self.rp_params = rp_params
 
+        super().__init__()
+
         self._network = TapNetNetwork(
             dropout=self.dropout,
             filter_sizes=self.filter_sizes,
diff --git a/sktime/datatypes/_registry.py b/sktime/datatypes/_registry.py
index 7d762c1ba..194972a66 100644
--- a/sktime/datatypes/_registry.py
+++ b/sktime/datatypes/_registry.py
@@ -127,7 +127,7 @@ def mtype_to_scitype(mtype: str, return_unique=False, coerce_to_list=False):
         if None, returns None
     return_unique : bool, default=False
         if True, makes return unique
-    coerce_to_list : bool, default=Fakse
+    coerce_to_list : bool, default=False
         if True, coerces rerturn to list, even if one-element
 
     Raises
diff --git a/sktime/forecasting/base/_base.py b/sktime/forecasting/base/_base.py
index 9ee373acf..f8d930e50 100644
--- a/sktime/forecasting/base/_base.py
+++ b/sktime/forecasting/base/_base.py
@@ -2601,7 +2601,9 @@ def _format_moving_cutoff_predictions(y_preds, cutoffs):
 
     if not y_pred.index.is_monotonic_increasing:
         y_pred = y_pred.sort_index()
-    if hasattr(y_pred, "columns") and not y_pred.columns.is_monotonic_increasing:
-        y_pred = y_pred.sort_index(axis=1)
+
+    if hasattr(y_preds[0], "columns") and not isinstance(y_pred.columns, pd.MultiIndex):
+        col_ordered = y_preds[0].columns
+        y_pred = y_pred.loc[:, col_ordered]
 
     return y_pred
diff --git a/sktime/forecasting/base/_fh.py b/sktime/forecasting/base/_fh.py
index 7141302ea..e10b2761b 100644
--- a/sktime/forecasting/base/_fh.py
+++ b/sktime/forecasting/base/_fh.py
@@ -381,6 +381,9 @@ class ForecastingHorizon:
         if hasattr(self, "_freq") and hasattr(self._freq, "freqstr"):
             # _freq is a pandas offset, frequency string is obtained via freqstr
             return self._freq.freqstr
+        elif hasattr(self, "_freq") and isinstance(self._freq, str):
+            # _freq is a string, frequency string is obtained directly
+            return self._freq
         else:
             return None
 
@@ -415,8 +418,12 @@ class ForecastingHorizon:
                     f"Current: {freq_from_self}, from update: {freq_from_obj}."
                 )
         elif freq_from_obj is not None:  # only freq_from_obj is not None
+            if freq_from_obj == "ME":
+                freq_from_obj = "M"
             self._freq = freq_from_obj
         else:
+            if freq_from_obj == "ME":
+                freq_from_obj = "M"
             # leave self._freq as freq_from_self, or set to None if does not exist yet
             self._freq = freq_from_self
 
diff --git a/sktime/forecasting/compose/_fallback.py b/sktime/forecasting/compose/_fallback.py
index d2382066c..7b9f867c1 100644
--- a/sktime/forecasting/compose/_fallback.py
+++ b/sktime/forecasting/compose/_fallback.py
@@ -8,7 +8,7 @@ If the active forecaster fails during prediction, it proceeds to the next. This
 a robust forecasting mechanism by providing fallback options.
 """
 
-__author__ = ["ninedigits"]
+__author__ = ["ninedigits", "RikStarmans"]
 __all__ = ["FallbackForecaster"]
 
 from sktime.base import _HeterogenousMetaEstimator
@@ -107,7 +107,7 @@ class FallbackForecaster(_HeterogenousMetaEstimator, _DelegatedForecaster):
     """
 
     _tags = {
-        "authors": ["ninedigits"],
+        "authors": ["ninedigits", "RikStarmans"],
         "maintainers": ["ninedigits"],
         "handles-missing-data": True,
         "scitype:y": "both",
diff --git a/sktime/networks/rnn.py b/sktime/networks/rnn.py
index 836bef650..f63ff822d 100644
--- a/sktime/networks/rnn.py
+++ b/sktime/networks/rnn.py
@@ -74,3 +74,29 @@ class RNNNetwork(BaseDeepNetwork):
         )(input_layer)
 
         return input_layer, output_layer
+
+    @classmethod
+    def get_test_params(cls, parameter_set="default"):
+        """Return testing parameter settings for the estimator.
+
+        Parameters
+        ----------
+        parameter_set : str, default="default"
+            Name of the set of test parameters to return, for use in tests. If no
+            special parameters are defined for a value, will return ``"default"`` set.
+            Reserved values for classifiers:
+                "results_comparison" - used for identity testing in some classifiers
+                    should contain parameter settings comparable to "TSC bakeoff"
+
+        Returns
+        -------
+        params : dict or list of dict, default = {}
+            Parameters to create testing instances of the class
+            Each dict are parameters to construct an "interesting" test instance, i.e.,
+            ``MyClass(**params)`` or ``MyClass(**params[i])`` creates a valid test
+            instance.
+            ``create_test_instance`` uses the first (or only) dictionary in ``params``
+        """
+        params1 = {}
+        params2 = {"units": 5}
+        return [params1, params2]
diff --git a/sktime/regression/deep_learning/base.py b/sktime/regression/deep_learning/base.py
index 17deefca6..87b9680ae 100644
--- a/sktime/regression/deep_learning/base.py
+++ b/sktime/regression/deep_learning/base.py
@@ -39,12 +39,6 @@ class BaseDeepRegressor(BaseRegressor, ABC):
         "python_dependencies": "tensorflow",
     }
 
-    def __init__(self, batch_size=40):
-        super().__init__()
-
-        self.batch_size = batch_size
-        self.model_ = None
-
     @abstractmethod
     def build_model(self, input_shape, **kwargs):
         """Construct a compiled, un-trained, keras model that is ready for training.
diff --git a/sktime/regression/deep_learning/cnn.py b/sktime/regression/deep_learning/cnn.py
index 505a75086..3ec565359 100644
--- a/sktime/regression/deep_learning/cnn.py
+++ b/sktime/regression/deep_learning/cnn.py
@@ -92,9 +92,7 @@ class CNNRegressor(BaseDeepRegressor):
         optimizer=None,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__(
-            batch_size=batch_size,
-        )
+        super().__init__()
         self.n_conv_layers = n_conv_layers
         self.avg_pool_size = avg_pool_size
         self.kernel_size = kernel_size
diff --git a/sktime/regression/deep_learning/cntc.py b/sktime/regression/deep_learning/cntc.py
index 44ca435df..2a88293f6 100644
--- a/sktime/regression/deep_learning/cntc.py
+++ b/sktime/regression/deep_learning/cntc.py
@@ -97,9 +97,10 @@ class CNTCRegressor(BaseDeepRegressor):
         self.loss = loss
         self.metrics = metrics
         self.random_state = random_state
-        self._network = CNTCNetwork()
 
-        super().__init__(batch_size=batch_size, random_state=random_state)
+        super().__init__()
+
+        self._network = CNTCNetwork()
 
     def build_model(self, input_shape, **kwargs):
         """Construct a compiled, un-trained, keras model that is ready for training.
diff --git a/sktime/regression/deep_learning/fcn.py b/sktime/regression/deep_learning/fcn.py
index e75ac6f50..a6df9e45b 100644
--- a/sktime/regression/deep_learning/fcn.py
+++ b/sktime/regression/deep_learning/fcn.py
@@ -71,7 +71,7 @@ class FCNRegressor(BaseDeepRegressor):
         optimizer=None,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__()
+
         self.n_epochs = n_epochs
         self.batch_size = batch_size
         self.callbacks = callbacks
@@ -83,6 +83,9 @@ class FCNRegressor(BaseDeepRegressor):
         self.use_bias = use_bias
         self.optimizer = optimizer
         self.history = None
+
+        super().__init__()
+
         self._network = FCNNetwork(
             random_state=self.random_state,
         )
diff --git a/sktime/regression/deep_learning/inceptiontime.py b/sktime/regression/deep_learning/inceptiontime.py
index 9e5e7d055..bef5e9ebd 100644
--- a/sktime/regression/deep_learning/inceptiontime.py
+++ b/sktime/regression/deep_learning/inceptiontime.py
@@ -68,7 +68,6 @@ class InceptionTimeRegressor(BaseDeepRegressor):
         metrics=None,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__()
 
         self.verbose = verbose
 
@@ -86,7 +85,8 @@ class InceptionTimeRegressor(BaseDeepRegressor):
         self.use_bottleneck = use_bottleneck
         self.use_residual = use_residual
         self.verbose = verbose
-        self._is_fitted = False
+
+        super().__init__()
 
         network_params = {
             "n_filters": n_filters,
@@ -153,7 +153,7 @@ class InceptionTimeRegressor(BaseDeepRegressor):
 
         check_random_state(self.random_state)
         self.input_shape = X.shape[1:]
-        self.model_ = self.build_model(self.input_shape, self.n_classes_)
+        self.model_ = self.build_model(self.input_shape)
         if self.verbose:
             self.model_.summary()
 
diff --git a/sktime/regression/deep_learning/lstmfcn.py b/sktime/regression/deep_learning/lstmfcn.py
index f1dfe2b4a..b10ca16bd 100644
--- a/sktime/regression/deep_learning/lstmfcn.py
+++ b/sktime/regression/deep_learning/lstmfcn.py
@@ -76,12 +76,6 @@ class LSTMFCNRegressor(BaseDeepRegressor):
         random_state=None,
         verbose=0,
     ):
-        super().__init__()
-
-        self.input_shape = None
-        self.model_ = None
-        self.history = None
-
         # predefined
         self.n_epochs = n_epochs
         self.batch_size = batch_size
@@ -95,6 +89,12 @@ class LSTMFCNRegressor(BaseDeepRegressor):
         self.random_state = random_state
         self.verbose = verbose
 
+        super().__init__()
+
+        self.input_shape = None
+        self.model_ = None
+        self.history = None
+
         self._network = LSTMFCNNetwork(
             kernel_sizes=self.kernel_sizes,
             filter_sizes=self.filter_sizes,
@@ -103,7 +103,6 @@ class LSTMFCNRegressor(BaseDeepRegressor):
             dropout=self.dropout,
             attention=self.attention,
         )
-        self._is_fitted = False
 
     def build_model(self, input_shape, **kwargs):
         """
diff --git a/sktime/regression/deep_learning/macnn.py b/sktime/regression/deep_learning/macnn.py
index 09fb22887..b546b1301 100644
--- a/sktime/regression/deep_learning/macnn.py
+++ b/sktime/regression/deep_learning/macnn.py
@@ -94,7 +94,6 @@ class MACNNRegressor(BaseDeepRegressor):
         verbose=False,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__()
 
         self.n_epochs = n_epochs
         self.batch_size = batch_size
@@ -113,6 +112,9 @@ class MACNNRegressor(BaseDeepRegressor):
         self.callbacks = callbacks
         self.random_state = random_state
         self.verbose = verbose
+
+        super().__init__()
+
         self.history = None
         self._network = MACNNNetwork(
             padding=self.padding,
diff --git a/sktime/regression/deep_learning/mcdcnn.py b/sktime/regression/deep_learning/mcdcnn.py
index 55ef4e799..c6c064dd8 100644
--- a/sktime/regression/deep_learning/mcdcnn.py
+++ b/sktime/regression/deep_learning/mcdcnn.py
@@ -105,7 +105,6 @@ class MCDCNNRegressor(BaseDeepRegressor):
         random_state=0,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__()
 
         self.n_epochs = n_epochs
         self.batch_size = batch_size
@@ -123,6 +122,9 @@ class MCDCNNRegressor(BaseDeepRegressor):
         self.optimizer = optimizer
         self.verbose = verbose
         self.random_state = random_state
+
+        super().__init__()
+
         self.history = None
         self._network = MCDCNNNetwork(
             kernel_size=self.kernel_size,
diff --git a/sktime/regression/deep_learning/mlp.py b/sktime/regression/deep_learning/mlp.py
index 5c0f26d75..5dfa8ff04 100644
--- a/sktime/regression/deep_learning/mlp.py
+++ b/sktime/regression/deep_learning/mlp.py
@@ -48,6 +48,17 @@ class MLPRegressor(BaseDeepRegressor):
     .. [1] Wang et. al, Time series classification from
     scratch with deep neural networks: A strong baseline,
     International joint conference on neural networks (IJCNN), 2017.
+
+    Examples
+    --------
+    >>> from sktime.datasets import load_unit_test
+    >>> from sktime.regression.deep_learning.mlp import MLPRegressor
+    >>> X_train, y_train = load_unit_test(return_X_y=True, split="train")
+    >>> X_test, y_test = load_unit_test(return_X_y=True, split="test")
+    >>> regressor = MLPRegressor() # doctest: +SKIP
+    >>> regressor.fit(X_train, y_train) # doctest: +SKIP
+    MLPRegressor(...)
+    >>> y_pred = regressor.predict(X_test) # doctest: +SKIP
     """
 
     _tags = {
@@ -72,7 +83,7 @@ class MLPRegressor(BaseDeepRegressor):
         optimizer=None,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__()
+
         self.callbacks = callbacks
         self.n_epochs = n_epochs
         self.batch_size = batch_size
@@ -83,6 +94,9 @@ class MLPRegressor(BaseDeepRegressor):
         self.activation = activation
         self.use_bias = use_bias
         self.optimizer = optimizer
+
+        super().__init__()
+
         self.history = None
         self._network = MLPNetwork(
             random_state=self.random_state,
diff --git a/sktime/regression/deep_learning/resnet.py b/sktime/regression/deep_learning/resnet.py
index 4a678ae44..c41ccfd2d 100644
--- a/sktime/regression/deep_learning/resnet.py
+++ b/sktime/regression/deep_learning/resnet.py
@@ -82,7 +82,6 @@ class ResNetRegressor(BaseDeepRegressor):
         optimizer=None,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__()
 
         self.n_epochs = n_epochs
         self.callbacks = callbacks
@@ -94,6 +93,9 @@ class ResNetRegressor(BaseDeepRegressor):
         self.activation = activation
         self.use_bias = use_bias
         self.optimizer = optimizer
+
+        super().__init__()
+
         self.history = None
         self._network = ResNetNetwork(random_state=random_state)
 
diff --git a/sktime/regression/deep_learning/rnn.py b/sktime/regression/deep_learning/rnn.py
index 1ea5ed4bd..a3d655ce6 100644
--- a/sktime/regression/deep_learning/rnn.py
+++ b/sktime/regression/deep_learning/rnn.py
@@ -47,6 +47,15 @@ class SimpleRNNRegressor(BaseDeepRegressor):
     ----------
     ..[1] benchmark forecaster in M4 forecasting competition:
     https://github.com/Mcompetitions/M4-methods
+
+    Examples
+    --------
+    >>> from sktime.regression.deep_learning.rnn import SimpleRNNRegressor
+    >>> from sktime.datasets import load_unit_test
+    >>> X_train, Y_train = load_unit_test(split="train")
+    >>> clf = SimpleRNNRegressor(n_epochs=20, batch_size=4) # doctest: +SKIP
+    >>> clf.fit(X_train, Y_train) # doctest: +SKIP
+    SimpleRNNRegressor(...)
     """
 
     _tags = {
@@ -74,8 +83,7 @@ class SimpleRNNRegressor(BaseDeepRegressor):
     ):
         _check_dl_dependencies(severity="error")
 
-        super().__init__()
-
+        self.n_epochs = n_epochs
         self.batch_size = batch_size
         self.verbose = verbose
         self.units = units
@@ -87,9 +95,11 @@ class SimpleRNNRegressor(BaseDeepRegressor):
         self.activation = activation
         self.use_bias = use_bias
         self.optimizer = optimizer
+
+        super().__init__()
+
         self.history = None
         self._network = RNNNetwork(random_state=random_state, units=units)
-        self.n_epochs = n_epochs
 
     def build_model(self, input_shape, **kwargs):
         """Construct a compiled, un-trained, keras model that is ready for training.
@@ -117,7 +127,7 @@ class SimpleRNNRegressor(BaseDeepRegressor):
         )(output_layer)
 
         self.optimizer_ = (
-            keras.optimizers.RMSprop(lr=0.001)
+            keras.optimizers.RMSprop(learning_rate=0.001)
             if self.optimizer is None
             else self.optimizer
         )
diff --git a/sktime/regression/deep_learning/tapnet.py b/sktime/regression/deep_learning/tapnet.py
index 785c300bf..eb21135e0 100644
--- a/sktime/regression/deep_learning/tapnet.py
+++ b/sktime/regression/deep_learning/tapnet.py
@@ -107,7 +107,6 @@ class TapNetRegressor(BaseDeepRegressor):
         verbose=False,
     ):
         _check_dl_dependencies(severity="error")
-        super().__init__()
 
         self.batch_size = batch_size
         self.random_state = random_state
@@ -136,6 +135,8 @@ class TapNetRegressor(BaseDeepRegressor):
         self.use_rp = use_rp
         self.rp_params = rp_params
 
+        super().__init__()
+
         self._network = TapNetNetwork(
             dropout=self.dropout,
             filter_sizes=self.filter_sizes,
diff --git a/sktime/transformations/panel/shapelet_transform/__init__.py b/sktime/transformations/panel/shapelet_transform/__init__.py
new file mode 100644
index 000000000..d6e504484
--- /dev/null
+++ b/sktime/transformations/panel/shapelet_transform/__init__.py
@@ -0,0 +1,14 @@
+"""Shapelet Transformers."""
+__all__ = [
+    "ShapeletTransform",
+    "RandomShapeletTransform",
+    "ShapeletTransformPyts",
+]
+
+from sktime.transformations.panel.shapelet_transform._shapelet_transform import (
+    RandomShapeletTransform,
+    ShapeletTransform,
+)
+from sktime.transformations.panel.shapelet_transform._shapelet_transform_pyts import (
+    ShapeletTransformPyts,
+)
diff --git a/sktime/transformations/panel/shapelet_transform.py b/sktime/transformations/panel/shapelet_transform/_shapelet_transform.py
similarity index 100%
rename from sktime/transformations/panel/shapelet_transform.py
rename to sktime/transformations/panel/shapelet_transform/_shapelet_transform.py
diff --git a/sktime/transformations/panel/shapelet_transform/_shapelet_transform_pyts.py b/sktime/transformations/panel/shapelet_transform/_shapelet_transform_pyts.py
new file mode 100644
index 000000000..3f40d621e
--- /dev/null
+++ b/sktime/transformations/panel/shapelet_transform/_shapelet_transform_pyts.py
@@ -0,0 +1,196 @@
+"""Shapelet transformer, from pyts."""
+# copyright: sktime developers, BSD-3-Clause License (see LICENSE file)
+
+__author__ = ["Abhay-Lejith"]
+__all__ = ["ShapeletTransformPyts"]
+
+from sktime.base.adapters._pyts import _PytsAdapter
+from sktime.transformations.base import BaseTransformer
+
+
+class ShapeletTransformPyts(_PytsAdapter, BaseTransformer):
+    """Shapelet Transform, from ``pyts``.
+
+    Direct interface to ``pyts.transformation.ShapeletTransform``.
+
+    The Shapelet Transform algorithm extracts shapelets from a data set of time series
+    and returns the distances between the shapelets and the time series. A shapelet is
+    defined as a subset of a time series, that is a set of values from consecutive time
+    points. The distance between a shapelet and a time series is defined as the minimum
+    of the distances between this shapelet and all the shapelets of same length
+    extracted from this time series. The most discriminative shapelets are selected.
+    Two criteria are made available: mutual information and F-scores.
+
+    Parameters
+    ----------
+    n_shapelets : int or 'auto' (default = 'auto')
+        The number of shapelets to keep. If 'auto', `n_timestamps // 2`
+        shapelets are considered, where `n_timestamps` is the number of
+        time points in the dataset. Note that there might be a smaller
+        number of shapelets if fewer than ``n_shapelets`` shapelets have been
+        extracted during the search.
+
+    criterion : 'mutual_info' or 'anova' (default = 'mutual_info')
+        Criterion to perform the selection of the shapelets.
+        'mutual_info' uses the mutual information, while 'anova' use
+        the ANOVA F-value.
+
+    window_sizes : array-like or 'auto '(default = 'auto')
+        Size of the sliding windows. If 'auto', the range for the
+        window sizes is determined automatically.
+        Otherwise, all the elements must be either integers or floats.
+        In the latter case, each element represents the percentage
+        of the size of each time series and must be between 0 and 1; the size
+        of the sliding windows will be computed as
+        ``np.ceil(window_sizes * n_timestamps)``.
+
+    window_steps : None or array-like (default = None)
+        Step of the sliding windows. If None, each ``window_step`` is equal
+        to 1. Otherwise, all the elements must be either integers or floats.
+        In the latter case, each element represents the percentage of the size
+        of each time series and must be between 0 and 1; the step of the
+        sliding windows will be computed as
+        ``np.ceil(window_steps * n_timestamps)``.
+        Must be None if ``window_sizes='auto'``.
+
+    remove_similar : bool (default = True)
+        If True, self-similar shapelets are removed, keeping only
+        the non-self-similar shapelets with the highest scores. Two
+        shapelets are considered to be self-similar if they are
+        taken from the the same time series and have at least one
+        overlapping index.
+
+    sort : bool (default = False)
+        If True, shapelets are sorted in descending order according to
+        their associated scores. If False, the order is undefined.
+
+    verbose : int (default = 0)
+        Verbosity level when fitting: if non zero, progress messages are
+        printed. Above 50, the output is sent to stdout.
+        The frequency of the messages increases with the verbosity level.
+
+    random_state : int, RandomState instance or None (default = None)
+        If int, random_state is the seed used by the random number generator;
+        If RandomState instance, random_state is the random number generator;
+        If None, the random number generator is the RandomState instance used
+        by ``np.random``. Only used if ``window_sizes='auto'`` in order to
+        subsample the dataset to find the best range or if
+        ``criterion=='mutual_info'`` to add small noise to the data.
+
+    n_jobs : None or int (default = None)
+        The number of jobs to run in parallel for ``fit``.
+        If -1, then the number of jobs is set to the number of cores.
+
+    Attributes
+    ----------
+    shapelets_ : array, shape = (n_shapelets,)
+        The array with the selected shapelets.
+
+    indices_ : array, shape = (n_shapelets, 3)
+        The indices for the corresponding shapelets in the training set.
+        The first column consists of the indices of the samples.
+        The second column consists of the starting indices (included)
+        of the shapelets. The third column consists of the ending indices
+        (excluded) of the shapelets.
+
+    scores_ : array, shape = (n_shapelets,)
+        The scores associated to the shapelets. The higher, the more
+        discriminant.
+        If ``criterion='mutual_info'``, mutual information scores are reported.
+        If ``criterion='anova'``, F-scores are reported.
+
+    window_range_ : None or tuple
+        Range of the window sizes if ``window_sizes='auto'``. None otherwise.
+
+    References
+    ----------
+    .. [1] J. Lines, L. M. Davis, J. Hills and A. Bagnall, "A Shapelet
+           Transform for Time Series Classification". Data Mining and Knowledge
+           Discovery, 289-297 (2012).
+
+    Examples
+    --------
+    >>> from sktime.transformations.panel.shapelet_transform import (
+    ...     ShapeletTransformPyts
+    ... )
+    >>> from sktime.datasets import load_unit_test
+    >>> X_train, y_train = load_unit_test(split="train") # doctest: +SKIP
+    >>> stp = ShapeletTransformPyts() # doctest: +SKIP
+    >>> stp.fit(X_train,y_train) # doctest: +SKIP
+    >>> stp.transform(X_train) # doctest: +SKIP
+    """
+
+    _tags = {
+        # packaging info
+        # --------------
+        "authors": "Abhay-Lejith",
+        "python_dependencies": "pyts",
+        # univariate-only controls whether internal X can be univariate/multivariate
+        # if True (only univariate), always applies vectorization over variables
+        "univariate-only": True,
+        "scitype:transform-input": "Series",
+        "scitype:transform-output": "Primitives",
+        "scitype:instancewise": False,
+        "fit_is_empty": False,
+        "y_inner_mtype": "numpy1D",
+        "requires_y": True,
+    }
+
+    _estimator_attr = "_pyts_shapelet_transform"
+
+    def _get_pyts_class(self):
+        """Get pyts class.
+
+        should import and return pyts class
+        """
+        from pyts.transformation.shapelet_transform import ShapeletTransform
+
+        return ShapeletTransform
+
+    def __init__(
+        self,
+        n_shapelets="auto",
+        criterion="mutual_info",
+        window_sizes="auto",
+        window_steps=None,
+        remove_similar=True,
+        sort=False,
+        verbose=0,
+        random_state=None,
+        n_jobs=None,
+    ):
+        self.n_shapelets = n_shapelets
+        self.criterion = criterion
+        self.window_sizes = window_sizes
+        self.window_steps = window_steps
+        self.remove_similar = remove_similar
+        self.sort = sort
+        self.verbose = verbose
+        self.random_state = random_state
+        self.n_jobs = n_jobs
+
+        super().__init__()
+
+    @classmethod
+    def get_test_params(cls, parameter_set="default"):
+        """
+        Return testing parameter settings for the estimator.
+
+        Parameters
+        ----------
+        parameter_set : str, default="default"
+            Name of the set of test parameters to return, for use in tests. If no
+            special parameters are defined for a value, will return `"default"` set.
+
+
+        Returns
+        -------
+        params : dict or list of dict, default = {}
+            Parameters to create testing instances of the class
+            Each dict are parameters to construct an "interesting" test instance, i.e.,
+            `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance.
+            `create_test_instance` uses the first (or only) dictionary in `params`
+        """
+        params1 = {"criterion": "anova", "n_shapelets": 10}
+        params2 = {"window_sizes": [3]}
+        return [params1, params2]
diff --git a/sktime/transformations/series/summarize.py b/sktime/transformations/series/summarize.py
index 8347e2289..86d000ad7 100644
--- a/sktime/transformations/series/summarize.py
+++ b/sktime/transformations/series/summarize.py
@@ -473,38 +473,37 @@ def _window_feature(Z, summarizer=None, window=None, bfill=False):
             if bfill is False:
                 feat = Z.apply(
                     lambda x: getattr(
-                        x.shift(lag).rolling(
-                            window=window_length, min_periods=window_length
-                        ),
+                        x.rolling(window=window_length, min_periods=window_length),
                         summarizer,
-                    )()
+                    )().shift(lag)
                 )
             else:
                 feat = Z.apply(
                     lambda x: getattr(
-                        x.shift(lag)
-                        .bfill()
-                        .rolling(window=window_length, min_periods=window_length),
+                        x.rolling(window=window_length, min_periods=window_length),
                         summarizer,
                     )()
+                    .shift(lag)
+                    .bfill()
                 )
     else:
-        if bfill is False:
-            feat = Z.shift(lag)
-        else:
-            feat = Z.shift(lag).bfill()
         if isinstance(Z, pd.core.groupby.generic.SeriesGroupBy) and callable(
             summarizer
         ):
-            feat = feat.rolling(window_length).apply(summarizer, raw=True)
+            feat = Z.rolling(window_length).apply(summarizer, raw=True)
         elif not isinstance(Z, pd.core.groupby.generic.SeriesGroupBy) and callable(
             summarizer
         ):
-            feat = feat.apply(
+            feat = Z.apply(
                 lambda x: x.rolling(
                     window=window_length, min_periods=window_length
                 ).apply(summarizer, raw=True)
             )
+        if bfill is False:
+            feat = Z.shift(lag)
+        else:
+            feat = Z.shift(lag).bfill()
+
         feat = pd.DataFrame(feat)
     if bfill is True:
         feat = feat.bfill()
diff --git a/sktime/transformations/series/temporian.py b/sktime/transformations/series/temporian.py
new file mode 100644
index 000000000..01ddf472a
--- /dev/null
+++ b/sktime/transformations/series/temporian.py
@@ -0,0 +1,154 @@
+# copyright: sktime developers, BSD-3-Clause License (see LICENSE file)
+
+"""Implementation of TemporianTransformer. Contributed by the Temporian team."""
+
+__author__ = ["ianspektor", "javiber"]
+
+from sktime.transformations.base import BaseTransformer
+
+
+class TemporianTransformer(BaseTransformer):
+    """Applies a Temporian function to the input time series.
+
+    This transformer applies a Temporian [1]_ function to the input time series.
+
+    The conversion from sktime's internal representation to Temporian's EventSet [2]_
+    and back is handled automatically by the transformer.
+
+    Parameters
+    ----------
+    function : Callable[[temporian.EventSet], temporian.EventSet]
+        Temporian function to apply to the input time series. The function must receive
+        and return a single Temporian EventSet, and can apply an arbitrary number of
+        Temporian operators to its input.
+    compile : bool, default=False
+        If True, the function will be compiled using Temporian's @tp.compile [3]_
+        decorator, which can lead to significant speedups by optimizing the graph of
+        operations.
+
+    Examples
+    --------
+    >>> from sktime.datasets import load_airline
+    >>> from sktime.transformations.series.temporian import TemporianTransformer
+    >>> import temporian as tp  # doctest: +SKIP
+    >>>
+    >>> def function(evset):  # doctest: +SKIP
+    ...     return evset.simple_moving_average(tp.duration.days(3 * 365))  \
+        # doctest: +SKIP
+    >>> transformer = TemporianTransformer(function=function)  # doctest: +SKIP
+    >>> X = load_airline()  # doctest: +SKIP
+    >>> X_averaged = transformer.fit_transform(X)  # doctest: +SKIP
+
+    References
+    ----------
+    .. [1] https://temporian.readthedocs.io/en/stable/
+    .. [2] https://temporian.readthedocs.io/en/stable/reference/temporian/EventSet/
+    .. [3] https://temporian.readthedocs.io/en/stable/reference/temporian/compile/
+    """
+
+    _tags = {
+        # packaging info
+        # --------------
+        "authors": ["ianspektor", "javiber"],
+        "maintainers": ["ianspektor", "javiber"],
+        "python_dependencies": ["temporian"],
+        "python_version": ">=3.8",
+        # estimator tags
+        # --------------
+        "univariate-only": False,
+        "scitype:transform-input": "Series",
+        "scitype:transform-output": "Series",
+        "scitype:instancewise": True,
+        "scitype:transform-labels": "None",
+        "X_inner_mtype": "pd.DataFrame",
+        "fit_is_empty": True,
+        "capability:inverse_transform": False,
+        "capability:unequal_length": True,
+        "handles-missing-data": False,
+    }
+
+    def __init__(self, function, compile=False):
+        self.function = function
+        self.compile = compile
+
+        super().__init__()
+
+    def _transform(self, X, y=None):
+        """Transform X and return a transformed version.
+
+        private _transform containing core logic, called from transform
+
+        Parameters
+        ----------
+        X : pd.DataFrame
+            if self.get_tag("univariate-only")==True:
+                guaranteed to have a single column
+            if self.get_tag("univariate-only")==False: no restrictions apply
+        y : None, present only for interface compatibility
+
+        Returns
+        -------
+        transformed version of X
+        """
+        import temporian as tp
+
+        X_noindex = X.reset_index(drop=False)
+        X_noindex.columns = X_noindex.columns.astype(str)
+        timestamps_col = X_noindex.columns[0]
+        evset = tp.from_pandas(X_noindex, timestamps=timestamps_col)
+
+        function = tp.compile(self.function) if self.compile else self.function
+
+        res = function(evset)
+        if not isinstance(res, tp.EventSet):
+            raise TypeError(
+                f"Expected return type to be an EventSet but received a {type(res)}"
+            )
+
+        # Test that the sampling was not modified, otherwise the conversion back to
+        # pandas and the set_index would not work as expected
+        try:
+            res.check_same_sampling(evset)
+        except ValueError as exc:
+            raise ValueError(
+                "The resulting EventSet must have the same sampling as the input. "
+                "Visit our docs for more info "
+                "https://temporian.readthedocs.io/en/stable/user_guide/#sampling"
+            ) from exc
+
+        res = tp.to_pandas(res, timestamps=False)
+        res = res.set_index(X.index)
+
+        return res
+
+    @classmethod
+    def get_test_params(cls, parameter_set="default"):
+        """Return testing parameter settings for the estimator.
+
+        Parameters
+        ----------
+        parameter_set : str, default="default"
+            Name of the set of test parameters to return, for use in tests. If no
+            special parameters are defined for a value, will return `"default"` set.
+            There are currently no reserved values for transformers.
+
+        Returns
+        -------
+        params : dict or list of dict, default = {}
+            Parameters to create testing instances of the class
+            Each dict are parameters to construct an "interesting" test instance, i.e.,
+            `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance.
+            `create_test_instance` uses the first (or only) dictionary in `params`
+        """
+        return [
+            {"function": _test_function_single_op, "compile": False},
+            {"function": _test_function_many_ops, "compile": True},
+        ]
+
+
+def _test_function_single_op(evset):
+    return evset + 1
+
+
+def _test_function_many_ops(evset):
+    return evset.simple_moving_average(10).lag(10).resample(evset)


Test patch:
diff --git a/sktime/forecasting/base/tests/test_fh.py b/sktime/forecasting/base/tests/test_fh.py
index 524163439..206470066 100644
--- a/sktime/forecasting/base/tests/test_fh.py
+++ b/sktime/forecasting/base/tests/test_fh.py
@@ -41,6 +41,7 @@ from sktime.utils.datetime import (
     _shift,
     infer_freq,
 )
+from sktime.utils.validation._dependencies import _check_soft_dependencies
 from sktime.utils.validation.series import is_in_valid_index_types, is_integer_index
 
 
@@ -326,11 +327,16 @@ FREQUENCY_STRINGS = [*FIXED_FREQUENCY_STRINGS, *NON_FIXED_FREQUENCY_STRINGS]
 
 def _get_expected_freqstr(freqstr):
     # special case for 10min, T is being deprecated and replaced by min
-    if freqstr == "10min":
-        fh_freqstr_expected = "10T"
-    else:
-        fh_freqstr_expected = freqstr
-    return fh_freqstr_expected
+    if _check_soft_dependencies("pandas<2.2.0", severity="none"):
+        if freqstr == "10min":
+            return "10T"
+        return freqstr
+    # on more recent pandas versions, >=2.2.0
+    if freqstr == "H":
+        return "h"
+    if freqstr == "M":
+        return "ME"
+    return freqstr
 
 
 @pytest.mark.parametrize("freqstr", FREQUENCY_STRINGS)
diff --git a/sktime/tests/_config.py b/sktime/tests/_config.py
index 144c8adcd..cc1024f4e 100644
--- a/sktime/tests/_config.py
+++ b/sktime/tests/_config.py
@@ -34,8 +34,6 @@ EXCLUDE_ESTIMATORS = [
     # DL classifier suspected to cause hangs and memouts, see #4610
     "FCNClassifier",
     "MACNNClassifier",
-    "SimpleRNNClassifier",
-    "SimpleRNNRegressor",
     "EditDist",
     "CNNClassifier",
     "FCNClassifier",
@@ -48,7 +46,6 @@ EXCLUDE_ESTIMATORS = [
     "FCNRegressor",
     "LSTMFCNRegressor",
     "MACNNRegressor",
-    "InceptionTimeRegressor",
     "CNTCClassifier",
     "CNTCRegressor",
 ]
@@ -218,6 +215,8 @@ EXCLUDED_TESTS = {
     "StatsForecastMSTL": ["test_pred_int_tag"],
     # KNeighborsTimeSeriesClassifierTslearn crashes in parallel mode
     "KNeighborsTimeSeriesClassifierTslearn": ["test_multiprocessing_idempotent"],
+    # ShapeletTransformPyts creates nested numpy shapelets sporadically, see #6171
+    "ShapeletTransformPyts": ["test_non_state_changing_method_contract"],
 }
 
 # We use estimator tags in addition to class hierarchies to further distinguish
diff --git a/sktime/tests/test_softdeps.py b/sktime/tests/test_softdeps.py
index c83d6ada8..7f3d100b2 100644
--- a/sktime/tests/test_softdeps.py
+++ b/sktime/tests/test_softdeps.py
@@ -53,6 +53,7 @@ EXCEPTED_FROM_NO_DEP_CHECK = []
 EXCEPTED_FROM_GET_PARAMS_CHECK = [
     "PyODAnnotator",  # adapters always require soft dep. Here: pyod
     "HCrystalBallAdapter",  # adapters always require soft dep. Here: hcrystalball
+    "TemporianTransformer",  # adapters always require soft dep. Here: temporian
 ]
 
 
diff --git a/sktime/transformations/panel/shapelet_transform/tests/__init__.py b/sktime/transformations/panel/shapelet_transform/tests/__init__.py
new file mode 100644
index 000000000..37034d8e4
--- /dev/null
+++ b/sktime/transformations/panel/shapelet_transform/tests/__init__.py
@@ -0,0 +1,1 @@
+"""Shapelet transform unit tests."""
diff --git a/sktime/transformations/panel/tests/test_shapelet_transform.py b/sktime/transformations/panel/shapelet_transform/tests/test_shapelet_transform.py
similarity index 100%
rename from sktime/transformations/panel/tests/test_shapelet_transform.py
rename to sktime/transformations/panel/shapelet_transform/tests/test_shapelet_transform.py
diff --git a/sktime/transformations/panel/shapelet_transform/tests/test_shapelet_transform_pyts.py b/sktime/transformations/panel/shapelet_transform/tests/test_shapelet_transform_pyts.py
new file mode 100644
index 000000000..23384c840
--- /dev/null
+++ b/sktime/transformations/panel/shapelet_transform/tests/test_shapelet_transform_pyts.py
@@ -0,0 +1,40 @@
+"""ShapeletTransformPyts test code."""
+import numpy as np
+import pytest
+from numpy import testing
+
+from sktime.datasets import load_unit_test
+from sktime.tests.test_switch import run_test_for_class
+from sktime.transformations.panel.shapelet_transform import ShapeletTransformPyts
+
+
+@pytest.mark.skipif(
+    not run_test_for_class(ShapeletTransformPyts),
+    reason="run test only if softdeps are present and incrementally (if requested)",
+)
+def test_stp_on_unit_test():
+    """Test of ShapeletTransformPyts on unit test data."""
+    # load unit test data
+    X_train, y_train = load_unit_test(split="train")
+    indices = np.random.RandomState(0).choice(len(y_train), 5, replace=False)
+
+    # fit the shapelet transform
+    stp = ShapeletTransformPyts(n_shapelets=5, random_state=0)
+    stp.fit(X_train.iloc[indices], y_train[indices])
+
+    # assert transformed data is the same
+    data = stp.transform(X_train.iloc[indices])
+    testing.assert_array_almost_equal(
+        data, shapelet_transform_unit_test_data, decimal=4
+    )
+
+
+shapelet_transform_unit_test_data = np.array(
+    [
+        [176.0, 14.866069, 17.262677, 0.000000, 7.0],
+        [0.0, 51.908573, 82.197932, 65.517173, 15.0],
+        [223.0, 30.413813, 0.000000, 17.262677, 7.0],
+        [1.0, 61.159627, 71.515733, 59.502101, 19.0],
+        [32.0, 0.000000, 30.413813, 14.866069, 0.0],
+    ]
+)
diff --git a/sktime/transformations/series/tests/test_temporian.py b/sktime/transformations/series/tests/test_temporian.py
new file mode 100644
index 000000000..7a7138d10
--- /dev/null
+++ b/sktime/transformations/series/tests/test_temporian.py
@@ -0,0 +1,225 @@
+"""Tests for TemporianTransformer."""
+
+# copyright: sktime developers, BSD-3-Clause License (see LICENSE file).
+
+__author__ = ["ianspektor", "javiber"]
+
+from datetime import datetime
+from unittest.mock import patch
+
+import numpy as np
+import pandas as pd
+import pytest
+
+from sktime.datasets import load_solar
+from sktime.datatypes import get_examples
+from sktime.tests.test_switch import run_test_for_class
+from sktime.transformations.series.temporian import TemporianTransformer
+
+
+@pytest.mark.skipif(
+    not run_test_for_class(TemporianTransformer),
+    reason="run test only if softdeps are present and incrementally (if requested)",
+)
+def test_flat_univariate():
+    """Tests basic function works on flat (non-indexed) univariate time series."""
+    X = load_solar()[0:32]
+
+    def function(evset):
+        return evset["solar_gen"] + 1
+
+    transformer = TemporianTransformer(function=function)
+    X_transformed = transformer.fit_transform(X=X)
+
+    pd.testing.assert_series_equal(X_transformed, X + 1)
+
+
+@pytest.mark.skipif(
+    not run_test_for_class(TemporianTransformer),
+    reason="run test only if softdeps are present and incrementally (if requested)",
+)
+def test_panel():
+    """Tests basic function works on Panels."""
+
+    def function(evset):
+        return evset + 1
+
+    examples = get_examples("pd-multiindex", as_scitype="Panel").values()
+    assert len(examples) > 0
+
+    for X in examples:
+        transformer = TemporianTransformer(function=function)
+        X_transformed = transformer.fit_transform(X=X)
+        pd.testing.assert_frame_equal(X_transformed, X + 1)
+
+
+@pytest.mark.skipif(
+    not run_test_for_class(TemporianTransformer),
+    reason="run test only if softdeps are present and incrementally (if requested)",
+)
+def test_hier():
+    """Tests basic function works on Hierarchical."""
+
+    def function(evset):
+        return evset + 1
+
+    examples = get_examples("pd_multiindex_hier", as_scitype="Hierarchical").values()
+    assert len(examples) > 0
+
+    for X in examples:
+        transformer = TemporianTransformer(function=function)
+        X_transformed = transformer.fit_transform(X=X)
+        pd.testing.assert_frame_equal(X_transformed, X + 1)
+
+
+@pytest.mark.skipif(
+    not run_test_for_class(TemporianTransformer),
+    reason="run test only if softdeps are present and incrementally (if requested)",
+)
+def test_dtypes():
+    """Tests basic function works on all dtypes."""
+
+    def function(evset):
+        return evset + 1
+
+    X = pd.DataFrame(
+        {
+            str(dtype): np.zeros(10).astype(dtype)
+            for dtype in [
+                np.int32,
+                np.int64,
+                np.float32,
+                np.float64,
+            ]
+        }
+    )
+    transformer = TemporianTransformer(function=function)
+    X_transformed = transformer.fit_transform(X=X)
+    pd.testing.assert_frame_equal(X_transformed, X + 1)
+
+
+@pytest.mark.skipif(
+    not run_test_for_class(TemporianTransformer),
+    reason="run test only if softdeps are present and incrementally (if requested)",
+)
+def test_compiled():
+    """Tests compiling the function."""
+    import temporian as tp
+
+    def function(evset):
+        return evset + 1
+
+    X = get_examples("pd.Series", as_scitype="Series")[0]
+
+    true_compile = tp.compile
+
+    with patch.object(tp, "compile") as compile_patch:
+        compile_patch.side_effect = true_compile
+        transformer = TemporianTransformer(function=function, compile=True)
+        X_transformed = transformer.fit_transform(X=X)
+        pd.testing.assert_series_equal(X_transformed, X + 1)
+        compile_patch.assert_called_once_with(function)
+
+
+@pytest.mark.skipif(
+    not run_test_for_class(TemporianTransformer),
+    reason="run test only if softdeps are present and incrementally (if requested)",
+)
+def test_compile_already_compiled():
+    """Tests compiling doesn't fail if the function was compiled already."""
+    import temporian as tp
+
+    @tp.compile
+    def function(evset):
+        return evset + 1
+
+    X = get_examples("pd.Series", as_scitype="Series")[0]
+
+    true_compile = tp.compile
+
+    with patch.object(tp, "compile") as compile_patch:
+        compile_patch.side_effect = true_compile
+        transformer = TemporianTransformer(function, compile=True)
+        X_transformed = transformer.fit_transform(X=X)
+        pd.testing.assert_series_equal(X_transformed, X + 1)
+        compile_patch.assert_called_once_with(function)
+
+
+@pytest.mark.skipif(
+    not run_test_for_class(TemporianTransformer),
+    reason="run test only if softdeps are present and incrementally (if requested)",
+)
+def test_multiple_output():
+    """Tests errors when functions return incorrect types."""
+
+    def function(evset):
+        split = datetime(1950, 7, 16)
+        return evset.before(split), evset.after(split)
+
+    X = load_solar()
+
+    transformer = TemporianTransformer(function=function)
+    with pytest.raises(
+        TypeError, match="Expected return type to be an EventSet but received"
+    ):
+        _ = transformer.fit_transform(X=X)
+
+
+@pytest.mark.skipif(
+    not run_test_for_class(TemporianTransformer),
+    reason="run test only if softdeps are present and incrementally (if requested)",
+)
+def test_multiple_input():
+    """Tests errors on incorrectly defined functions."""
+
+    def function(evset, incorrect_param):
+        return evset + 1
+
+    X = load_solar()
+
+    transformer = TemporianTransformer(function=function)
+    with pytest.raises(TypeError, match="missing 1 required positional"):
+        _ = transformer.fit_transform(X=X)
+
+
+@pytest.mark.skipif(
+    not run_test_for_class(TemporianTransformer),
+    reason="run test only if softdeps are present and incrementally (if requested)",
+)
+def test_change_sampling():
+    """Tests error when changing the sampling."""
+    import temporian as tp
+
+    # in this dataset each row is a period of 1/2 hour
+    # lagging for one hour would remove the first two rows thus changing the sampling
+    X = load_solar()
+
+    def function(evset):
+        return evset.lag(tp.duration.hours(1))
+
+    transformer = TemporianTransformer(function=function, compile=True)
+    with pytest.raises(
+        ValueError,
+        match="The resulting EventSet must have the same sampling as the input",
+    ):
+        _ = transformer.fit_transform(X=X)
+
+
+@pytest.mark.skipif(
+    not run_test_for_class(TemporianTransformer),
+    reason="run test only if softdeps are present and incrementally (if requested)",
+)
+def test_complex_function():
+    import temporian as tp
+
+    # in this dataset each row is a period of 1/2 hour
+
+    def function(evset):
+        return evset.simple_moving_average(tp.duration.days(1)).resample(evset)
+
+    X = load_solar()
+
+    transformer = TemporianTransformer(function=function, compile=True)
+    result = transformer.fit_transform(X=X)
+    assert result.iloc[0] == X.iloc[0]
+    assert np.allclose(result.iloc[-1], X.iloc[-48:].mean())
diff --git a/sktime/transformations/series/tests/test_window_summarizer.py b/sktime/transformations/series/tests/test_window_summarizer.py
index 0d0306798..7cb16aadf 100644
--- a/sktime/transformations/series/tests/test_window_summarizer.py
+++ b/sktime/transformations/series/tests/test_window_summarizer.py
@@ -76,6 +76,13 @@ kwargs_custom = {
         count_gt100: [[3, 2]],
     }
 }
+
+kwargs_negative_lags = {
+    "lag_feature": {
+        "mean": [[-1, 1], [-1, 2]],
+    }
+}
+
 # Generate named and unnamed y
 y_train.name = None
 y_train_named = y_train.copy()
@@ -94,6 +101,20 @@ Xtmvar_none = ["GNPDEFL_lag_3", "GNPDEFL_lag_6", "GNP", "UNEMP", "ARMED", "POP"]
 @pytest.mark.parametrize(
     "kwargs, column_names, y, target_cols, truncate",
     [
+        (
+            kwargs_negative_lags,
+            ["a_mean_-1_1", "a_mean_-1_2"],
+            y_pd,
+            None,
+            None,
+        ),
+        (
+            kwargs_negative_lags,
+            ["y_mean_-1_1", "y_mean_-1_2"],
+            y_hierarchical,
+            None,
+            None,
+        ),
         (
             kwargs,
             ["y_lag_1", "y_mean_1_3", "y_mean_1_12", "y_std_1_4"],
diff --git a/sktime/utils/tests/test_datetime.py b/sktime/utils/tests/test_datetime.py
index be7b95155..c83cd4ef8 100755
--- a/sktime/utils/tests/test_datetime.py
+++ b/sktime/utils/tests/test_datetime.py
@@ -82,7 +82,7 @@ def test_infer_freq() -> None:
 
     index = pd.date_range(start="2021-01-01", periods=1, freq="M")
     y = pd.Series(index=index, dtype=int)
-    assert infer_freq(y) == "M"
+    assert infer_freq(y) in ["M", "ME"]
 
     y = pd.DataFrame({"a": 1}, index=pd.date_range(start="2021-01-01", periods=1))
     assert infer_freq(y) == "D"
@@ -90,39 +90,11 @@ def test_infer_freq() -> None:
     y = pd.DataFrame(
         {"a": 1}, index=pd.date_range(start="2021-01-01", periods=1, freq="M")
     )
-    assert infer_freq(y) == "M"
+    assert infer_freq(y) in ["M", "ME"]
 
     y = _bottom_hier_datagen(no_levels=2)
     y = VectorizedDF(X=y, iterate_as="Series", is_scitype="Hierarchical")
-    assert infer_freq(y) == "M"
-
-
-def test_set_freq() -> None:
-    """Test frequency inference."""
-    assert infer_freq(None) is None
-
-    y = pd.Series(dtype=int)
-    assert infer_freq(y) is None
-
-    index = pd.date_range(start="2021-01-01", periods=1)
-    y = pd.Series(index=index, dtype=int)
-    assert infer_freq(y) == "D"
-
-    index = pd.date_range(start="2021-01-01", periods=1, freq="M")
-    y = pd.Series(index=index, dtype=int)
-    assert infer_freq(y) == "M"
-
-    y = pd.DataFrame({"a": 1}, index=pd.date_range(start="2021-01-01", periods=1))
-    assert infer_freq(y) == "D"
-
-    y = pd.DataFrame(
-        {"a": 1}, index=pd.date_range(start="2021-01-01", periods=1, freq="M")
-    )
-    assert infer_freq(y) == "M"
-
-    y = _bottom_hier_datagen(no_levels=2)
-    y = VectorizedDF(X=y, iterate_as="Series", is_scitype="Hierarchical")
-    assert infer_freq(y) == "M"
+    assert infer_freq(y) in ["M", "ME"]
 
 
 def test_set_freq_hier():