Skip to content

Commit cec6a5f

Browse files
committed
add time Series Forest Classifier test function using sktime
1 parent 4f11321 commit cec6a5f

File tree

7 files changed

+357
-0
lines changed

7 files changed

+357
-0
lines changed

src/surfaces/test_functions/machine_learning/timeseries/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@
1111
RandomForestForecasterFunction,
1212
)
1313

14+
# sktime-based functions (require sktime)
15+
try:
16+
from .classification import TSForestClassifierFunction
17+
from .forecasting import ExpSmoothingForecasterFunction
18+
19+
_HAS_SKTIME = True
20+
except ImportError:
21+
_HAS_SKTIME = False
22+
1423
__all__ = [
1524
# Forecasting
1625
"GradientBoostingForecasterFunction",
@@ -19,3 +28,11 @@
1928
"RandomForestTSClassifierFunction",
2029
"KNNTSClassifierFunction",
2130
]
31+
32+
if _HAS_SKTIME:
33+
__all__.extend(
34+
[
35+
"ExpSmoothingForecasterFunction",
36+
"TSForestClassifierFunction",
37+
]
38+
)

src/surfaces/test_functions/machine_learning/timeseries/classification/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,18 @@
77
RandomForestTSClassifierFunction,
88
)
99

10+
# sktime-based classifiers (require sktime)
11+
try:
12+
from .test_functions import TSForestClassifierFunction
13+
14+
_HAS_SKTIME = True
15+
except ImportError:
16+
_HAS_SKTIME = False
17+
1018
__all__ = [
1119
"RandomForestTSClassifierFunction",
1220
"KNNTSClassifierFunction",
1321
]
22+
23+
if _HAS_SKTIME:
24+
__all__.append("TSForestClassifierFunction")

src/surfaces/test_functions/machine_learning/timeseries/classification/test_functions/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,18 @@
55
from .knn_ts_classifier import KNNTSClassifierFunction
66
from .random_forest_ts_classifier import RandomForestTSClassifierFunction
77

8+
# sktime-based classifiers (require sktime)
9+
try:
10+
from .ts_forest_classifier import TSForestClassifierFunction
11+
12+
_HAS_SKTIME = True
13+
except ImportError:
14+
_HAS_SKTIME = False
15+
816
__all__ = [
917
"RandomForestTSClassifierFunction",
1018
"KNNTSClassifierFunction",
1119
]
20+
21+
if _HAS_SKTIME:
22+
__all__.append("TSForestClassifierFunction")
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# Author: Simon Blanke
2+
3+
# License: MIT License
4+
5+
"""Time Series Forest Classifier test function using sktime."""
6+
7+
8+
from .._base_ts_classification import BaseTSClassification
9+
from ..datasets import DATASETS
10+
11+
12+
def _check_sktime():
13+
"""Check if sktime is available."""
14+
try:
15+
import sktime # noqa: F401
16+
17+
return True
18+
except ImportError:
19+
raise ImportError(
20+
"Time Series Forest classifier requires sktime. "
21+
"Install with: pip install surfaces[timeseries]"
22+
)
23+
24+
25+
class TSForestClassifierFunction(BaseTSClassification):
26+
"""Time Series Forest Classifier test function using sktime.
27+
28+
Uses sktime's TimeSeriesForestClassifier, an ensemble of decision trees
29+
built on random intervals of time series data.
30+
31+
Parameters
32+
----------
33+
dataset : str, default="gunpoint"
34+
Dataset to use. One of: "gunpoint", "ecg", "synthetic_ts".
35+
cv : int, default=5
36+
Number of cross-validation folds.
37+
use_surrogate : bool, default=False
38+
If True, use pre-trained surrogate for fast evaluation.
39+
objective : str, default="maximize"
40+
Either "minimize" or "maximize".
41+
sleep : float, default=0
42+
Artificial delay in seconds.
43+
44+
Examples
45+
--------
46+
>>> from surfaces.test_functions.machine_learning.timeseries import (
47+
... TSForestClassifierFunction
48+
... )
49+
>>> func = TSForestClassifierFunction(dataset="gunpoint")
50+
>>> result = func({"n_estimators": 100, "min_interval": 3})
51+
"""
52+
53+
name = "Time Series Forest Classifier Function"
54+
_name_ = "ts_forest_classifier"
55+
__name__ = "TSForestClassifierFunction"
56+
57+
available_datasets = list(DATASETS.keys())
58+
available_cv = [2, 3, 5]
59+
60+
# Search space parameters
61+
para_names = ["n_estimators", "min_interval"]
62+
n_estimators_default = [50, 100, 150, 200, 250]
63+
min_interval_default = [3, 5, 7, 10, 15]
64+
65+
def __init__(
66+
self,
67+
dataset: str = "gunpoint",
68+
cv: int = 5,
69+
objective: str = "maximize",
70+
sleep: float = 0,
71+
memory: bool = False,
72+
collect_data: bool = True,
73+
callbacks=None,
74+
catch_errors=None,
75+
use_surrogate: bool = False,
76+
):
77+
_check_sktime()
78+
79+
if dataset not in DATASETS:
80+
raise ValueError(
81+
f"Unknown dataset '{dataset}'. " f"Available: {self.available_datasets}"
82+
)
83+
84+
if cv not in self.available_cv:
85+
raise ValueError(f"Invalid cv={cv}. Available: {self.available_cv}")
86+
87+
self.dataset = dataset
88+
self.cv = cv
89+
self._dataset_loader = DATASETS[dataset]
90+
91+
super().__init__(
92+
objective=objective,
93+
sleep=sleep,
94+
memory=memory,
95+
collect_data=collect_data,
96+
callbacks=callbacks,
97+
catch_errors=catch_errors,
98+
use_surrogate=use_surrogate,
99+
)
100+
101+
@property
102+
def search_space(self):
103+
"""Search space containing hyperparameters."""
104+
return {
105+
"n_estimators": self.n_estimators_default,
106+
"min_interval": self.min_interval_default,
107+
}
108+
109+
def _create_objective_function(self):
110+
"""Create objective function with fixed dataset and cv."""
111+
from sklearn.model_selection import cross_val_score
112+
from sktime.classification.interval_based import TimeSeriesForestClassifier
113+
114+
X_raw, y = self._dataset_loader()
115+
cv = self.cv
116+
117+
# sktime expects 3D array: (n_samples, n_channels, n_timepoints)
118+
# Our data is 2D: (n_samples, n_timepoints)
119+
# Reshape to add channel dimension
120+
X = X_raw.reshape(X_raw.shape[0], 1, X_raw.shape[1])
121+
122+
def ts_forest_classifier(params):
123+
model = TimeSeriesForestClassifier(
124+
n_estimators=params["n_estimators"],
125+
min_interval=params["min_interval"],
126+
random_state=42,
127+
n_jobs=-1,
128+
)
129+
130+
scores = cross_val_score(model, X, y, cv=cv, scoring="accuracy")
131+
return scores.mean()
132+
133+
self.pure_objective_function = ts_forest_classifier
134+
135+
def _get_surrogate_params(self, params):
136+
"""Add fixed parameters for surrogate prediction."""
137+
return {
138+
**params,
139+
"dataset": self.dataset,
140+
"cv": self.cv,
141+
}

src/surfaces/test_functions/machine_learning/timeseries/forecasting/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,18 @@
77
RandomForestForecasterFunction,
88
)
99

10+
# sktime-based forecasters (require sktime)
11+
try:
12+
from .test_functions import ExpSmoothingForecasterFunction
13+
14+
_HAS_SKTIME = True
15+
except ImportError:
16+
_HAS_SKTIME = False
17+
1018
__all__ = [
1119
"GradientBoostingForecasterFunction",
1220
"RandomForestForecasterFunction",
1321
]
22+
23+
if _HAS_SKTIME:
24+
__all__.append("ExpSmoothingForecasterFunction")

src/surfaces/test_functions/machine_learning/timeseries/forecasting/test_functions/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,18 @@
55
from .gradient_boosting_forecaster import GradientBoostingForecasterFunction
66
from .random_forest_forecaster import RandomForestForecasterFunction
77

8+
# sktime-based forecasters (require sktime)
9+
try:
10+
from .exp_smoothing_forecaster import ExpSmoothingForecasterFunction
11+
12+
_HAS_SKTIME = True
13+
except ImportError:
14+
_HAS_SKTIME = False
15+
816
__all__ = [
917
"GradientBoostingForecasterFunction",
1018
"RandomForestForecasterFunction",
1119
]
20+
21+
if _HAS_SKTIME:
22+
__all__.append("ExpSmoothingForecasterFunction")

0 commit comments

Comments
 (0)