Repository: aeon-toolkit/aeon (python)

Issue:
[MNT] Use MacOS for `examples/` workflow
### Describe the issue

MacOS is generally faster for our CI, we should try running our examples workflow using it and see if there is a speed up.

### Suggest a potential alternative/fix

Swap over to MacOS runners in the example CI. Evaluate whether this is faster than the current Linux runner.

### Additional context

See https://github.com/aeon-toolkit/aeon/pull/2390, these are the three files that will have to change (at least)

Pull request description:
[MNT] Use MacOS for examples/ workflow
<!--
Thanks for contributing a pull request! Please ensure you have taken a look at our
contribution guide: https://www.aeon-toolkit.org/en/latest/contributing.html.

Feel free to delete sections of this template if they do not apply to your PR,
avoid submitting a blank template or empty sections.
If you are a new contributor, do not delete this template without a suitable
replacement or reason. If in doubt, ask for help. We're here to help!

Please be aware that we are a team of volunteers so patience is
necessary when waiting for a review or reply. There may not be a quick turnaround for
reviews during slow periods. While we value all contributions big or small, pull
requests which do not follow our guidelines may be closed.
-->

#### Reference Issues/PRs
Fixes #2665
<!--
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
-->

#### What does this implement/fix? Explain your changes.
- Changed the os in the workflows for `pr_examples` and `periodic_tests` to `macos-latest`.
- Changed the workflow to install `bash 5.x` before running `run_examples.sh`
as lastpipe isnt available in `bash 3.2` which is in the github runner image for `macos-latest` (https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md).
- Also added a step to install `boost` and `esig` before the `run_examples.sh` as `esig` is not installed on Darwin since its excluded in `pyproject.toml`.


<!--
A clear and concise description of what you have implemented.
-->

#### Does your contribution introduce a new dependency? If yes, which one?
No
<!--
If your contribution does add a dependency, we may suggest adding it as an
optional/soft dependency to keep external dependencies of the core aeon package
to a minimum.
-->

#### Any other comments?

<!--
Any other information that is important to this PR or helpful for reviewers.
-->

### PR checklist

<!--
Please go through the checklist below. Please feel free to remove points if they are
not applicable. To check a box, replace the space inside the square brackets with an
'x' i.e. [x].
-->

##### For all contributions
- [x] I've added myself to the [list of contributors](https://github.com/aeon-toolkit/aeon/blob/main/.all-contributorsrc). Alternatively, you can use the [@all-contributors](https://allcontributors.org/docs/en/bot/usage) bot to do this for you after the PR has been merged.
- [x] The PR title starts with either [ENH], [MNT], [DOC], [BUG], [REF], [DEP] or [GOV] indicating whether the PR topic is related to enhancement, maintenance, documentation, bugs, refactoring, deprecation or governance.

##### For new estimators and functions
- [ ] I've added the estimator/function to the online [API documentation](https://www.aeon-toolkit.org/en/latest/api_reference.html).
- [ ] (OPTIONAL) I've added myself as a `__maintainer__` at the top of relevant files and want to be contacted regarding its maintenance. Unmaintained files may be removed. This is for the full file, and you should not add yourself if you are just making minor changes or do not want to help maintain its contents.

##### For developers with write access
- [ ] (OPTIONAL) I've updated aeon's [CODEOWNERS](https://github.com/aeon-toolkit/aeon/blob/main/CODEOWNERS) to receive notifications about future changes to these files.


<!--
Thanks for contributing!
-->


Patch:
diff --git a/.github/utilities/run_examples.sh b/.github/utilities/run_examples.sh
index fd7376c0..fdbcdb90 100755
--- a/.github/utilities/run_examples.sh
+++ b/.github/utilities/run_examples.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/opt/homebrew/bin/bash
 
 # Script to run all example notebooks.
 set -euxo pipefail
@@ -23,6 +23,7 @@ if [ "$1" = true ]; then
     "examples/classification/shapelet_based.ipynb"
     "examples/classification/convolution_based.ipynb"
     "examples/similarity_search/code_speed.ipynb"
+    "examples/transformations/signature_method.ipynb"
 
   )
 fi
@@ -32,7 +33,7 @@ notebooks=()
 runtimes=()
 
 # Loop over all notebooks in the examples directory.
-find "examples/" -name "*.ipynb" -print0 |
+find "examples" -name "*.ipynb" -print0 |
   while IFS= read -r -d "" notebook; do
     # Skip notebooks in the excluded list.
     if printf "%s\0" "${excluded[@]}" | grep -Fxqz -- "$notebook"; then
diff --git a/.github/workflows/pr_examples.yml b/.github/workflows/pr_examples.yml
index adc26631..2d7ea6f1 100644
--- a/.github/workflows/pr_examples.yml
+++ b/.github/workflows/pr_examples.yml
@@ -19,12 +19,17 @@ concurrency:
 
 jobs:
   run-notebook-examples:
-    runs-on: ubuntu-24.04
+    runs-on: macos-14
 
     steps:
       - name: Checkout
         uses: actions/checkout@v4
 
+      - name: Install latest version of bash
+        run: |
+          brew install bash
+          /opt/homebrew/bin/bash --version
+
       - name: Setup Python 3.10
         uses: actions/setup-python@v5
         with:
diff --git a/.github/workflows/pr_precommit.yml b/.github/workflows/pr_precommit.yml
index a74e8b12..809803fe 100644
--- a/.github/workflows/pr_precommit.yml
+++ b/.github/workflows/pr_precommit.yml
@@ -37,7 +37,7 @@ jobs:
           python-version: "3.10"
 
       - name: Get changed files
-        uses: tj-actions/changed-files@v46.0.1
+        uses: tj-actions/changed-files@v46.0.3
         id: changed-files
 
       - name: List changed files
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 854da8df..b09f5f22 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -29,7 +29,7 @@ repos:
         args: [ "--create", "--python-folders", "aeon" ]
 
   - repo: https://github.com/astral-sh/ruff-pre-commit
-    rev: v0.11.0
+    rev: v0.11.2
     hooks:
       - id: ruff
         args: [ "--fix"]
diff --git a/aeon/classification/feature_based/_catch22.py b/aeon/classification/feature_based/_catch22.py
index bec5deff..26a56d0a 100644
--- a/aeon/classification/feature_based/_catch22.py
+++ b/aeon/classification/feature_based/_catch22.py
@@ -43,8 +43,11 @@ class Catch22Classifier(BaseClassifier):
         true. If a List of specific features to extract is provided, "Mean" and/or
         "StandardDeviation" must be added to the List to extract these features.
     outlier_norm : bool, optional, default=False
-        Normalise each series during the two outlier Catch22 features, which can take a
-        while to process for large values.
+        If True, each time series is normalized during the computation of the two
+        outlier Catch22 features, which can take a while to process for large values
+        as it depends on the max value in the timseries. Note that this parameter
+        did not exist in the original publication/implementation as they used time
+        series that were already normalized.
     replace_nans : bool, default=True
         Replace NaN or inf values from the Catch22 transform with 0.
     use_pycatch22 : bool, default=False
@@ -136,7 +139,7 @@ class Catch22Classifier(BaseClassifier):
         self,
         features="all",
         catch24=True,
-        outlier_norm=False,
+        outlier_norm=True,
         replace_nans=True,
         use_pycatch22=False,
         estimator=None,
diff --git a/aeon/clustering/feature_based/_catch22.py b/aeon/clustering/feature_based/_catch22.py
index 33f0b79b..30fad7ff 100644
--- a/aeon/clustering/feature_based/_catch22.py
+++ b/aeon/clustering/feature_based/_catch22.py
@@ -42,9 +42,12 @@ class Catch22Clusterer(BaseClusterer):
         Extract the mean and standard deviation as well as the 22 Catch22 features if
         true. If a List of specific features to extract is provided, "Mean" and/or
         "StandardDeviation" must be added to the List to extract these features.
-    outlier_norm : bool, optional, default=False
-        Normalise each series during the two outlier Catch22 features, which can take a
-        while to process for large values.
+        outlier_norm : bool, optional, default=False
+            If True, each time series is normalized during the computation of the two
+            outlier Catch22 features, which can take a while to process for large values
+            as it depends on the max value in the timseries. Note that this parameter
+            did not exist in the original publication/implementation as they used
+            time series that were already normalized.
     replace_nans : bool, default=True
         Replace NaN or inf values from the Catch22 transform with 0.
     use_pycatch22 : bool, default=False
@@ -103,7 +106,7 @@ class Catch22Clusterer(BaseClusterer):
         self,
         features="all",
         catch24=True,
-        outlier_norm=False,
+        outlier_norm=True,
         replace_nans=True,
         use_pycatch22=False,
         estimator=None,
diff --git a/aeon/regression/feature_based/_catch22.py b/aeon/regression/feature_based/_catch22.py
index f669cbe8..1ab04ee6 100644
--- a/aeon/regression/feature_based/_catch22.py
+++ b/aeon/regression/feature_based/_catch22.py
@@ -43,8 +43,11 @@ class Catch22Regressor(BaseRegressor):
         True. If a List of specific features to extract is provided, "Mean" and/or
         "StandardDeviation" must be added to the List to extract these features.
     outlier_norm : bool, optional, default=False
-        Normalise each series during the two outlier Catch22 features, which can take a
-        while to process for large values.
+        If True, each time series is normalized during the computation of the two
+        outlier Catch22 features, which can take a while to process for large values
+        as it depends on the max value in the timseries. Note that this parameter
+        did not exist in the original publication/implementation as they used time
+        series that were already normalized.
     replace_nans : bool, optional, default=True
         Replace NaN or inf values from the Catch22 transform with 0.
     use_pycatch22 : bool, optional, default=False
@@ -110,7 +113,7 @@ class Catch22Regressor(BaseRegressor):
         self,
         features="all",
         catch24=True,
-        outlier_norm=False,
+        outlier_norm=True,
         replace_nans=True,
         use_pycatch22=False,
         estimator=None,
diff --git a/aeon/transformations/collection/base.py b/aeon/transformations/collection/base.py
index 013001d8..a3664eb4 100644
--- a/aeon/transformations/collection/base.py
+++ b/aeon/transformations/collection/base.py
@@ -64,8 +64,8 @@ class BaseCollectionTransformer(BaseCollectionEstimator, BaseTransformer):
         X : np.ndarray or list
             Data to fit transform to, of valid collection type. Input data,
             any number of channels, equal length series of shape ``(
-            n_cases, n_channels, n_timepoints)`` or list of numpy arrays (any number
-            of channels, unequal length series) of shape ``[n_cases]``, 2D np.array
+            n_cases, n_channels, n_timepoints)`` or list of numpy arrays (number
+            of channels, series length) of shape ``[n_cases]``, 2D np.array
             ``(n_channels, n_timepoints_i)``, where ``n_timepoints_i`` is length of
             series ``i``. Other types are allowed and converted into one of the above.
 
@@ -118,8 +118,8 @@ class BaseCollectionTransformer(BaseCollectionEstimator, BaseTransformer):
         X : np.ndarray or list
             Data to fit transform to, of valid collection type. Input data,
             any number of channels, equal length series of shape ``(
-            n_cases, n_channels, n_timepoints)`` or list of numpy arrays (any number
-            of channels, unequal length series) of shape ``[n_cases]``, 2D np.array
+            n_cases, n_channels, n_timepoints)`` or list of numpy arrays (number
+            of channels, series length) of shape ``[n_cases]``, 2D np.array
             ``(n_channels, n_timepoints_i)``, where ``n_timepoints_i`` is length of
             series ``i``. Other types are allowed and converted into one of the above.
 
@@ -171,10 +171,10 @@ class BaseCollectionTransformer(BaseCollectionEstimator, BaseTransformer):
         ----------
         X : np.ndarray or list
             Data to fit transform to, of valid collection type. Input data,
-            any number of channels, equal length series of shape ``(n_cases,
-            n_channels, n_timepoints)`` or list of numpy arrays (any number of
-            channels, unequal length series) of shape ``[n_cases]``, 2D np.array ``(
-            n_channels, n_timepoints_i)``, where ``n_timepoints_i`` is length of
+            any number of channels, equal length series of shape ``(
+            n_cases, n_channels, n_timepoints)`` or list of numpy arrays (number
+            of channels, series length) of shape ``[n_cases]``, 2D np.array
+            ``(n_channels, n_timepoints_i)``, where ``n_timepoints_i`` is length of
             series ``i``. Other types are allowed and converted into one of the above.
 
             Different estimators have different capabilities to handle different
@@ -222,8 +222,8 @@ class BaseCollectionTransformer(BaseCollectionEstimator, BaseTransformer):
         X : np.ndarray or list
             Data to fit transform to, of valid collection type. Input data,
             any number of channels, equal length series of shape ``(
-            n_cases, n_channels, n_timepoints)`` or list of numpy arrays (any number
-            of channels, unequal length series)  of shape ``[n_cases]``, 2D np.array
+            n_cases, n_channels, n_timepoints)`` or list of numpy arrays (number
+            of channels, series length) of shape ``[n_cases]``, 2D np.array
             ``(n_channels, n_timepoints_i)``, where ``n_timepoints_i`` is length of
             series ``i``. Other types are allowed and converted into one of the above.
 
diff --git a/aeon/transformations/collection/feature_based/_catch22.py b/aeon/transformations/collection/feature_based/_catch22.py
index daae46f5..0431da8d 100644
--- a/aeon/transformations/collection/feature_based/_catch22.py
+++ b/aeon/transformations/collection/feature_based/_catch22.py
@@ -111,8 +111,11 @@ class Catch22(BaseCollectionTransformer):
         true. If a List of specific features to extract is provided, "Mean" and/or
         "StandardDeviation" must be added to the List to extract these features.
     outlier_norm : bool, optional, default=False
-        Normalise each series during the two outlier Catch22 features, which can take a
-        while to process for large values.
+        If True, each time series is normalized during the computation of the two
+        outlier Catch22 features, which can take a while to process for large values
+        as it depends on the max value in the timseries. Note that this parameter
+        did not exist in the original publication/implementation as they used time
+        series that were already normalized.
     replace_nans : bool, default=False
         Replace NaN or inf values from the Catch22 transform with 0.
     use_pycatch22 : bool, optional, default=False
@@ -163,7 +166,7 @@ class Catch22(BaseCollectionTransformer):
     [1.15639531e+00 1.31700577e+00 5.66227710e-01 2.00000000e+00
      3.89048349e-01 2.33853577e-01 1.00000000e+00 3.00000000e+00
      8.23045267e-03 0.00000000e+00 1.70859420e-01 2.00000000e+00
-     1.00000000e+00 2.00000000e-01 0.00000000e+00 1.10933565e-32
+     1.00000000e+00 7.00000000e-01 2.00000000e-01 1.10933565e-32
      4.00000000e+00 2.04319187e+00 0.00000000e+00 0.00000000e+00
      1.96349541e+00 5.51667002e-01]
     """
@@ -181,7 +184,7 @@ class Catch22(BaseCollectionTransformer):
         self,
         features="all",
         catch24=False,
-        outlier_norm=False,
+        outlier_norm=True,
         replace_nans=False,
         use_pycatch22=False,
         n_jobs=1,


Test patch:
diff --git a/.github/workflows/periodic_tests.yml b/.github/workflows/periodic_tests.yml
index 64e297d6..15289595 100644
--- a/.github/workflows/periodic_tests.yml
+++ b/.github/workflows/periodic_tests.yml
@@ -46,12 +46,17 @@ jobs:
           extra_args: --all-files
 
   run-notebook-examples:
-    runs-on: ubuntu-24.04
+    runs-on: macos-14
 
     steps:
       - name: Checkout
         uses: actions/checkout@v4
 
+      - name: Install latest version of bash
+        run: |
+          brew install bash
+          /opt/homebrew/bin/bash --version
+
       - name: Setup Python 3.10
         uses: actions/setup-python@v5
         with:
diff --git a/aeon/transformations/collection/feature_based/tests/test_catch22.py b/aeon/transformations/collection/feature_based/tests/test_catch22.py
index 5b5bc289..9ebc6786 100644
--- a/aeon/transformations/collection/feature_based/tests/test_catch22.py
+++ b/aeon/transformations/collection/feature_based/tests/test_catch22.py
@@ -120,7 +120,7 @@ catch22_basic_motions_data = np.array(
             0.0616,
             1.0,
             0.5,
-            -0.2,
+            -0.2799,
             0.04,
             0.4158,
             4.0,
@@ -231,7 +231,7 @@ catch22_basic_motions_data = np.array(
             2.0,
             1.0,
             -0.11,
-            -0.72,
+            -0.81,
             1.7181,
             8.0,
             1.8142,
@@ -255,7 +255,7 @@ catch22_basic_motions_data = np.array(
             4.0,
             0.3333,
             -0.15,
-            0.03,
+            0.01,
             32.285,
             8.0,
             1.9501,
@@ -298,8 +298,8 @@ catch22_basic_motions_data = np.array(
             0.1303,
             3.0,
             0.3333,
-            -0.23,
-            -0.04,
+            -0.2299,
+            0.06,
             14.3938,
             5.0,
             2.0059,
@@ -320,8 +320,8 @@ catch22_basic_motions_data = np.array(
             0.1047,
             2.0,
             0.3333,
-            0.15,
-            -0.18,
+            0.06,
+            -0.235,
             7.1407,
             6.0,
             2.0097,
@@ -342,7 +342,7 @@ catch22_basic_motions_data = np.array(
             0.064,
             1.0,
             0.3333,
-            0.18,
+            0.20,
             0.3,
             1.6007,
             5.0,
@@ -365,7 +365,7 @@ catch22_basic_motions_data = np.array(
             2.0,
             0.3333,
             -0.14,
-            0.1,
+            -0.0399,
             7.3076,
             5.0,
             1.9736,
@@ -389,7 +389,7 @@ catch22_basic_motions_data = np.array(
             2.0,
             0.3333,
             -0.13,
-            0.02,
+            -0.3399,
             0.0081,
             5.0,
             2.133,
@@ -410,8 +410,8 @@ catch22_basic_motions_data = np.array(
             0.5715,
             2.0,
             1.0,
-            -0.12,
-            -0.02,
+            -0.1399,
+            -0.0099,
             0.1288,
             7.0,
             1.9505,
@@ -476,8 +476,8 @@ catch22_basic_motions_data = np.array(
             6.8497,
             2.0,
             0.3333,
-            -0.06,
-            0.05,
+            -0.0799,
+            0.03,
             0.0013,
             7.0,
             2.039,
@@ -498,8 +498,8 @@ catch22_basic_motions_data = np.array(
             3.1416,
             2.0,
             1.0,
-            -0.155,
-            0.125,
+            -0.1999,
+            0.1200,
             0.0212,
             7.0,
             1.8706,
@@ -522,7 +522,7 @@ catch22_basic_motions_data = np.array(
             0.1723,
             1.0,
             1.0,
-            -0.01,
+            -0.0799,
             -0.17,
             8.3186,
             5.0,
@@ -544,8 +544,8 @@ catch22_basic_motions_data = np.array(
             0.1222,
             1.0,
             1.0,
-            0.09,
-            0.01,
+            0.08,
+            -0.0099,
             5.3016,
             4.0,
             2.0075,
@@ -566,8 +566,8 @@ catch22_basic_motions_data = np.array(
             0.0841,
             2.0,
             0.5,
-            0.13,
-            -0.08,
+            -0.0199,
+            -0.1199,
             1.7627,
             5.0,
             2.1476,
@@ -611,7 +611,7 @@ catch22_basic_motions_data = np.array(
             1.0,
             0.5,
             -0.05,
-            -0.11,
+            -0.0999,
             0.2086,
             6.0,
             2.0597,
@@ -656,8 +656,8 @@ catch22_basic_motions_data = np.array(
             0.0718,
             1.0,
             0.3333,
-            0.03,
-            0.13,
+            0.025,
+            -0.1399,
             0.501,
             6.0,
             2.0492,
@@ -701,7 +701,7 @@ catch22_basic_motions_data = np.array(
             2.0,
             0.5,
             -0.13,
-            0.19,
+            0.29,
             0.3096,
             6.0,
             1.8881,
@@ -745,7 +745,7 @@ catch22_basic_motions_data = np.array(
             3.0,
             1.0,
             0.11,
-            0.35,
+            0.285,
             0.2719,
             7.0,
             1.7647,