Repository: sktime/sktime (python)

Issue:
[DOC] Document the `int_label` option in `BaseSeriesAnnotator`
#### Describe the issue linked to the documentation

<!--
Tell us about the confusion introduced in the documentation.
-->

The `BaseSeriesAnnotator` class has the attribute `labels` which, according to the documentation, can be either `indicator` or `score`. However, the `HMM` class which inherits from `BaseSeriesAnnotator` uses `int_label` for the `labels` attribute, this option is not documented in `BaseSeriesAnnotator`.

The label `int_label` means that for observations `obs = [10, 11, 8, -1. -4. -2]`, the annotator should produce an output like `y = [0, 0, 0, 1, 1, 1]`.

#### Suggest a potential alternative/fix

<!--
Tell us how we could improve the documentation in this regard.
-->

Add proprer documentation to the `BaseSeriesAnnotator` for the `int_label` option for the `labels` parameter.

#### Other comments

There are other algorithms in the annotations module which produce integer labels, such as `GreedyGaussianSegmentation` (GSS), which do not inherit from `BaseSeriesAnnotator`. Perhaps we can change `GreedyGaussianSegmentation` to inherit from `BaseSeriesAnnotator` and use the `int_label` option.


Pull request description:
[DOC] in `BaseSeriesAnnotator`, document the `int_label` option
<!--
Welcome to sktime, and thanks for contributing!
Please have a look at our contribution guide:
https://www.sktime.net/en/latest/get_involved/contributing.html
-->

#### Reference Issues/PRs
<!--
Example: Fixes #1234. See also #3456.

Please use keywords (e.g., Fixes) to create link to the issues or pull requests
you resolved, so that they will automatically be closed when your pull request
is merged. See https://github.com/blog/1506-closing-issues-via-pull-requests.
If no issue exists, you can open one here: https://github.com/sktime/sktime/issues
-->

Closes #5305.

#### What does this implement/fix? Explain your changes.
<!--
A clear and concise description of what you have implemented.
-->

This PR documents the `int_label` option in the `BaseSeriesAnnotator` class. This option is used in the the greedy gaussian segmentation model and the hidden markov model.

#### Does your contribution introduce a new dependency? If yes, which one?

No.
<!--
Only relevant if you changed pyproject.toml.
We try to minimize dependencies in the core dependency set. There
are also further specific instructions to follow for soft dependencies.
See here for handling dependencies in sktime: https://www.sktime.net/en/latest/developer_guide/dependencies.html
-->

#### What should a reviewer concentrate their feedback on?

<!-- This section is particularly useful if you have a pull request that is still in development. You can guide the reviews to focus on the parts that are ready for their comments. We suggest using bullets (indicated by * or -) and filled checkboxes [x] here -->

#### Did you add any tests for the change?

<!-- This section is useful if you have added a test in addition to the existing ones. This will ensure that further changes to these files won't introduce the same kind of bug. It is considered good practice to add tests with newly added code to enforce the fact that the code actually works. This will reduce the chance of introducing logical bugs.
-->

#### Any other comments?
<!--
We value all user contributions, no matter how small or complex they are. If you have any questions, feel free to post
in the dev-chat channel on the sktime discord https://discord.com/invite/54ACzaFsn7. If we are slow to review (>3 working days), likewise feel free to ping us on discord. Thank you for your understanding during the review process.
-->

#### PR checklist
<!--
Please go through the checklist below. Please feel free to remove points if they are not applicable.
-->

##### For all contributions
- [x] I've added myself to the [list of contributors](https://github.com/sktime/sktime/blob/main/CONTRIBUTORS.md) with any new badges I've earned :-)
  How to: add yourself to the [all-contributors file](https://github.com/sktime/sktime/blob/main/.all-contributorsrc) in the `sktime` root directory (not the `CONTRIBUTORS.md`). Common badges: `code` - fixing a bug, or adding code logic. `doc` - writing or improving documentation or docstrings. `bug` - reporting or diagnosing a bug (get this plus `code` if you also fixed the bug in the PR).`maintenance` - CI, test framework, release.
  See here for [full badge reference](https://allcontributors.org/docs/en/emoji-key)
- [ ] Optionally, I've added myself and possibly others to the [CODEOWNERS](https://github.com/sktime/sktime/blob/main/CODEOWNERS) file - do this if you want to become the owner or maintainer of an estimator you added.
  See here for further details on the [algorithm maintainer role](https://www.sktime.net/en/latest/get_involved/governance.html#algorithm-maintainers).
- [x] The PR title starts with either [ENH], [MNT], [DOC], or [BUG]. [BUG] - bugfix, [MNT] - CI, test framework, [ENH] - adding or improving code, [DOC] - writing or improving documentation or docstrings.

<!--
Thanks for contributing!
-->


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/resnet.py b/sktime/classification/deep_learning/resnet.py
index f85fcf7f0..44c3ef4c5 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(...)
     """
 
diff --git a/sktime/classification/deep_learning/rnn.py b/sktime/classification/deep_learning/rnn.py
index ab651853f..e5b6b0815 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 = {
@@ -121,7 +130,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/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/mlp.py b/sktime/regression/deep_learning/mlp.py
index 5c0f26d75..354daca74 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 = {
diff --git a/sktime/regression/deep_learning/rnn.py b/sktime/regression/deep_learning/rnn.py
index 1ea5ed4bd..7d40c7ce1 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 = {
@@ -117,7 +126,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/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/tests/_config.py b/sktime/tests/_config.py
index 144c8adcd..2f07f028d 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",
@@ -218,6 +216,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"],