Repository: aeon-toolkit/aeon
Pull request #1988 (2024-08-19 10:40:57)

[BUG] Bug fixes for interval classes
#### What does this implement/fix? Explain your changes.

Corrects warning printouts for attribute subsampling in the interval forest base class

Fixes a bug that caused random intervals to ignore the last timepoint of the series


aeon-actions-bot[bot]: 
## Thank you for contributing to `aeon`


I would have added the following labels to this PR based on the changes made: **[ $\\color{#41A8F6}{\\textsf{transformations}}$ ]**, however some package labels are already present.

The [Checks](https://github.com/aeon-toolkit/aeon/pull/1988/checks) tab will show the status of our automated tests. You can click on individual test runs in the tab or "Details" in the panel below to see more information if there is a failure.

If our `pre-commit` code quality check fails, any trivial fixes will automatically be pushed to your PR unless it is a draft.

Don't hesitate to ask questions on the `aeon` [Slack](https://join.slack.com/t/aeon-toolkit/shared_invite/zt-22vwvut29-HDpCu~7VBUozyfL_8j3dLA) channel if you have any.

### PR CI actions

These checkboxes will add labels to enable/disable CI functionality for this PR. This may not take effect immediately, and a new commit may be required to run the new configuration.

- [ ] Run `pre-commit` checks for all files
- [ ] Run all `pytest` tests and configurations
- [ ] Run all notebook example tests
- [ ] Run numba-disabled `codecov` tests
- [ ] Stop automatic `pre-commit` fixes (always disabled for drafts)
- [ ] Push an empty commit to re-run CI checks
    

Patch:
diff --git a/aeon/base/estimator/interval_based/base_interval_forest.py b/aeon/base/estimator/interval_based/base_interval_forest.py
index 71bd8d6e..a93f7030 100644
--- a/aeon/base/estimator/interval_based/base_interval_forest.py
+++ b/aeon/base/estimator/interval_based/base_interval_forest.py
@@ -948,12 +948,17 @@ class BaseIntervalForest(metaclass=ABCMeta):
                     for i in range(att_subsample_size - count):
                         features.append(all_function_features[atts[count + i] - length])
                 else:
-                    warnings.warn(
-                        f"Attribute subsample size {att_subsample_size} is larger than "
-                        f"or equal to the number of attributes {num_features} for "
-                        f"series {self._series_transformers[r]}",
-                        stacklevel=2,
-                    )
+                    # only warn if requested number of features is greater than actual
+                    if att_subsample_size > num_features:
+                        warnings.warn(
+                            f"Attribute subsample size {att_subsample_size} is "
+                            f"larger than the number of attributes {num_features} "
+                            f"for series {self._series_transformers[r]}",
+                            stacklevel=2,
+                        )
+
+                    self._att_subsample_size[r] = None
+
                     for feature in self._interval_features[r]:
                         if isinstance(feature, BaseTransformer):
                             features.append(_clone_estimator(feature, seed))
@@ -1151,7 +1156,7 @@ class BaseIntervalForest(metaclass=ABCMeta):
         """
         if not isinstance(self._base_estimator, ContinuousIntervalTree):
             raise ValueError(
-                "CIF base estimator for temporal importance curves must"
+                "base_estimator for temporal importance curves must"
                 " be ContinuousIntervalTree."
             )
 
@@ -1172,9 +1177,6 @@ class BaseIntervalForest(metaclass=ABCMeta):
                 )
 
                 for interval in rep.intervals_:
-                    if t % len(self._interval_features[n]) - 1 == 0:
-                        t = 0
-
                     if _is_transformer(interval[3]):
                         if self._att_subsample_size[n] is None:
                             names = None
@@ -1193,6 +1195,9 @@ class BaseIntervalForest(metaclass=ABCMeta):
                                     "importance curves."
                                 )
                         else:
+                            if t % len(self._interval_features[n]) - 1 == 0:
+                                t = 0
+
                             names = getattr(
                                 interval[3], self._transformer_feature_names[n][t]
                             )
diff --git a/aeon/classification/interval_based/_interval_pipelines.py b/aeon/classification/interval_based/_interval_pipelines.py
index dc514f35..00aa16e1 100644
--- a/aeon/classification/interval_based/_interval_pipelines.py
+++ b/aeon/classification/interval_based/_interval_pipelines.py
@@ -94,7 +94,7 @@ class RandomIntervalClassifier(BaseClassifier):
     >>> clf.fit(X, y)
     RandomIntervalClassifier(...)
     >>> clf.predict(X)
-    array([0, 1, 0, 1, 0, 0, 0, 1, 1, 0])
+    array([0, 1, 0, 1, 0, 0, 1, 1, 1, 0])
     """
 
     _tags = {
diff --git a/aeon/regression/interval_based/_cif.py b/aeon/regression/interval_based/_cif.py
index 98501093..34fede19 100644
--- a/aeon/regression/interval_based/_cif.py
+++ b/aeon/regression/interval_based/_cif.py
@@ -136,8 +136,8 @@ class CanonicalIntervalForestRegressor(BaseIntervalForest, BaseRegressor):
     >>> reg.fit(X, y)
     CanonicalIntervalForestRegressor(n_estimators=10, random_state=0)
     >>> reg.predict(X)
-    array([0.7252543 , 1.50132442, 0.95608366, 1.64399016, 0.42385504,
-           0.60639322, 1.01919317, 1.30157483, 1.66017354, 0.2900776 ])
+    array([0.7252543 , 1.45657786, 0.95608366, 1.64399016, 0.42385504,
+           0.65113978, 1.01919317, 1.30157483, 1.66017354, 0.2900776 ])
     """
 
     _tags = {
diff --git a/aeon/regression/interval_based/_interval_pipelines.py b/aeon/regression/interval_based/_interval_pipelines.py
index 995b45ce..04cce958 100644
--- a/aeon/regression/interval_based/_interval_pipelines.py
+++ b/aeon/regression/interval_based/_interval_pipelines.py
@@ -87,8 +87,8 @@ class RandomIntervalRegressor(BaseRegressor):
     >>> reg.fit(X, y)
     RandomIntervalRegressor(...)
     >>> reg.predict(X)
-    array([0.90900147, 1.22266619, 0.99984114, 1.57550709, 0.39709955,
-           0.67621779, 0.76843601, 1.37005789, 1.58521712, 0.31683308])
+    array([0.70148208, 1.22266619, 0.73353397, 1.57550709, 0.46036267,
+           0.67770987, 1.11890876, 1.37005789, 1.35438452, 0.31683308])
     """
 
     _tags = {
diff --git a/aeon/transformations/collection/interval_based/_random_intervals.py b/aeon/transformations/collection/interval_based/_random_intervals.py
index 54442d3a..c43b01f5 100644
--- a/aeon/transformations/collection/interval_based/_random_intervals.py
+++ b/aeon/transformations/collection/interval_based/_random_intervals.py
@@ -315,12 +315,12 @@ class RandomIntervals(BaseCollectionTransformer):
 
         if rng.random() < 0.5:
             interval_start = (
-                rng.randint(0, self.n_timepoints_ - self._min_interval_length)
+                rng.randint(0, self.n_timepoints_ + 1 - self._min_interval_length)
                 if self.n_timepoints_ > self._min_interval_length
                 else 0
             )
             len_range = min(
-                self.n_timepoints_ - interval_start,
+                self.n_timepoints_ + 1 - interval_start,
                 self._max_interval_length,
             )
             length = (
@@ -332,7 +332,7 @@ class RandomIntervals(BaseCollectionTransformer):
             interval_end = interval_start + length
         else:
             interval_end = (
-                rng.randint(0, self.n_timepoints_ - self._min_interval_length)
+                rng.randint(0, self.n_timepoints_ + 1 - self._min_interval_length)
                 + self._min_interval_length
                 if self.n_timepoints_ > self._min_interval_length
                 else self._min_interval_length
diff --git a/aeon/transformations/collection/shapelet_based/_rsast.py b/aeon/transformations/collection/shapelet_based/_rsast.py
index 74eb2cc6..48a611ea 100644
--- a/aeon/transformations/collection/shapelet_based/_rsast.py
+++ b/aeon/transformations/collection/shapelet_based/_rsast.py
@@ -1,3 +1,5 @@
+from typing import List, Optional, Union
+
 import numpy as np
 import pandas as pd
 from numba import get_num_threads, njit, prange, set_num_threads
@@ -8,7 +10,7 @@ from aeon.utils.validation import check_n_jobs
 
 
 @njit(fastmath=False)
-def _apply_kernel(ts, arr):
+def _apply_kernel(ts: np.ndarray, arr: np.ndarray) -> float:
     d_best = np.inf  # sdist
     m = ts.shape[0]
     kernel = arr[~np.isnan(arr)]  # ignore nan
@@ -22,7 +24,7 @@ def _apply_kernel(ts, arr):
 
 
 @njit(parallel=True, fastmath=True)
-def _apply_kernels(X, kernels):
+def _apply_kernels(X: np.ndarray, kernels: np.ndarray) -> np.ndarray:
     nbk = len(kernels)
     out = np.zeros((X.shape[0], nbk), dtype=np.float32)
     for i in prange(nbk):
@@ -96,11 +98,11 @@ class RSAST(BaseCollectionTransformer):
 
     def __init__(
         self,
-        n_random_points=10,
-        len_method="both",
-        nb_inst_per_class=10,
-        seed=None,
-        n_jobs=-1,
+        n_random_points: int = 10,
+        len_method: str = "both",
+        nb_inst_per_class: int = 10,
+        seed: int = None,
+        n_jobs: int = 1,  # Parllel Processing
     ):
         self.n_random_points = n_random_points
         self.len_method = len_method
@@ -113,7 +115,7 @@ class RSAST(BaseCollectionTransformer):
         self._kernels_generators = {}  # Reference time series
         super().__init__()
 
-    def _fit(self, X, y):
+    def _fit(self, X: np.ndarray, y: Union[np.ndarray, List]) -> "RSAST":
         from scipy.stats import ConstantInputWarning, DegenerateDataWarning, f_oneway
         from statsmodels.tsa.stattools import acf, pacf
 
@@ -300,7 +302,9 @@ class RSAST(BaseCollectionTransformer):
 
         return self
 
-    def _transform(self, X, y=None):
+    def _transform(
+        self, X: np.ndarray, y: Optional[Union[np.ndarray, List]] = None
+    ) -> np.ndarray:
         """Transform the input X using the generated subsequences.
 
         Parameters
diff --git a/aeon/transformations/collection/shapelet_based/_sast.py b/aeon/transformations/collection/shapelet_based/_sast.py
index 9b1b2ec9..e6fb05b9 100644
--- a/aeon/transformations/collection/shapelet_based/_sast.py
+++ b/aeon/transformations/collection/shapelet_based/_sast.py
@@ -1,3 +1,5 @@
+from typing import List, Optional, Union
+
 import numpy as np
 from numba import get_num_threads, njit, prange, set_num_threads
 
@@ -7,7 +9,7 @@ from aeon.utils.validation import check_n_jobs
 
 
 @njit(fastmath=False)
-def _apply_kernel(ts, arr):
+def _apply_kernel(ts: np.ndarray, arr: np.ndarray) -> float:
     d_best = np.inf  # sdist
     m = ts.shape[0]
     kernel = arr[~np.isnan(arr)]  # ignore nan
@@ -22,7 +24,7 @@ def _apply_kernel(ts, arr):
 
 
 @njit(parallel=True, fastmath=True)
-def _apply_kernels(X, kernels):
+def _apply_kernels(X: np.ndarray, kernels: np.ndarray) -> np.ndarray:
     nbk = len(kernels)
     out = np.zeros((X.shape[0], nbk), dtype=np.float32)
     for i in prange(nbk):
@@ -88,11 +90,11 @@ class SAST(BaseCollectionTransformer):
 
     def __init__(
         self,
-        lengths=None,
-        stride=1,
-        nb_inst_per_class=1,
-        seed=None,
-        n_jobs=-1,
+        lengths: Optional[np.ndarray] = None,
+        stride: int = 1,
+        nb_inst_per_class: int = 1,
+        seed: Optional[int] = None,
+        n_jobs: int = 1,  # Parallel processing
     ):
         super().__init__()
         self.lengths = lengths
@@ -104,7 +106,7 @@ class SAST(BaseCollectionTransformer):
         self.n_jobs = n_jobs
         self.seed = seed
 
-    def _fit(self, X, y):
+    def _fit(self, X: np.ndarray, y: Union[np.ndarray, List]) -> "SAST":
         """Select reference time series and generate subsequences from them.
 
         Parameters
@@ -171,7 +173,9 @@ class SAST(BaseCollectionTransformer):
                     k += 1
         return self
 
-    def _transform(self, X, y=None):
+    def _transform(
+        self, X: np.ndarray, y: Optional[Union[np.ndarray, List]] = None
+    ) -> np.ndarray:
         """Transform the input X using the generated subsequences.
 
         Parameters


Test patch:
diff --git a/aeon/classification/early_classification/tests/test_probability_threshold.py b/aeon/classification/early_classification/tests/test_probability_threshold.py
index c34401dd..559c0689 100644
--- a/aeon/classification/early_classification/tests/test_probability_threshold.py
+++ b/aeon/classification/early_classification/tests/test_probability_threshold.py
@@ -54,7 +54,7 @@ def test_early_prob_threshold_score():
 
     _, acc, earl = pt.score(X_test, y_test)
     testing.assert_allclose(acc, 0.9, rtol=0.01)
-    testing.assert_allclose(earl, 0.3, rtol=0.01)
+    testing.assert_allclose(earl, 0.266667, rtol=0.01)
 
     # make sure update ends up with the same score
     pt.reset_state_info()
@@ -75,4 +75,4 @@ def test_early_prob_threshold_score():
     _, acc, earl = pt.compute_harmonic_mean(final_states, y_test)
 
     testing.assert_allclose(acc, 0.9, rtol=0.01)
-    testing.assert_allclose(earl, 0.3, rtol=0.01)
+    testing.assert_allclose(earl, 0.266667, rtol=0.01)
diff --git a/aeon/testing/expected_results/expected_classifier_outputs.py b/aeon/testing/expected_results/expected_classifier_outputs.py
index ef0c593c..c1ddedea 100644
--- a/aeon/testing/expected_results/expected_classifier_outputs.py
+++ b/aeon/testing/expected_results/expected_classifier_outputs.py
@@ -306,41 +306,41 @@ unit_test_proba["HIVECOTEV2"] = np.array(
 unit_test_proba["CanonicalIntervalForestClassifier"] = np.array(
     [
         [0.3, 0.7],
-        [0.9, 0.1],
-        [0.2, 0.8],
         [0.8, 0.2],
+        [0.2, 0.8],
+        [0.9, 0.1],
         [0.7, 0.3],
         [0.9, 0.1],
-        [0.4, 0.6],
+        [0.5, 0.5],
         [0.3, 0.7],
-        [0.6, 0.4],
+        [0.5, 0.5],
         [0.8, 0.2],
     ]
 )
 unit_test_proba["DrCIFClassifier"] = np.array(
     [
-        [0.2, 0.8],
-        [0.9, 0.1],
         [0.1, 0.9],
+        [0.8, 0.2],
+        [0.0, 1.0],
         [1.0, 0.0],
+        [0.7, 0.3],
         [0.9, 0.1],
-        [1.0, 0.0],
         [0.8, 0.2],
-        [0.5, 0.5],
-        [1.0, 0.0],
+        [0.4, 0.6],
+        [0.9, 0.1],
         [1.0, 0.0],
     ]
 )
 unit_test_proba["IntervalForestClassifier"] = np.array(
     [
         [0.2, 0.8],
-        [0.8, 0.2],
+        [0.7, 0.3],
         [0.1, 0.9],
-        [1.0, 0.0],
+        [0.9, 0.1],
+        [0.7, 0.3],
         [0.8, 0.2],
-        [1.0, 0.0],
-        [0.6, 0.4],
-        [0.4, 0.6],
+        [0.7, 0.3],
+        [0.5, 0.5],
         [0.7, 0.3],
         [1.0, 0.0],
     ]
@@ -348,15 +348,15 @@ unit_test_proba["IntervalForestClassifier"] = np.array(
 unit_test_proba["RandomIntervalSpectralEnsembleClassifier"] = np.array(
     [
         [0.3, 0.7],
-        [0.8, 0.2],
+        [0.7, 0.3],
         [0.1, 0.9],
         [0.7, 0.3],
         [0.6, 0.4],
+        [0.9, 0.1],
         [0.8, 0.2],
+        [0.3, 0.7],
         [0.7, 0.3],
-        [0.2, 0.8],
-        [0.6, 0.4],
-        [0.8, 0.2],
+        [0.9, 0.1],
     ]
 )
 unit_test_proba["RSTSF"] = np.array(
@@ -396,8 +396,8 @@ unit_test_proba["TimeSeriesForestClassifier"] = np.array(
         [1.0, 0.0],
         [1.0, 0.0],
         [0.8, 0.2],
-        [0.4, 0.6],
-        [0.9, 0.1],
+        [0.3, 0.7],
+        [0.8, 0.2],
         [0.9, 0.1],
     ]
 )
@@ -523,7 +523,7 @@ basic_motions_proba["ChannelEnsembleClassifier"] = np.array(
         [0.0, 0.0825, 0.0, 0.9175],
         [0.0, 0.0825, 0.25, 0.6675],
         [0.0, 0.3325, 0.4175, 0.25],
-        [0.0, 0.3325, 0.4175, 0.25],
+        [0.25, 0.0825, 0.4175, 0.25],
         [0.0, 0.5825, 0.4175, 0.0],
         [0.25, 0.0825, 0.6675, 0.0],
     ]
@@ -642,26 +642,26 @@ basic_motions_proba["KNeighborsTimeSeriesClassifier"] = np.array(
 )
 basic_motions_proba["TEASER"] = np.array(
     [
-        [0.0, 0.1, 0.1, 0.8],
-        [0.2, 0.2, 0.1, 0.5],
+        [0.0, 0.1, 0.2, 0.7],
+        [0.1, 0.0, 0.3, 0.6],
         [0.0, 0.0, 1.0, 0.0],
         [0.2, 0.8, 0.0, 0.0],
-        [0.0, 0.1, 0.3, 0.6],
-        [0.0, 0.1, 0.1, 0.8],
+        [0.0, 0.0, 0.4, 0.6],
+        [0.0, 0.1, 0.2, 0.7],
         [0.5, 0.4, 0.0, 0.1],
-        [0.0, 0.0, 0.8, 0.2],
+        [0.1, 0.1, 0.6, 0.2],
+        [0.0, 0.9, 0.0, 0.1],
         [0.0, 0.9, 0.0, 0.1],
-        [0.0, 0.3, 0.2, 0.5],
     ]
 )
 basic_motions_proba["ProbabilityThresholdEarlyClassifier"] = np.array(
     [
-        [0.0, 0.0, 0.1, 0.9],
+        [0.1, 0.0, 0.0, 0.9],
         [0.6, 0.4, 0.0, 0.0],
         [0.0, 0.0, 1.0, 0.0],
         [0.2, 0.8, 0.0, 0.0],
         [0.0, 0.2, 0.1, 0.7],
-        [0.0, 0.1, 0.1, 0.8],
+        [0.0, 0.1, 0.2, 0.7],
         [0.5, 0.4, 0.0, 0.1],
         [0.0, 0.0, 1.0, 0.0],
         [0.0, 0.9, 0.0, 0.1],
@@ -783,14 +783,14 @@ basic_motions_proba["HIVECOTEV2"] = np.array(
 basic_motions_proba["CanonicalIntervalForestClassifier"] = np.array(
     [
         [0.0, 0.0, 0.1, 0.9],
-        [0.3, 0.5, 0.0, 0.2],
+        [0.3, 0.4, 0.0, 0.3],
         [0.0, 0.0, 0.8, 0.2],
-        [0.4, 0.2, 0.2, 0.2],
+        [0.3, 0.3, 0.2, 0.2],
         [0.1, 0.0, 0.0, 0.9],
         [0.0, 0.0, 0.2, 0.8],
         [0.3, 0.3, 0.2, 0.2],
-        [0.0, 0.2, 0.7, 0.1],
-        [0.0, 1.0, 0.0, 0.0],
+        [0.1, 0.2, 0.7, 0.0],
+        [0.1, 0.9, 0.0, 0.0],
         [0.1, 0.7, 0.0, 0.2],
     ]
 )
@@ -951,28 +951,28 @@ basic_motions_proba["ShapeletTransformClassifier"] = np.array(
 )
 unit_test_proba["TEASER"] = np.array(
     [
-        [0.0, 1.0],
-        [0.8, 0.2],
+        [0.2, 0.8],
+        [0.9, 0.1],
         [0.0, 1.0],
         [1.0, 0.0],
         [1.0, 0.0],
         [1.0, 0.0],
         [1.0, 0.0],
-        [0.1, 0.9],
-        [0.9, 0.1],
+        [0.2, 0.8],
+        [0.8, 0.2],
         [1.0, 0.0],
     ]
 )
 unit_test_proba["ProbabilityThresholdEarlyClassifier"] = np.array(
     [
         [0.0, 1.0],
-        [0.9, 0.1],
+        [1.0, 0.0],
         [0.0, 1.0],
         [1.0, 0.0],
         [1.0, 0.0],
         [1.0, 0.0],
         [1.0, 0.0],
-        [0.1, 0.9],
+        [0.0, 1.0],
         [1.0, 0.0],
         [1.0, 0.0],
     ]
diff --git a/aeon/testing/expected_results/expected_regressor_outputs.py b/aeon/testing/expected_results/expected_regressor_outputs.py
index cd89dc2c..6b435464 100644
--- a/aeon/testing/expected_results/expected_regressor_outputs.py
+++ b/aeon/testing/expected_results/expected_regressor_outputs.py
@@ -312,25 +312,47 @@ cardano_sentiment_preds["RISTRegressor"] = np.array(
 )
 
 cardano_sentiment_preds["CanonicalIntervalForestRegressor"] = np.array(
-    [0.2546, 0.1796, 0.3423, 0.2016, 0.2369, 0.3178, 0.2051, 0.2286, 0.1956, 0.2452]
+    [
+        0.2814,
+        0.1796,
+        0.3305,
+        0.2093,
+        0.2403,
+        0.2543,
+        0.1683,
+        0.2636,
+        0.1321,
+        0.2302,
+    ]
 )
 
 cardano_sentiment_preds["DrCIFRegressor"] = np.array(
-    [0.2569, 0.2196, 0.2948, 0.2677, 0.0829, 0.0677, 0.1584, 0.1840, 0.0498, 0.1383]
+    [
+        0.2621,
+        0.2652,
+        0.2569,
+        0.1791,
+        0.1364,
+        0.1513,
+        0.1549,
+        0.1407,
+        0.1197,
+        0.1924,
+    ]
 )
 
 cardano_sentiment_preds["IntervalForestRegressor"] = np.array(
     [
         0.173,
-        0.083,
-        0.3016,
-        0.1179,
-        0.1651,
-        0.1383,
-        -0.0245,
-        0.0961,
-        0.049,
-        0.1718,
+        0.0907,
+        0.2631,
+        0.153,
+        0.1266,
+        0.1245,
+        0.0296,
+        0.1578,
+        0.0389,
+        0.1636,
     ]
 )
 
@@ -351,30 +373,30 @@ cardano_sentiment_preds["RandomIntervalRegressor"] = np.array(
 
 cardano_sentiment_preds["RandomIntervalSpectralEnsembleRegressor"] = np.array(
     [
-        0.4,
-        -0.0056,
-        0.2023,
-        0.0986,
-        0.068,
-        0.2063,
-        0.1309,
-        0.1811,
-        0.1295,
-        0.2968,
+        0.4563,
+        0.004,
+        0.2486,
+        0.101,
+        0.1233,
+        0.188,
+        0.1242,
+        0.238,
+        0.1252,
+        0.3264,
     ]
 )
 
 cardano_sentiment_preds["TimeSeriesForestRegressor"] = np.array(
     [
         0.2336,
-        -0.0505,
+        0.0385,
         0.5514,
         0.089,
         0.3174,
-        0.125,
-        0.089,
-        0.0,
-        0.0412,
+        -0.0505,
+        -0.0505,
+        -0.0505,
+        -0.0093,
         0.1924,
     ]
 )
diff --git a/aeon/transformations/collection/interval_based/tests/test_intervals.py b/aeon/transformations/collection/interval_based/tests/test_intervals.py
index d0374eb5..731f630c 100644
--- a/aeon/transformations/collection/interval_based/tests/test_intervals.py
+++ b/aeon/transformations/collection/interval_based/tests/test_intervals.py
@@ -29,12 +29,12 @@ def test_interval_prune():
 
 def test_random_interval_transformer():
     """Test the RandomIntervals transformer output."""
-    X, y = make_example_3d_numpy(random_state=0, n_channels=2, n_timepoints=10)
+    X, y = make_example_3d_numpy(random_state=0, n_channels=2, n_timepoints=20)
 
     rit = RandomIntervals(
         features=SevenNumberSummaryTransformer(),
         n_intervals=5,
-        random_state=2,
+        random_state=0,
     )
     X_t = rit.fit_transform(X, y)