1
1
"""ROCKAD anomaly detector."""
2
2
3
+ __maintainer__ = []
3
4
__all__ = ["ROCKAD" ]
4
5
5
6
import warnings
17
18
18
19
class ROCKAD (BaseSeriesAnomalyDetector ):
19
20
"""
20
- ROCKET-based Anomaly Detector (ROCKAD).
21
+ ROCKET-based Semi-Supervised Anomaly Detector (ROCKAD).
21
22
23
+ Adapted ROCKAD [1]_ version to detect anomalies on time-points.
22
24
ROCKAD leverages the ROCKET transformation for feature extraction from
23
25
time series data and applies the scikit learn k-nearest neighbors (k-NN)
24
26
approach with bootstrap aggregation for robust anomaly detection.
25
27
After windowing, the data gets transformed into the ROCKET feature space.
26
28
Then the windows are compared based on the feature space by
27
- finding the nearest neighbours.
29
+ finding the nearest neighbours. Whole-series based ROCKAD as proposed in
30
+ [1]_ can be found at aeon/anomaly_detection/collection/_rockad.py
28
31
29
32
This class supports both univariate and multivariate time series and
30
33
provides options for normalizing features, applying power transformations,
@@ -61,6 +64,31 @@ class ROCKAD(BaseSeriesAnomalyDetector):
61
64
List containing k-NN estimators used for anomaly scoring, set after fitting.
62
65
power_transformer_ : PowerTransformer
63
66
Transformer used to apply power transformation to the features.
67
+
68
+ References
69
+ ----------
70
+ .. [1] Theissler, A., Wengert, M., Gerschner, F. (2023).
71
+ ROCKAD: Transferring ROCKET to Whole Time Series Anomaly Detection.
72
+ In: Crémilleux, B., Hess, S., Nijssen, S. (eds) Advances in Intelligent
73
+ Data Analysis XXI. IDA 2023. Lecture Notes in Computer Science,
74
+ vol 13876. Springer, Cham. https://doi.org/10.1007/978-3-031-30047-9_33
75
+
76
+ Examples
77
+ --------
78
+ >>> import numpy as np
79
+ >>> from aeon.anomaly_detection.series.distance_based import ROCKAD
80
+ >>> rng = np.random.default_rng(seed=42)
81
+ >>> X_train = rng.normal(loc=0.0, scale=1.0, size=(1000,))
82
+ >>> X_test = rng.normal(loc=0.0, scale=1.0, size=(20,))
83
+ >>> X_test[15:20] -= 5
84
+ >>> detector = ROCKAD(window_size=15,n_estimators=10,n_kernels=10,n_neighbors=3)
85
+ >>> detector.fit(X_train)
86
+ ROCKAD(...)
87
+ >>> detector.predict(X_test)
88
+ array([0. , 0.00554713, 0.0699094 , 0.22881059, 0.32382585,
89
+ 0.43652154, 0.43652154, 0.43652154, 0.43652154, 0.43652154,
90
+ 0.43652154, 0.43652154, 0.43652154, 0.43652154, 0.43652154,
91
+ 0.52382585, 0.65200875, 0.80313368, 0.85194345, 1. ])
64
92
"""
65
93
66
94
_tags = {
@@ -86,7 +114,6 @@ def __init__(
86
114
n_jobs = 1 ,
87
115
random_state = 42 ,
88
116
):
89
-
90
117
self .n_estimators = n_estimators
91
118
self .n_kernels = n_kernels
92
119
self .normalise = normalise
@@ -136,7 +163,6 @@ def _check_params(self, X: np.ndarray) -> None:
136
163
)
137
164
138
165
def _inner_fit (self , X : np .ndarray ) -> None :
139
-
140
166
self .rocket_transformer_ = Rocket (
141
167
n_kernels = self .n_kernels ,
142
168
normalise = self .normalise ,
@@ -189,7 +215,6 @@ def _inner_fit(self, X: np.ndarray) -> None:
189
215
self .list_baggers_ .append (estimator )
190
216
191
217
def _predict (self , X ) -> np .ndarray :
192
-
193
218
_X , padding = sliding_windows (
194
219
X , window_size = self .window_size , stride = self .stride , axis = 0
195
220
)
@@ -209,22 +234,8 @@ def _fit_predict(self, X: np.ndarray, y: Optional[np.ndarray] = None) -> np.ndar
209
234
return point_anomaly_scores
210
235
211
236
def _inner_predict (self , X : np .ndarray , padding : int ) -> np .ndarray :
212
-
213
- anomaly_scores = self ._predict_proba (X )
214
-
215
- point_anomaly_scores = reverse_windowing (
216
- anomaly_scores , self .window_size , np .nanmean , self .stride , padding
217
- )
218
-
219
- point_anomaly_scores = (point_anomaly_scores - point_anomaly_scores .min ()) / (
220
- point_anomaly_scores .max () - point_anomaly_scores .min ()
221
- )
222
-
223
- return point_anomaly_scores
224
-
225
- def _predict_proba (self , X ):
226
237
"""
227
- Predicts the probability of anomalies for the input data.
238
+ Predict the anomaly score for each time-point in the input data.
228
239
229
240
Parameters
230
241
----------
@@ -259,6 +270,14 @@ def _predict_proba(self, X):
259
270
y_scores [:, idx ] = scores
260
271
261
272
# Average the scores to get the final score for each time series
262
- y_scores = y_scores .mean (axis = 1 )
273
+ anomaly_scores = y_scores .mean (axis = 1 )
263
274
264
- return y_scores
275
+ point_anomaly_scores = reverse_windowing (
276
+ anomaly_scores , self .window_size , np .nanmean , self .stride , padding
277
+ )
278
+
279
+ point_anomaly_scores = (point_anomaly_scores - point_anomaly_scores .min ()) / (
280
+ point_anomaly_scores .max () - point_anomaly_scores .min ()
281
+ )
282
+
283
+ return point_anomaly_scores
0 commit comments