Repository: sktime/sktime
Pull request #6221 (2024-03-27 09:36:40)

Release 0.28.0
Release PR for 0.28.0

* version number bump
* changelog


Patch:
diff --git a/README.md b/README.md
index 7880d5969..9d74745e2 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
 
 > A unified interface for machine learning with time series
 
-:rocket: **Version 0.27.1 out now!** [Check out the release notes here](https://www.sktime.net/en/latest/changelog.html).
+:rocket: **Version 0.28.0 out now!** [Check out the release notes here](https://www.sktime.net/en/latest/changelog.html).
 
 sktime is a library for time series analysis in Python. It provides a unified interface for multiple time series learning tasks. Currently, this includes time series classification, regression, clustering, annotation, and forecasting. It comes with [time series algorithms](https://www.sktime.net/en/stable/estimator_overview.html) and [scikit-learn] compatible tools to build, tune and validate time series models.
 
diff --git a/docs/source/api_reference/transformations.rst b/docs/source/api_reference/transformations.rst
index 1a2388973..b584c4d25 100644
--- a/docs/source/api_reference/transformations.rst
+++ b/docs/source/api_reference/transformations.rst
@@ -445,7 +445,7 @@ Binning, sampling and segmentation
     :toctree: auto_generated/
     :template: class.rst
 
-    PAA2
+    PAA
 
 .. currentmodule:: sktime.transformations.series.sax
 
@@ -453,7 +453,7 @@ Binning, sampling and segmentation
     :toctree: auto_generated/
     :template: class.rst
 
-    SAX2
+    SAX
 
 .. currentmodule:: sktime.transformations.panel.dictionary_based
 
@@ -461,8 +461,8 @@ Binning, sampling and segmentation
     :toctree: auto_generated/
     :template: class.rst
 
-    PAA
-    SAX
+    PAAlegacy
+    SAXlegacy
 
 Missing value treatment
 ~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst
index df5ddd738..81a4e77d5 100644
--- a/docs/source/changelog.rst
+++ b/docs/source/changelog.rst
@@ -18,6 +18,97 @@ available on GitHub.
 For upcoming changes and next releases, see our `milestones <https://github.com/sktime/sktime/milestones?direction=asc&sort=due_date&state=open>`_.
 For our long-term plan, see our :ref:`roadmap`.
 
+Version 0.28.0 - 2024-03-27
+---------------------------
+
+Maintenance release:
+
+* scheduled deprecations and change actions
+* support for ``pandas 2.2.X``
+
+For last non-maintenance content updates, see 0.27.1.
+
+Dependency changes
+~~~~~~~~~~~~~~~~~~
+
+* ``sktime`` now supports ``pandas`` ``2.2.X``, bounds have been updated to ``<2.3.0,>=1.1``.
+* ``temporian`` (transformations soft dependency) bounds have been updated to ``>=0.7.0,<0.9.0``.
+* ``pykalman-bardo`` dependencies have been replaced by the original fork ``pykalman``.
+  ``pykalman-bardo`` has been merged back into ``pykalman``,
+  which is no longer abandoned.
+  This is a soft dependency, and the switch does not affect users installing
+  ``sktime`` using one of its dependency sets.
+
+
+Deprecations and removals
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Forecasting
+^^^^^^^^^^^
+
+* in ``ProphetPiecewiseLinearTrendForecaster``, the seasonality parameters
+  ``yearly_seasonality``, ``weekly_seasonality`` and ``daily_seasonality``
+  now have default values of ``False``.
+  To retain previous behaviour, set these parameters explicitly to ``"auto"``.
+
+Transformations
+^^^^^^^^^^^^^^^
+
+* The ``n_jobs`` parameter in the ``Catch22`` transformer is deprecated
+  and will be removed in 0.29.0.
+  Users should pass parallelization backend parameters via ``set_config`` instead.
+  To specify ``n_jobs``, use any of the backends supporting it in the
+  ``backend:parallel`` configuration, such as ``"loky"`` or ``"multithreading"``.
+  The ``n_jobs`` parameter should be passed via the
+  ``backend:parallel:params`` configuration.
+  To retain previous behaviour, with a specific setting of ``n_jobs=x``,
+  use ``set_config(**{"backend:parallel": "loky", "backend:parallel:params": {"n_jobs": x}})``.
+* The ``n_jobs`` parameter in the ``Catch22Wrapper`` transformer has been removed.
+  Users should pass parallelization backend parameters via ``set_config`` instead.
+  To specify ``n_jobs``, use any of the backends supporting it in the
+  ``backend:parallel`` configuration, such as ``"loky"`` or ``"multithreading"``.
+  The ``n_jobs`` parameter should be passed via the
+  ``backend:parallel:params`` configuration.
+  To retain previous behaviour, with a specific setting of ``n_jobs=x``,
+  use ``set_config(**{"backend:parallel": "loky", "backend:parallel:params": {"n_jobs": x}})``.
+* ``panel.dictionary_based.PAA`` has been renamed to ``PAAlegacy`` in 0.27.0,
+  and ``sktime.transformations.series.PAA2`` has been renamed to ``PAA``.
+  ``PAA`` is now the primary PAA implementation in ``sktime``.
+  After completion of the deprecation cycle, the estimators are no longer available
+  under their previous names.
+  To migrate dependent code to use the new names, do one of the following:
+  1. replace use of ``PAA`` from ``sktime.transformations.panel.dictionary_based``
+  by use of ``PAA2`` from ``sktime.transformations.series.paa``, switching
+  parameter names appropriately, or
+  2. replace use of ``PAA`` from ``sktime.transformations.panel.dictionary_based``
+  by use of ``PAAlegacy`` from ``sktime.transformations.panel.dictionary_based``,
+  without change of parameter values.
+* ``panel.dictionary_based.SAX`` has been renamed to ``SAXlegacy`` in 0.27.0,
+  while ``sktime.transformations.series.SAX2`` has been renamed to ``SAX``.
+  ``SAX`` is now the primary SAX implementation in ``sktime``,
+  while the former ``SAX`` will continue to be available as ``SAXlegacy``.
+  After completion of the deprecation cycle, the estimators are no longer available
+  under their previous names.
+  To migrate dependent code to use the new names, do one of the following:
+  1. replace use of ``SAX`` from ``sktime.transformations.panel.dictionary_based``
+  by use of ``SAX2`` from ``sktime.transformations.series.paa``, switching
+  parameter names appropriately, or
+  2. replace use of ``SAX`` from ``sktime.transformations.panel.dictionary_based``
+  by use of ``SAXlegacy`` from ``sktime.transformations.panel.dictionary_based``,
+  without change of parameter values.
+
+Contents
+~~~~~~~~
+
+* [MNT] 0.28.0 deprecations and change actions (:pr:`6198`) :user:`fkiraly`
+* [MNT] raise ``pandas`` bound to ``pandas<2.3.0`` (:pr:`5841`) :user:`fkiraly`
+* [MNT] update ``temporian`` bound to ``<0.9.0,!=0.8.0`` (:pr:`6222`) :user:`fkiraly`
+* [MNT] revert switch from ``pykalman`` to ``pykalman-bardo`` (:pr:`6114`) :user:`fkiraly`
+* [MNT] [Dependabot](deps-dev): Update ``pytest-cov`` requirement from ``<4.2,>=4.1`` to ``>=4.1,<5.1`` (:pr:`6215`) :user:`dependabot[bot]`
+* [MNT] [Dependabot](deps): Bump ``tj-actions/changed-files`` from 43 to 44 (:pr:`6226`) :user:`dependabot[bot]`
+* [ENH] stricter condition for ``get_test_params`` not failing in repo soft dependency isolation tests (:pr:`6223`) :user:`fkiraly`
+
+
 Version 0.27.1 - 2024-03-25
 ---------------------------
 
@@ -369,7 +460,6 @@ Maintenance
 * [MNT] 0.27.0 deprecations and change actions (:pr:`5974`) :user:`fkiraly`
 * [MNT] [Dependabot](deps-dev): Update ``numba`` requirement from ``<0.59`` to ``<0.60`` (:pr:`5877`) :user:`dependabot[bot]`
 
-Contributors
 
 Version 0.26.1 - 2024-02-26
 ---------------------------
@@ -521,8 +611,8 @@ Maintenance
 * [MNT] improvements to modular CI framework - part 2, merge frameworks (:pr:`5785`) :user:`fkiraly`
 * [MNT] ``pandas 2.2.X`` compatibility fixes (:pr:`5840`) :user:`fkiraly`
 * [MNT] fix moto breaking change by using different mocking methods depending on version (:pr:`5858`) :user:`yarnabrina`
-* [MNT] address some `pandas` deprecations (:pr:`5883`) :user:`fkiraly`
-* [MNT] addressed `FutureWarning` for RMSE by using newer ``root_mean_absolute_error`` function (:pr:`5884`) :user:`yarnabrina`
+* [MNT] address some ``pandas`` deprecations (:pr:`5883`) :user:`fkiraly`
+* [MNT] addressed ``FutureWarning`` for RMSE by using newer ``root_mean_absolute_error`` function (:pr:`5884`) :user:`yarnabrina`
 * [MNT] Skip ``mlflow`` tests when soft-dependencies are absent (:pr:`5888`) :user:`achieveordie`
 * [MNT] fix failing CRON "test all" workflow (:pr:`5925`) :user:`fkiraly`
 * [MNT] update versions of several actions (:pr:`5929`) :user:`yarnabrina`
diff --git a/pyproject.toml b/pyproject.toml
index d60b99911..22435d51a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [project]
 name = "sktime"
-version = "0.27.1"
+version = "0.28.0"
 description = "A unified framework for machine learning with time series"
 readme = "README.md"
 keywords = [
@@ -108,7 +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.8.0,>=0.7.0; python_version < "3.12" and sys_platform != "win32"',
+  'temporian<0.9.0,>=0.7.0,!=0.8.0; python_version < "3.12" and sys_platform != "win32"',
   'tensorflow<2.17,>=2; python_version < "3.12"',
   'tsbootstrap<0.2,>=0.1.0',
   'tsfresh>=0.17; python_version < "3.12"',
@@ -147,7 +147,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.8.0,>=0.7.0; python_version < "3.12" and sys_platform != "win32"',
+  'temporian<0.9.0,>=0.7.0,!=0.8.0; python_version < "3.12" and sys_platform != "win32"',
   'tensorflow<2.17,>=2; python_version < "3.12"',
   'tsbootstrap<0.2,>=0.1.0',
   'tsfresh>=0.17; python_version < "3.12"',
@@ -214,7 +214,7 @@ transformations = [
   "pykalman<0.10,>=0.9.5",
   "statsmodels<0.15,>=0.12.1",
   'stumpy<1.13,>=1.5.1; python_version < "3.12"',
-  'temporian<0.8.0,>=0.7.0; python_version < "3.12" and sys_platform != "win32"',
+  'temporian<0.9.0,>=0.7.0,!=0.8.0; python_version < "3.12" and sys_platform != "win32"',
   'tsbootstrap<0.2,>=0.1.0',
   'tsfresh<0.21,>=0.17; python_version < "3.12"',
 ]
diff --git a/sktime/__init__.py b/sktime/__init__.py
index a9a923c23..66a4c38c4 100644
--- a/sktime/__init__.py
+++ b/sktime/__init__.py
@@ -1,6 +1,6 @@
 """sktime."""
 
-__version__ = "0.27.1"
+__version__ = "0.28.0"
 
 __all__ = ["show_versions"]
 
diff --git a/sktime/classification/early_classification/_probability_threshold.py b/sktime/classification/early_classification/_probability_threshold.py
index 3b8497cb4..72fc3d853 100644
--- a/sktime/classification/early_classification/_probability_threshold.py
+++ b/sktime/classification/early_classification/_probability_threshold.py
@@ -20,7 +20,7 @@ from sktime.classification.interval_based import CanonicalIntervalForest
 from sktime.utils.validation.panel import check_X
 
 
-# TODO: fix this in 0.28.0
+# TODO: fix this in 0.29.0
 # base class should have been changed to BaseEarlyClassifier
 class ProbabilityThresholdEarlyClassifier(BaseClassifier):
     """Probability Threshold Early Classifier.
diff --git a/sktime/forecasting/base/_fh.py b/sktime/forecasting/base/_fh.py
index e10b2761b..2576b2a9d 100644
--- a/sktime/forecasting/base/_fh.py
+++ b/sktime/forecasting/base/_fh.py
@@ -816,7 +816,7 @@ def _to_relative(fh: ForecastingHorizon, cutoff=None) -> ForecastingHorizon:
             absolute = _coerce_to_period(absolute, freq=fh.freq)
             cutoff = _coerce_to_period(cutoff, freq=fh.freq)
 
-        # TODO: 0.28.0:
+        # TODO: 0.29.0:
         # Check at every minor release whether lower pandas bound >=0.15.0
         # if yes, can remove the workaround in the "else" condition and the check
         #
diff --git a/sktime/forecasting/compose/_pipeline.py b/sktime/forecasting/compose/_pipeline.py
index 36bb5be50..dae89630e 100644
--- a/sktime/forecasting/compose/_pipeline.py
+++ b/sktime/forecasting/compose/_pipeline.py
@@ -160,7 +160,7 @@ class _Pipeline(_HeterogenousMetaEstimator, BaseForecaster):
                         if len(levels) == 1:
                             levels = levels[0]
                         yt[ix] = y.xs(ix, level=levels, axis=1)
-                        # todo 0.28.0 - check why this cannot be easily removed
+                        # todo 0.29.0 - check why this cannot be easily removed
                         # in theory, we should get rid of the "Coverage" case treatment
                         # (the legacy naming convention was removed in 0.23.0)
                         # deal with the "Coverage" case, we need to get rid of this
diff --git a/sktime/forecasting/model_selection/__init__.py b/sktime/forecasting/model_selection/__init__.py
index 0b5ab0e59..318a27761 100644
--- a/sktime/forecasting/model_selection/__init__.py
+++ b/sktime/forecasting/model_selection/__init__.py
@@ -18,7 +18,7 @@ from sktime.forecasting.model_selection._tune import (
 )
 
 
-# todo 0.28.0 - check whether we should remove, otherwise bump
+# todo 0.29.0 - check whether we should remove, otherwise bump
 # still used in blog posts and old tutorials
 def temporal_train_test_split(
     y, X=None, test_size=None, train_size=None, fh=None, anchor="start"
@@ -45,7 +45,7 @@ def temporal_train_test_split(
     )
 
 
-# todo 0.28.0 - check whether we should remove, otherwise bump
+# todo 0.29.0 - check whether we should remove, otherwise bump
 # still used in blog posts and old tutorials
 def ExpandingWindowSplitter(fh=1, initial_window=10, step_length=1):
     """Legacy export of Expanding window splitter.
@@ -68,7 +68,7 @@ def ExpandingWindowSplitter(fh=1, initial_window=10, step_length=1):
     return _EWSplitter(fh=fh, initial_window=initial_window, step_length=step_length)
 
 
-# todo 0.28.0 - check whether we should remove, otherwise bump
+# todo 0.29.0 - check whether we should remove, otherwise bump
 # still used in blog posts and old tutorials
 def SlidingWindowSplitter(
     fh=1, window_length=10, step_length=1, initial_window=None, start_with_window=True
diff --git a/sktime/forecasting/model_selection/_tune.py b/sktime/forecasting/model_selection/_tune.py
index a7afe38c0..05c76c59a 100644
--- a/sktime/forecasting/model_selection/_tune.py
+++ b/sktime/forecasting/model_selection/_tune.py
@@ -84,7 +84,7 @@ class BaseGridSearch(_DelegatedForecaster):
         if tune_by_variable:
             self.set_tags(**{"scitype:y": "univariate"})
 
-        # todo 0.28.0: check if this is still necessary
+        # todo 0.29.0: check if this is still necessary
         # n_jobs is deprecated, left due to use in tutorials, books, blog posts
         if n_jobs != "deprecated":
             warn(
diff --git a/sktime/forecasting/trend/_pwl_trend_forecaster.py b/sktime/forecasting/trend/_pwl_trend_forecaster.py
index 12d67589e..94e3695cb 100644
--- a/sktime/forecasting/trend/_pwl_trend_forecaster.py
+++ b/sktime/forecasting/trend/_pwl_trend_forecaster.py
@@ -8,7 +8,6 @@ import pandas as pd
 
 from sktime.forecasting.base._base import DEFAULT_ALPHA
 from sktime.forecasting.base.adapters import _ProphetAdapter
-from sktime.utils.warnings import warn
 
 
 class ProphetPiecewiseLinearTrendForecaster(_ProphetAdapter):
@@ -52,15 +51,15 @@ class ProphetPiecewiseLinearTrendForecaster(_ProphetAdapter):
         automatic changepoint selection. Large values will allow many
         changepoints, small values will allow few changepoints.
         Recommended to take values within [0.001,0.5].
-    yearly_seasonality: str or bool or int, default="auto"
+    yearly_seasonality: str or bool or int, default=False
         Include yearly seasonality in the model. "auto" for automatic determination,
         True to enable, False to disable, or an integer specifying the number of terms
         to include in the Fourier series.
-    weekly_seasonality: str or bool or int, default="auto"
+    weekly_seasonality: str or bool or int, default=False
         Include weekly seasonality in the model. "auto" for automatic determination,
         True to enable, False to disable, or an integer specifying the number of terms
         to include in the Fourier series.
-    daily_seasonality: str or bool or int, default="auto"
+    daily_seasonality: str or bool or int, default=False
         Include weekly seasonality in the model. "auto" for automatic determination,
         True to enable, False to disable, or an integer specifying the number of terms
         to include in the Fourier series.
@@ -95,10 +94,6 @@ class ProphetPiecewiseLinearTrendForecaster(_ProphetAdapter):
         "python_dependencies": "prophet",
     }
 
-    # TODO (release 0.28.0) - change defaults to False
-    # set yearly_seasonality = False in __init__
-    # set weekly_seasonality = False in __init__
-    # set daily_seasonality = False in __init__
     def __init__(
         self,
         changepoints=None,
@@ -106,9 +101,9 @@ class ProphetPiecewiseLinearTrendForecaster(_ProphetAdapter):
         changepoint_range=0.8,
         changepoint_prior_scale=0.05,
         verbose=0,
-        yearly_seasonality="changing_value",
-        weekly_seasonality="changing_value",
-        daily_seasonality="changing_value",
+        yearly_seasonality=False,
+        weekly_seasonality=False,
+        daily_seasonality=False,
     ):
         self.freq = None
         self.add_seasonality = None
@@ -134,43 +129,6 @@ class ProphetPiecewiseLinearTrendForecaster(_ProphetAdapter):
         self.verbose = verbose
 
         super().__init__()
-        # TODO (release 0.28.0)
-        # remove the following 4 'if' checks
-        # set yearly_seasonality=self.yearly_seasonality in def _instantiate_model
-        # set weekly_seasonality=self.weekly_seasonality in def _instantiate_model
-        # set daily_seasonality=self.daily_seasonality in def _instantiate_model
-        if any(
-            setting == "changing_value"
-            for setting in [
-                yearly_seasonality,
-                weekly_seasonality,
-                daily_seasonality,
-            ]
-        ):
-            warn(
-                "Warning: In sktime 0.28.0, the default value for all seasonality "
-                "parameters in ProphetPiecewiseLinearTrendForecaster will change from "
-                "'auto' to 'False'. To retain the prior behavior, set all seasonality "
-                "parameters to 'auto' explicitly.",
-                category=DeprecationWarning,
-                stacklevel=3,
-            )
-
-        if yearly_seasonality == "changing_value":
-            self._yearly_seasonality = "auto"
-        else:
-            self._yearly_seasonality = yearly_seasonality
-
-        if weekly_seasonality == "changing_value":
-            self._weekly_seasonality = "auto"
-        else:
-            self._weekly_seasonality = weekly_seasonality
-
-        if daily_seasonality == "changing_value":
-            self._daily_seasonality = "auto"
-        else:
-            self._daily_seasonality = daily_seasonality
-        # end of TODO (release 0.28.0)
 
         # import inside method to avoid hard dependency
         from prophet.forecaster import Prophet as _Prophet
@@ -183,9 +141,9 @@ class ProphetPiecewiseLinearTrendForecaster(_ProphetAdapter):
             changepoints=self.changepoints,
             n_changepoints=self.n_changepoints,
             changepoint_range=self.changepoint_range,
-            yearly_seasonality=self._yearly_seasonality,  # TODO (release 0.28.0)
-            weekly_seasonality=self._weekly_seasonality,  # TODO (release 0.28.0)
-            daily_seasonality=self._daily_seasonality,  # TODO (release 0.28.0)
+            yearly_seasonality=self.yearly_seasonality,
+            weekly_seasonality=self.weekly_seasonality,
+            daily_seasonality=self.daily_seasonality,
             holidays=self.holidays,
             seasonality_mode=self.seasonality_mode,
             seasonality_prior_scale=float(self.seasonality_prior_scale),
diff --git a/sktime/transformations/bootstrap/_tsbootstrap.py b/sktime/transformations/bootstrap/_tsbootstrap.py
index 695a57b9a..af3d2fb07 100644
--- a/sktime/transformations/bootstrap/_tsbootstrap.py
+++ b/sktime/transformations/bootstrap/_tsbootstrap.py
@@ -119,16 +119,18 @@ class TSBootstrapAdapter(BaseTransformer):
         from sktime.utils.validation._dependencies import _check_soft_dependencies
 
         deps = cls.get_class_tag("python_dependencies")
-        _check_soft_dependencies(deps, severity="error")
 
-        from tsbootstrap import BlockBootstrap, MovingBlockBootstrap
+        if _check_soft_dependencies(deps, severity="none"):
+            from tsbootstrap import BlockBootstrap, MovingBlockBootstrap
 
-        params = [
-            {"bootstrap": BlockBootstrap(n_bootstraps=10)},
-            {
-                "bootstrap": MovingBlockBootstrap(n_bootstraps=10, block_length=4),
-                "include_actual": True,
-            },
-        ]
+            params = [
+                {"bootstrap": BlockBootstrap(n_bootstraps=10)},
+                {
+                    "bootstrap": MovingBlockBootstrap(n_bootstraps=10, block_length=4),
+                    "include_actual": True,
+                },
+            ]
+        else:
+            params = {"bootstrap": "dummy"}
 
         return params
diff --git a/sktime/transformations/panel/catch22wrapper.py b/sktime/transformations/panel/catch22wrapper.py
index 975fa2748..c71a03721 100644
--- a/sktime/transformations/panel/catch22wrapper.py
+++ b/sktime/transformations/panel/catch22wrapper.py
@@ -11,7 +11,6 @@ import pandas as pd
 
 from sktime.transformations.base import BaseTransformer
 from sktime.transformations.panel import catch22
-from sktime.utils.warnings import warn
 
 
 class Catch22Wrapper(BaseTransformer):
@@ -89,21 +88,18 @@ class Catch22Wrapper(BaseTransformer):
         "fit_is_empty": True,
     }
 
-    # todo 0.28.0: remove n_jobs parameter
     def __init__(
         self,
         features="all",
         catch24=False,
         outlier_norm=False,
         replace_nans=False,
-        n_jobs="deprecated",
         col_names="range",
     ):
         self.features = features
         self.catch24 = catch24
         self.outlier_norm = outlier_norm
         self.replace_nans = replace_nans
-        self.n_jobs = n_jobs
         self.col_names = col_names
 
         self.features_arguments = (
@@ -130,19 +126,6 @@ class Catch22Wrapper(BaseTransformer):
 
         super().__init__()
 
-        # todo 0.28.0: remove this warning and logic
-        if n_jobs != "deprecated":
-            warn(
-                "In Catch22Wrapper, the parameter "
-                "n_jobs is deprecated and will be removed in v0.28.0. "
-                "Instead, use set_config with the backend and backend:params "
-                "config fields, and set backend to 'joblib' and pass n_jobs "
-                "as a parameter of backend_params. ",
-                FutureWarning,
-                obj=self,
-            )
-            self.set_config(backend="joblib", backend_params={"n_jobs": n_jobs})
-
     def _transform(self, X, y=None):
         """Transform data into the Catch22 features.
 
diff --git a/sktime/transformations/panel/dictionary_based/__init__.py b/sktime/transformations/panel/dictionary_based/__init__.py
index 8e3b9c56d..a49a704e4 100644
--- a/sktime/transformations/panel/dictionary_based/__init__.py
+++ b/sktime/transformations/panel/dictionary_based/__init__.py
@@ -1,10 +1,8 @@
 """Transformers."""
 
-# TODO 0.28.0 - remove exports of PAA, SAX
-__all__ = ["PAA", "SFA", "SFAFast", "SAX", "PAAlegacy", "SAXlegacy"]
+__all__ = ["SFA", "SFAFast", "PAAlegacy", "SAXlegacy"]
 
-# TODO 0.28.0 - remove exports of PAA, SAX
-from sktime.transformations.panel.dictionary_based._paa import PAA, PAAlegacy
-from sktime.transformations.panel.dictionary_based._sax import SAX, SAXlegacy
+from sktime.transformations.panel.dictionary_based._paa import PAAlegacy
+from sktime.transformations.panel.dictionary_based._sax import SAXlegacy
 from sktime.transformations.panel.dictionary_based._sfa import SFA
 from sktime.transformations.panel.dictionary_based._sfa_fast import SFAFast
diff --git a/sktime/transformations/panel/dictionary_based/_paa.py b/sktime/transformations/panel/dictionary_based/_paa.py
index 020a66b93..db137cff7 100644
--- a/sktime/transformations/panel/dictionary_based/_paa.py
+++ b/sktime/transformations/panel/dictionary_based/_paa.py
@@ -3,7 +3,6 @@ import pandas as pd
 
 from sktime.datatypes._panel._convert import from_nested_to_2d_array
 from sktime.transformations.base import BaseTransformer
-from sktime.utils.warnings import warn
 
 __author__ = ["MatthewMiddlehurst"]
 
@@ -44,24 +43,6 @@ class PAAlegacy(BaseTransformer):
         self.num_intervals = num_intervals
         super().__init__()
 
-        # todo 0.28.0: remove this warning
-        warn(
-            "panel.dictionary_based.PAA has been renamed to PAAlegacy in sktime 0.27.0,"
-            " while sktime.transformations.series.PAA2 was renamed to PAA. "
-            "PAA2 will become the primary PAA implementation in sktime, "
-            "while the former PAA will continue to be available as PAAlegacy. "
-            "Both estimators are also available under their future name at their "
-            "current location, and will be available under their deprecated name "
-            "until 0.28.0. "
-            "To prepare for the name change, do one of the following: "
-            "1. replace use of PAA2 from sktime.transformations.panel.dictionary_based "
-            "by use of PAA from sktime.transformations.series.paa, or "
-            "2. replace use of PAA from sktime.transformations.panel.dictionary_based "
-            "by use of PAAlegacy from sktime.transformations.panel.dictionary_based. ",
-            DeprecationWarning,
-            obj=self,
-        )
-
     def set_num_intervals(self, n):
         """Set self.num_intervals to n."""
         self.num_intervals = n
@@ -171,7 +152,3 @@ class PAAlegacy(BaseTransformer):
                 + type(self.num_intervals).__name__
                 + "' instead."
             )
-
-
-# TODO 0.28.0: remove this alias altogether
-PAA = PAAlegacy
diff --git a/sktime/transformations/panel/dictionary_based/_sax.py b/sktime/transformations/panel/dictionary_based/_sax.py
index c64d7367b..716036cf7 100644
--- a/sktime/transformations/panel/dictionary_based/_sax.py
+++ b/sktime/transformations/panel/dictionary_based/_sax.py
@@ -8,7 +8,6 @@ import scipy.stats
 
 from sktime.transformations.base import BaseTransformer
 from sktime.transformations.panel.dictionary_based import PAAlegacy as PAA
-from sktime.utils.warnings import warn
 
 __author__ = ["MatthewMiddlehurst"]
 
@@ -86,24 +85,6 @@ class SAXlegacy(BaseTransformer):
 
         super().__init__()
 
-        # todo 0.28.0: remove this warning
-        warn(
-            "panel.dictionary_based.SAX has been renamed to SAXlegacy in sktime 0.27.0,"
-            " while sktime.transformations.series.SAX2 was renamed to SAX. "
-            "SAX2 will become the primary SAX implementation in sktime, "
-            "while the former SAX will continue to be available as SAXlegacy. "
-            "Both estimators are also available under their future name at their "
-            "current location, and will be available under their deprecated name "
-            "until 0.28.0. "
-            "To prepare for the name change, do one of the following: "
-            "1. replace use of SAX2 from sktime.transformations.panel.dictionary_based "
-            "by use of SAX from sktime.transformations.series.sax, or "
-            "2. replace use of SAX from sktime.transformations.panel.dictionary_based "
-            "by use of SAXlegacy from sktime.transformations.panel.dictionary_based. ",
-            DeprecationWarning,
-            obj=self,
-        )
-
         self.set_config(**{"output_conversion": "off"})
 
     # todo: looks like this just loops over series instances
@@ -235,7 +216,3 @@ class SAXlegacy(BaseTransformer):
         # small word length, window size for testing
         params = {"word_length": 2, "window_size": 4}
         return params
-
-
-# TODO 0.28.0: remove this alias altogether
-SAX = SAXlegacy
diff --git a/sktime/transformations/series/paa.py b/sktime/transformations/series/paa.py
index cb189fe72..db6cb6079 100644
--- a/sktime/transformations/series/paa.py
+++ b/sktime/transformations/series/paa.py
@@ -5,7 +5,6 @@ __author__ = ["steenrotsman"]
 import numpy as np
 
 from sktime.transformations.base import BaseTransformer
-from sktime.utils.warnings import warn
 
 
 class PAA(BaseTransformer):
@@ -38,13 +37,13 @@ class PAA(BaseTransformer):
     Examples
     --------
     >>> from numpy import arange
-    >>> from sktime.transformations.series.paa import PAA2
+    >>> from sktime.transformations.series.paa import PAA
 
     >>> X = arange(10)
-    >>> paa = PAA2(frames=3)
+    >>> paa = PAA(frames=3)
     >>> paa.fit_transform(X)  # doctest: +SKIP
     array([1.2, 4.5, 7.8])
-    >>> paa = PAA2(frame_size=3)  # doctest: +SKIP
+    >>> paa = PAA(frame_size=3)  # doctest: +SKIP
     array([1, 4, 7, 9])
     """
 
@@ -70,20 +69,6 @@ class PAA(BaseTransformer):
 
         super().__init__()
 
-        # TODO 0.28.0: remove the deprecation warning
-        warn(
-            "Since sktime 0.27.0, PAA2 is the primary PAA implementation in "
-            "sktime, and has been renamed to PAA. "
-            "PAA2 is available under both its current and future name at its "
-            "current location, imports under the deprecated name PAA2 will be possible"
-            "until 0.28.0. "
-            "To prepare for the name change, replace imports of PAA2 from "
-            "sktime.transformations.series.paa by imports of PAA from the same "
-            "module.",
-            DeprecationWarning,
-            obj=self,
-        )
-
         self._check_params()
 
     def _transform(self, X, y=None):
@@ -167,7 +152,3 @@ class PAA(BaseTransformer):
 
         if self.frames < 1 and not self.frame_size:
             raise ValueError("frames must be at least 1.")
-
-
-# TODO 0.28.0: remove the alias line altogether
-PAA2 = PAA
diff --git a/sktime/transformations/series/sax.py b/sktime/transformations/series/sax.py
index 8e71c3a41..30968dd85 100644
--- a/sktime/transformations/series/sax.py
+++ b/sktime/transformations/series/sax.py
@@ -5,7 +5,6 @@ from scipy.stats import norm, zscore
 
 from sktime.transformations.base import BaseTransformer
 from sktime.transformations.series.paa import PAA
-from sktime.utils.warnings import warn
 
 
 class SAX(BaseTransformer):
@@ -47,13 +46,13 @@ class SAX(BaseTransformer):
     Examples
     --------
     >>> from numpy import arange
-    >>> from sktime.transformations.series.sax import SAX2
+    >>> from sktime.transformations.series.sax import SAX
 
     >>> X = arange(10)
-    >>> sax = SAX2(word_size=3, alphabet_size=5)
+    >>> sax = SAX(word_size=3, alphabet_size=5)
     >>> sax.fit_transform(X)  # doctest: +SKIP
     array([0, 2, 4])
-    >>> sax = SAX2(frame_size=2, alphabet_size=5)  # doctest: +SKIP
+    >>> sax = SAX(frame_size=2, alphabet_size=5)  # doctest: +SKIP
     array([0, 1, 2, 3, 4])
     """
 
@@ -80,19 +79,6 @@ class SAX(BaseTransformer):
 
         super().__init__()
 
-        warn(
-            "Since sktime 0.27.0, SAX2 is the primary SAX implementation in "
-            "sktime, and has been renamed to SAX. "
-            "SAX2 is available under both its current and future name at its "
-            "current location, imports under the deprecated name SAX2 will be possible"
-            "until 0.28.0. "
-            "To prepare for the name change, replace imports of SAX2 from "
-            "sktime.transformations.series.sax by imports of SAX from the same "
-            "module.",
-            DeprecationWarning,
-            obj=self,
-        )
-
         self._check_params()
 
     def _transform(self, X, y=None):
@@ -156,7 +142,3 @@ class SAX(BaseTransformer):
             raise ValueError("alphabet_size must be at least 2.")
         if self.frame_size < 0:
             raise ValueError("frame_size must be at least 0.")
-
-
-# TODO 0.28.0: remove the alias line altogether
-SAX2 = SAX
diff --git a/sktime/utils/deep_equals/__init__.py b/sktime/utils/deep_equals/__init__.py
index 25c52a96b..2449f4a4b 100644
--- a/sktime/utils/deep_equals/__init__.py
+++ b/sktime/utils/deep_equals/__init__.py
@@ -2,7 +2,7 @@
 """Module for nested equality checking."""
 from sktime.utils.validation._dependencies import _check_soft_dependencies
 
-# todo 0.28.0: check whether scikit-base>=0.6.1 lower bound is 0.6.1 or higher
+# todo 0.29.0: check whether scikit-base>=0.6.1 lower bound is 0.6.1 or higher
 # if yes, remove legacy handling and only use the new deep_equals
 if _check_soft_dependencies(
     "scikit-base<0.6.1",


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 359f6e569..02a099845 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -27,7 +27,7 @@ jobs:
         run: python3 -m pip install pre-commit
       - id: changed-files
         name: identify modified files
-        uses: tj-actions/changed-files@v43
+        uses: tj-actions/changed-files@v44
       - name: run pre-commit hooks on modified files
         run: pre-commit run --color always --files ${{ steps.changed-files.outputs.all_changed_files }} --show-diff-on-failure
       - name: check missing __init__ files
diff --git a/sktime/forecasting/trend/tests/test_pwl_trend.py b/sktime/forecasting/trend/tests/test_pwl_trend.py
index 01275098c..6c1947fd0 100644
--- a/sktime/forecasting/trend/tests/test_pwl_trend.py
+++ b/sktime/forecasting/trend/tests/test_pwl_trend.py
@@ -97,8 +97,15 @@ def test_pred_with_explicit_changepoints():
     y_train, y_test = temporal_train_test_split(y)
 
     fh = ForecastingHorizon(y_test.index, is_relative=False)
-    a = ProphetPiecewiseLinearTrendForecaster(changepoints=["1953-05-31"])
-    b = ProphetPiecewiseLinearTrendForecaster()
+    seasonality_params = {
+        "yearly_seasonality": True,
+        "weekly_seasonality": True,
+        "daily_seasonality": True,
+    }
+    a = ProphetPiecewiseLinearTrendForecaster(
+        changepoints=["1953-05-31"], **seasonality_params
+    )
+    b = ProphetPiecewiseLinearTrendForecaster(**seasonality_params)
 
     slope_a = a.fit(y_train).predict(fh).diff().mean()
     slope_b = b.fit(y_train).predict(fh).diff().mean()
diff --git a/sktime/tests/test_softdeps.py b/sktime/tests/test_softdeps.py
index 39f0e4bac..e35468df4 100644
--- a/sktime/tests/test_softdeps.py
+++ b/sktime/tests/test_softdeps.py
@@ -47,17 +47,6 @@ MODULES_TO_IGNORE = ("sktime._contrib", "sktime.utils._testing")
 EXCEPTED_FROM_NO_DEP_CHECK = []
 
 
-# estimators excepted from checking that get_test_params does not import soft deps
-# this is ok, in general, for adapters to soft dependency frameworks
-# since such adapters will import estimators from the adapted framework
-EXCEPTED_FROM_GET_PARAMS_CHECK = [
-    "PyODAnnotator",  # adapters always require soft dep. Here: pyod
-    "HCrystalBallAdapter",  # adapters always require soft dep. Here: hcrystalball
-    "TSBootstrapAdapter",  # adapters always require soft dep. Here: tsbootstrap
-    "TemporianTransformer",  # adapters always require soft dep. Here: temporian
-]
-
-
 def _is_test(module):
     module_parts = module.split(".")
     return any(part in ("tests", "test") for part in module_parts)
@@ -271,9 +260,6 @@ def test_est_construct_if_softdep_available(estimator):
 @pytest.mark.parametrize("estimator", all_ests)
 def test_est_get_params_without_modulenotfound(estimator):
     """Test that estimator test parameters do not rely on soft dependencies."""
-    if estimator.__name__ in EXCEPTED_FROM_GET_PARAMS_CHECK:
-        return None
-
     try:
         estimator.get_test_params()
     except ModuleNotFoundError as e:
@@ -282,6 +268,10 @@ def test_est_get_params_without_modulenotfound(estimator):
             f"Estimator {estimator.__name__} requires soft dependencies for parameters "
             f"returned by get_test_params. Test parameters should not require "
             f"soft dependencies and use only sktime internal objects. "
+            f"In a case where soft dependencies are required, return a shorter list, "
+            f"or an empty dict, with parameter sets that do not require soft "
+            f"dependencies, gated by a dependency check, for instance using "
+            f"skbase.utils.dependencies_check_soft_dependencies with severity='none'. "
             f"Exception text: {error_msg}"
         ) from e
 
diff --git a/sktime/transformations/series/tests/test_paa.py b/sktime/transformations/series/tests/test_paa.py
index 4acf1b13d..8d1338507 100644
--- a/sktime/transformations/series/tests/test_paa.py
+++ b/sktime/transformations/series/tests/test_paa.py
@@ -2,7 +2,7 @@
 import numpy as np
 import pytest
 
-from sktime.transformations.series.paa import PAA2
+from sktime.transformations.series.paa import PAA
 
 
 # Check that exception is raised for bad frames values.
@@ -16,10 +16,10 @@ def test_bad_input_args(bad_frames):
     if not isinstance(bad_frames, int):
         for attribute in ["frames", "frame_size"]:
             with pytest.raises(TypeError):
-                PAA2(**{attribute: bad_frames}).fit(X).transform(X)
+                PAA(**{attribute: bad_frames}).fit(X).transform(X)
     else:
         with pytest.raises(ValueError):
-            PAA2(bad_frames).fit(X).transform(X)
+            PAA(bad_frames).fit(X).transform(X)
 
 
 @pytest.mark.parametrize(
@@ -38,7 +38,7 @@ def test_bad_input_args(bad_frames):
 def test_output_of_transformer(frames, frame_size, expected):
     """Test that the transformer has changed the data correctly."""
     X = np.arange(10).T
-    paa = PAA2(frames, frame_size)
+    paa = PAA(frames, frame_size)
     res = paa.fit_transform(X)
     want = np.array(expected, dtype=np.float64).T
     np.testing.assert_array_equal(res, want)
diff --git a/sktime/transformations/series/tests/test_sax.py b/sktime/transformations/series/tests/test_sax.py
index ca122c932..116e7d293 100644
--- a/sktime/transformations/series/tests/test_sax.py
+++ b/sktime/transformations/series/tests/test_sax.py
@@ -2,7 +2,7 @@
 import numpy as np
 import pytest
 
-from sktime.transformations.series.sax import SAX2
+from sktime.transformations.series.sax import SAX
 
 
 # Check that exception is raised for bad size values.
@@ -13,7 +13,7 @@ def test_bad_input_types(bad_size):
     """Test that exception is raised for bad sizes."""
     for attribute in ["word_size", "alphabet_size", "frame_size"]:
         with pytest.raises(TypeError):
-            SAX2(**{attribute: bad_size})
+            SAX(**{attribute: bad_size})
 
 
 @pytest.mark.parametrize(
@@ -27,7 +27,7 @@ def test_bad_input_types(bad_size):
 def test_bad_input_values(attribute, bad_size):
     """Test that word_size is at least 1 (if frame_size is not set)."""
     with pytest.raises(ValueError):
-        SAX2(**{attribute: bad_size})
+        SAX(**{attribute: bad_size})
 
 
 @pytest.mark.parametrize(
@@ -42,7 +42,7 @@ def test_bad_input_values(attribute, bad_size):
 def test_output_of_transformer(word_size, alphabet_size, frame_size, expected):
     """Test that the transformer has changed the data correctly."""
     X = np.arange(10).T
-    sax = SAX2(word_size, alphabet_size, frame_size)
+    sax = SAX(word_size, alphabet_size, frame_size)
     res = sax.fit_transform(X)
     want = np.array(expected, dtype=np.float64).T
     np.testing.assert_array_equal(res, want)
diff --git a/sktime/utils/_testing/deep_equals.py b/sktime/utils/_testing/deep_equals.py
index 131ad09f4..4ccf000ad 100644
--- a/sktime/utils/_testing/deep_equals.py
+++ b/sktime/utils/_testing/deep_equals.py
@@ -16,7 +16,7 @@ import numpy as np
 import pandas as pd
 
 
-# todo 0.28.0: check whether scikit-base>=0.6.1 lower bound is 0.6.1 or higher
+# todo 0.29.0: check whether scikit-base>=0.6.1 lower bound is 0.6.1 or higher
 # if yes, remove this legacy function and use the new one from sktime.utils.deep_equals
 def deep_equals(x, y, return_msg=False):
     """Test two objects for equality in value.