tsadmetrics 0.1.14__py3-none-any.whl → 0.1.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- docs/conf.py +44 -20
- tests/test_binary.py +194 -7
- tests/test_non_binary.py +76 -27
- tests/test_utils.py +49 -0
- tsadmetrics/__init__.py +1 -1
- tsadmetrics/binary_metrics.py +290 -90
- tsadmetrics/metric_utils.py +3 -238
- tsadmetrics/non_binary_metrics.py +31 -2
- tsadmetrics/scripts/__init__.py +0 -0
- tsadmetrics/scripts/compute_metrics.py +42 -0
- tsadmetrics/utils.py +69 -2
- tsadmetrics/validation.py +35 -0
- {tsadmetrics-0.1.14.dist-info → tsadmetrics-0.1.16.dist-info}/METADATA +1 -1
- {tsadmetrics-0.1.14.dist-info → tsadmetrics-0.1.16.dist-info}/RECORD +17 -12
- tsadmetrics-0.1.16.dist-info/entry_points.txt +2 -0
- {tsadmetrics-0.1.14.dist-info → tsadmetrics-0.1.16.dist-info}/WHEEL +0 -0
- {tsadmetrics-0.1.14.dist-info → tsadmetrics-0.1.16.dist-info}/top_level.txt +0 -0
tsadmetrics/binary_metrics.py
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
import numpy as np
|
2
2
|
from .metric_utils import *
|
3
|
-
from .
|
4
|
-
|
5
|
-
|
3
|
+
from .validation import *
|
6
4
|
from ._tsadeval.metrics import *
|
7
5
|
from ._tsadeval.prts.basic_metrics_ts import ts_fscore
|
8
6
|
from pate.PATE_metric import PATE
|
@@ -23,6 +21,8 @@ def point_wise_recall(y_true: np.array, y_pred: np.array):
|
|
23
21
|
Returns:
|
24
22
|
float: The point-wise recall score, which is the ratio of true positives to the sum of true positives and false negatives.
|
25
23
|
"""
|
24
|
+
validate_binary_inputs(y_true, y_pred)
|
25
|
+
|
26
26
|
m = Pointwise_metrics(len(y_true),y_true,y_pred)
|
27
27
|
m.set_confusion()
|
28
28
|
TP,FN = m.tp,m.fn
|
@@ -47,6 +47,8 @@ def point_wise_precision(y_true: np.array, y_pred: np.array):
|
|
47
47
|
Returns:
|
48
48
|
float: The point-wise precision score, which is the ratio of true positives to the sum of true positives and false positives.
|
49
49
|
"""
|
50
|
+
validate_binary_inputs(y_true, y_pred)
|
51
|
+
|
50
52
|
m = Pointwise_metrics(len(y_true),y_true,y_pred)
|
51
53
|
m.set_confusion()
|
52
54
|
TP,FP = m.tp,m.fp
|
@@ -74,6 +76,8 @@ def point_wise_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
|
74
76
|
Returns:
|
75
77
|
float: The point-wise F-score, which is the harmonic mean of precision and recall, adjusted by the beta value.
|
76
78
|
"""
|
79
|
+
validate_binary_inputs(y_true, y_pred)
|
80
|
+
|
77
81
|
precision = point_wise_precision(y_true, y_pred)
|
78
82
|
recall = point_wise_recall(y_true, y_pred)
|
79
83
|
|
@@ -93,6 +97,9 @@ def point_adjusted_recall(y_true: np.array, y_pred: np.array):
|
|
93
97
|
|
94
98
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
95
99
|
|
100
|
+
For more information, see the original paper:
|
101
|
+
https://doi.org/10.1145/3178876.3185996
|
102
|
+
|
96
103
|
Parameters:
|
97
104
|
y_true (np.array):
|
98
105
|
The ground truth binary labels for the time series data.
|
@@ -102,6 +109,8 @@ def point_adjusted_recall(y_true: np.array, y_pred: np.array):
|
|
102
109
|
Returns:
|
103
110
|
float: The point-adjusted recall score, which is the ratio of true positives to the sum of true positives and false negatives.
|
104
111
|
"""
|
112
|
+
validate_binary_inputs(y_true, y_pred)
|
113
|
+
|
105
114
|
if np.sum(y_pred) == 0:
|
106
115
|
return 0
|
107
116
|
m = PointAdjust(len(y_true),y_true,y_pred)
|
@@ -121,6 +130,9 @@ def point_adjusted_precision(y_true: np.array, y_pred: np.array):
|
|
121
130
|
|
122
131
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
123
132
|
|
133
|
+
For more information, see the original paper:
|
134
|
+
https://doi.org/10.1145/3178876.3185996
|
135
|
+
|
124
136
|
Parameters:
|
125
137
|
y_true (np.array):
|
126
138
|
The ground truth binary labels for the time series data.
|
@@ -130,6 +142,8 @@ def point_adjusted_precision(y_true: np.array, y_pred: np.array):
|
|
130
142
|
Returns:
|
131
143
|
float: The point-adjusted precision score, which is the ratio of true positives to the sum of true positives and false positives.
|
132
144
|
"""
|
145
|
+
validate_binary_inputs(y_true, y_pred)
|
146
|
+
|
133
147
|
if np.sum(y_pred) == 0:
|
134
148
|
return 0
|
135
149
|
m = PointAdjust(len(y_true),y_true,y_pred)
|
@@ -146,8 +160,12 @@ def point_adjusted_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
|
146
160
|
if at least one point within that segment is predicted as anomalous, all points in the segment
|
147
161
|
are marked as correctly detected. The adjusted predictions are then compared to the ground-truth
|
148
162
|
labels using the standard point-wise F-Score formulation.
|
163
|
+
|
149
164
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
150
165
|
|
166
|
+
For more information, see the original paper:
|
167
|
+
https://doi.org/10.1145/3178876.3185996
|
168
|
+
|
151
169
|
Parameters:
|
152
170
|
y_true (np.array):
|
153
171
|
The ground truth binary labels for the time series data.
|
@@ -160,6 +178,8 @@ def point_adjusted_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
|
160
178
|
Returns:
|
161
179
|
float: The point-adjusted F-score, which is the harmonic mean of precision and recall, adjusted by the beta value.
|
162
180
|
"""
|
181
|
+
validate_binary_inputs(y_true, y_pred)
|
182
|
+
|
163
183
|
precision = point_adjusted_precision(y_true, y_pred)
|
164
184
|
recall = point_adjusted_recall(y_true, y_pred)
|
165
185
|
|
@@ -181,6 +201,9 @@ def delay_th_point_adjusted_recall(y_true: np.array, y_pred: np.array, k: int):
|
|
181
201
|
|
182
202
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
183
203
|
|
204
|
+
For more information, see the original paper:
|
205
|
+
https://doi.org/10.1145/3292500.3330680
|
206
|
+
|
184
207
|
Parameters:
|
185
208
|
y_true (np.array):
|
186
209
|
The ground truth binary labels for the time series data.
|
@@ -193,6 +216,8 @@ def delay_th_point_adjusted_recall(y_true: np.array, y_pred: np.array, k: int):
|
|
193
216
|
Returns:
|
194
217
|
float: The delay thresholded point-adjusted recall score, which is the ratio of true positives to the sum of true positives and false negatives.
|
195
218
|
"""
|
219
|
+
validate_binary_inputs(y_true, y_pred)
|
220
|
+
|
196
221
|
if np.sum(y_pred) == 0:
|
197
222
|
return 0
|
198
223
|
m = DelayThresholdedPointAdjust(len(y_true),y_true,y_pred,k=k)
|
@@ -212,6 +237,9 @@ def delay_th_point_adjusted_precision(y_true: np.array, y_pred: np.array, k: int
|
|
212
237
|
|
213
238
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
214
239
|
|
240
|
+
For more information, see the original paper:
|
241
|
+
https://doi.org/10.1145/3292500.3330680
|
242
|
+
|
215
243
|
Parameters:
|
216
244
|
y_true (np.array):
|
217
245
|
The ground truth binary labels for the time series data.
|
@@ -224,6 +252,8 @@ def delay_th_point_adjusted_precision(y_true: np.array, y_pred: np.array, k: int
|
|
224
252
|
Returns:
|
225
253
|
float: The delay thresholded point-adjusted precision score, which is the ratio of true positives to the sum of true positives and false positives.
|
226
254
|
"""
|
255
|
+
validate_binary_inputs(y_true, y_pred)
|
256
|
+
|
227
257
|
if np.sum(y_pred) == 0:
|
228
258
|
return 0
|
229
259
|
m = DelayThresholdedPointAdjust(len(y_true),y_true,y_pred,k=k)
|
@@ -243,6 +273,9 @@ def delay_th_point_adjusted_f_score(y_true: np.array, y_pred: np.array, k: int,
|
|
243
273
|
|
244
274
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
245
275
|
|
276
|
+
For more information, see the original paper:
|
277
|
+
https://doi.org/10.1145/3292500.3330680
|
278
|
+
|
246
279
|
Parameters:
|
247
280
|
y_true (np.array):
|
248
281
|
The ground truth binary labels for the time series data.
|
@@ -257,6 +290,8 @@ def delay_th_point_adjusted_f_score(y_true: np.array, y_pred: np.array, k: int,
|
|
257
290
|
Returns:
|
258
291
|
float: The delay thresholded point-adjusted F-score, which is the harmonic mean of precision and recall, adjusted by the beta value.
|
259
292
|
"""
|
293
|
+
validate_binary_inputs(y_true, y_pred)
|
294
|
+
|
260
295
|
precision = delay_th_point_adjusted_precision(y_true, y_pred, k)
|
261
296
|
recall = delay_th_point_adjusted_recall(y_true, y_pred, k)
|
262
297
|
|
@@ -272,12 +307,14 @@ def point_adjusted_at_k_recall(y_true: np.array, y_pred: np.array, k: float):
|
|
272
307
|
This metric is based on the standard recall score, but applies a temporal adjustment
|
273
308
|
to the predictions before computing it. Specifically, for each ground-truth anomalous segment,
|
274
309
|
if at least K% of the points within that segment are predicted as anomalous, all points in
|
275
|
-
the segment are marked as correctly detected.
|
276
|
-
missed, even if some points were correctly predicted. The adjusted predictions are then used
|
310
|
+
the segment are marked as correctly detected. The adjusted predictions are then used
|
277
311
|
to compute the standard point-wise recall.
|
278
312
|
|
279
313
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
280
314
|
|
315
|
+
For more information, see the original paper:
|
316
|
+
https://ojs.aaai.org/index.php/AAAI/article/view/20680
|
317
|
+
|
281
318
|
Parameters:
|
282
319
|
y_true (np.array):
|
283
320
|
The ground truth binary labels for the time series data.
|
@@ -289,6 +326,8 @@ def point_adjusted_at_k_recall(y_true: np.array, y_pred: np.array, k: float):
|
|
289
326
|
Returns:
|
290
327
|
float: The point-adjusted recall score, which is the ratio of true positives to the sum of true positives and false negatives.
|
291
328
|
"""
|
329
|
+
validate_binary_inputs(y_true, y_pred)
|
330
|
+
|
292
331
|
m = PointAdjustKPercent(len(y_true),y_true,y_pred,k=k)
|
293
332
|
TP,FN = m.tp,m.fn
|
294
333
|
if TP == 0:
|
@@ -301,10 +340,13 @@ def point_adjusted_at_k_precision(y_true: np.array, y_pred: np.array, k: float):
|
|
301
340
|
This metric is based on the standard precision score, but applies a temporal adjustment
|
302
341
|
to the predictions before computing it. Specifically, for each ground-truth anomalous segment,
|
303
342
|
if at least K% of the points within that segment are predicted as anomalous, all points in
|
304
|
-
the segment are marked as correctly detected.
|
305
|
-
missed, even if some points were correctly predicted. The adjusted predictions are then used
|
343
|
+
the segment are marked as correctly detected. The adjusted predictions are then used
|
306
344
|
to compute the standard point-wise precision.
|
345
|
+
|
307
346
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
347
|
+
|
348
|
+
For more information, see the original paper:
|
349
|
+
https://ojs.aaai.org/index.php/AAAI/article/view/20680
|
308
350
|
|
309
351
|
Parameters:
|
310
352
|
y_true (np.array):
|
@@ -317,6 +359,8 @@ def point_adjusted_at_k_precision(y_true: np.array, y_pred: np.array, k: float):
|
|
317
359
|
Returns:
|
318
360
|
float: The point-adjusted precision score, which is the ratio of true positives to the sum of true positives and false positives.
|
319
361
|
"""
|
362
|
+
validate_binary_inputs(y_true, y_pred)
|
363
|
+
|
320
364
|
m = PointAdjustKPercent(len(y_true),y_true,y_pred,k=k)
|
321
365
|
TP,FP = m.tp,m.fp
|
322
366
|
if TP == 0:
|
@@ -329,11 +373,13 @@ def point_adjusted_at_k_f_score(y_true: np.array, y_pred: np.array, k: float, be
|
|
329
373
|
This metric is based on the standard F-Score, but applies a temporal adjustment
|
330
374
|
to the predictions before computing it. Specifically, for each ground-truth anomalous segment,
|
331
375
|
if at least K% of the points within that segment are predicted as anomalous, all points in
|
332
|
-
the segment are marked as correctly detected.
|
333
|
-
missed, even if some points were correctly predicted. The adjusted predictions are then used
|
376
|
+
the segment are marked as correctly detected. The adjusted predictions are then used
|
334
377
|
to compute the standard F-Score precision.
|
335
378
|
|
336
379
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
380
|
+
|
381
|
+
For more information, see the original paper:
|
382
|
+
https://ojs.aaai.org/index.php/AAAI/article/view/20680
|
337
383
|
|
338
384
|
Parameters:
|
339
385
|
y_true (np.array):
|
@@ -349,6 +395,8 @@ def point_adjusted_at_k_f_score(y_true: np.array, y_pred: np.array, k: float, be
|
|
349
395
|
Returns:
|
350
396
|
float: The point-adjusted F-score, which is the harmonic mean of precision and recall, adjusted by the beta value.
|
351
397
|
"""
|
398
|
+
validate_binary_inputs(y_true, y_pred)
|
399
|
+
|
352
400
|
precision = point_adjusted_at_k_precision(y_true, y_pred, k)
|
353
401
|
recall = point_adjusted_at_k_recall(y_true, y_pred, k)
|
354
402
|
|
@@ -372,6 +420,9 @@ def latency_sparsity_aw_recall(y_true: np.array, y_pred: np.array, ni: int):
|
|
372
420
|
|
373
421
|
Implementation of https://dl.acm.org/doi/10.1145/3447548.3467174
|
374
422
|
|
423
|
+
For more information, see the original paper:
|
424
|
+
https://doi.org/10.1145/3447548.3467174
|
425
|
+
|
375
426
|
Parameters:
|
376
427
|
y_true (np.array):
|
377
428
|
The ground truth binary labels for the time series data.
|
@@ -383,6 +434,8 @@ def latency_sparsity_aw_recall(y_true: np.array, y_pred: np.array, ni: int):
|
|
383
434
|
Returns:
|
384
435
|
float: The latency and sparsity aware recall score, which is the ratio of true positives to the sum of true positives and false negatives.
|
385
436
|
"""
|
437
|
+
validate_binary_inputs(y_true, y_pred)
|
438
|
+
|
386
439
|
if np.sum(y_pred) == 0:
|
387
440
|
return 0
|
388
441
|
m = LatencySparsityAware(len(y_true),y_true,y_pred,tw=ni)
|
@@ -402,8 +455,12 @@ def latency_sparsity_aw_precision(y_true: np.array, y_pred: np.array, ni: int):
|
|
402
455
|
scattered false positives, predictions are subsampled using a sparsity factor n, so that
|
403
456
|
only one prediction is considered every n time steps. The adjusted predictions are then used
|
404
457
|
to compute the standard point-wise precision.
|
458
|
+
|
405
459
|
Implementation of https://dl.acm.org/doi/10.1145/3447548.3467174
|
406
460
|
|
461
|
+
For more information, see the original paper:
|
462
|
+
https://doi.org/10.1145/3447548.3467174
|
463
|
+
|
407
464
|
Parameters:
|
408
465
|
y_true (np.array):
|
409
466
|
The ground truth binary labels for the time series data.
|
@@ -415,6 +472,8 @@ def latency_sparsity_aw_precision(y_true: np.array, y_pred: np.array, ni: int):
|
|
415
472
|
Returns:
|
416
473
|
float: The latency and sparsity aware precision score, which is the ratio of true positives to the sum of true positives and false positives.
|
417
474
|
"""
|
475
|
+
validate_binary_inputs(y_true, y_pred)
|
476
|
+
|
418
477
|
if np.sum(y_pred) == 0:
|
419
478
|
return 0
|
420
479
|
m = LatencySparsityAware(len(y_true),y_true,y_pred,tw=ni)
|
@@ -437,6 +496,9 @@ def latency_sparsity_aw_f_score(y_true: np.array, y_pred: np.array, ni: int, bet
|
|
437
496
|
|
438
497
|
Implementation of https://dl.acm.org/doi/10.1145/3447548.3467174
|
439
498
|
|
499
|
+
For more information, see the original paper:
|
500
|
+
https://doi.org/10.1145/3447548.3467174
|
501
|
+
|
440
502
|
Parameters:
|
441
503
|
y_true (np.array):
|
442
504
|
The ground truth binary labels for the time series data.
|
@@ -451,6 +513,8 @@ def latency_sparsity_aw_f_score(y_true: np.array, y_pred: np.array, ni: int, bet
|
|
451
513
|
Returns:
|
452
514
|
float: The latency and sparsity aware F-score, which is the harmonic mean of precision and recall, adjusted by the beta value.
|
453
515
|
"""
|
516
|
+
validate_binary_inputs(y_true, y_pred)
|
517
|
+
|
454
518
|
if np.sum(y_pred) == 0:
|
455
519
|
return 0
|
456
520
|
|
@@ -472,7 +536,10 @@ def segment_wise_recall(y_true: np.array, y_pred: np.array):
|
|
472
536
|
overlap with any ground-truth anomaly. The final recall is computed using these adjusted
|
473
537
|
segment-level counts.
|
474
538
|
|
475
|
-
Implementation of https://
|
539
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
540
|
+
|
541
|
+
For more information, see the original paper:
|
542
|
+
https://doi.org/10.1145/3219819.3219845
|
476
543
|
|
477
544
|
Parameters:
|
478
545
|
y_true (np.array):
|
@@ -483,6 +550,8 @@ def segment_wise_recall(y_true: np.array, y_pred: np.array):
|
|
483
550
|
Returns:
|
484
551
|
float: The segment-wise recall score, which is the ratio of true positives to the sum of true positives and false negatives.
|
485
552
|
"""
|
553
|
+
validate_binary_inputs(y_true, y_pred)
|
554
|
+
|
486
555
|
m = Segmentwise_metrics(len(y_true),y_true,y_pred)
|
487
556
|
TP,FN = m.tp,m.fn
|
488
557
|
if TP == 0:
|
@@ -500,7 +569,10 @@ def segment_wise_precision(y_true: np.array, y_pred: np.array):
|
|
500
569
|
overlap with any ground-truth anomaly. The final precision is computed using these adjusted
|
501
570
|
segment-level counts.
|
502
571
|
|
503
|
-
Implementation of https://
|
572
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
573
|
+
|
574
|
+
For more information, see the original paper:
|
575
|
+
https://doi.org/10.1145/3219819.3219845
|
504
576
|
|
505
577
|
Parameters:
|
506
578
|
y_true (np.array):
|
@@ -511,6 +583,8 @@ def segment_wise_precision(y_true: np.array, y_pred: np.array):
|
|
511
583
|
Returns:
|
512
584
|
float: The segment-wise precision score, which is the ratio of true positives to the sum of true positives and false positives.
|
513
585
|
"""
|
586
|
+
validate_binary_inputs(y_true, y_pred)
|
587
|
+
|
514
588
|
m = Segmentwise_metrics(len(y_true),y_true,y_pred)
|
515
589
|
TP,FP = m.tp,m.fp
|
516
590
|
if TP == 0:
|
@@ -528,7 +602,10 @@ def segment_wise_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
|
528
602
|
overlap with any ground-truth anomaly. The final F-score is computed using these adjusted
|
529
603
|
segment-level counts.
|
530
604
|
|
531
|
-
Implementation of https://
|
605
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
606
|
+
|
607
|
+
For more information, see the original paper:
|
608
|
+
https://doi.org/10.1145/3219819.3219845
|
532
609
|
|
533
610
|
Parameters:
|
534
611
|
y_true (np.array):
|
@@ -543,6 +620,8 @@ def segment_wise_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
|
543
620
|
float: The segment-wise F-score, which is the harmonic mean of precision and recall, adjusted by the beta value.
|
544
621
|
|
545
622
|
"""
|
623
|
+
validate_binary_inputs(y_true, y_pred)
|
624
|
+
|
546
625
|
m = Segmentwise_metrics(len(y_true),y_true,y_pred)
|
547
626
|
TP,FN,FP = m.tp,m.fn,m.fp
|
548
627
|
if TP==0:
|
@@ -565,6 +644,9 @@ def composite_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
|
565
644
|
|
566
645
|
Implementation of https://ieeexplore.ieee.org/document/9525836
|
567
646
|
|
647
|
+
For more information, see the original paper:
|
648
|
+
https://doi.org/10.1109/TNNLS.2021.3105827
|
649
|
+
|
568
650
|
Parameters:
|
569
651
|
y_true (np.array):
|
570
652
|
The ground truth binary labels for the time series data.
|
@@ -578,6 +660,8 @@ def composite_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
|
578
660
|
float: The composite F-score, which is the harmonic mean of precision and recall, adjusted by the beta value.
|
579
661
|
|
580
662
|
"""
|
663
|
+
validate_binary_inputs(y_true, y_pred)
|
664
|
+
|
581
665
|
m = Composite_f(len(y_true),y_true,y_pred)
|
582
666
|
#Point wise precision
|
583
667
|
precision = m.precision()
|
@@ -595,11 +679,14 @@ def time_tolerant_recall(y_true: np.array, y_pred: np.array, t: int) -> float:
|
|
595
679
|
Calculate time tolerant recall for anomaly detection in time series.
|
596
680
|
This metric is based on the standard recall, but applies a temporal adjustment
|
597
681
|
to the predictions before computing it. Specifically, a predicted anomalous point is considered
|
598
|
-
a true positive if it lies within a temporal window of size
|
682
|
+
a true positive if it lies within a temporal window of size :math:`{\\tau}` around any ground-truth anomalous point.
|
599
683
|
This allows for small temporal deviations in the predictions to be tolerated. The adjusted predictions are then used
|
600
684
|
to compute the standard point-wise recall.
|
601
685
|
|
602
|
-
Implementation of https://
|
686
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
687
|
+
|
688
|
+
For more information, see the original paper:
|
689
|
+
10.48550/arXiv.2008.05788
|
603
690
|
|
604
691
|
Parameters:
|
605
692
|
y_true (np.array):
|
@@ -612,6 +699,8 @@ def time_tolerant_recall(y_true: np.array, y_pred: np.array, t: int) -> float:
|
|
612
699
|
Returns:
|
613
700
|
float: The time tolerant recall score, which is the ratio of true positives to the sum of true positives and false negatives.
|
614
701
|
"""
|
702
|
+
validate_binary_inputs(y_true, y_pred)
|
703
|
+
|
615
704
|
if np.sum(y_pred) == 0:
|
616
705
|
return 0
|
617
706
|
|
@@ -623,11 +712,14 @@ def time_tolerant_precision(y_true: np.array, y_pred: np.array, t: int) -> float
|
|
623
712
|
Calculate time tolerant precision for anomaly detection in time series.
|
624
713
|
This metric is based on the standard precision, but applies a temporal adjustment
|
625
714
|
to the predictions before computing it. Specifically, a predicted anomalous point is considered
|
626
|
-
a true positive if it lies within a temporal window of size
|
715
|
+
a true positive if it lies within a temporal window of size :math:`{\\tau}` around any ground-truth anomalous point.
|
627
716
|
This allows for small temporal deviations in the predictions to be tolerated. The adjusted predictions are then used
|
628
717
|
to compute the standard point-wise precision.
|
629
718
|
|
630
|
-
Implementation of https://
|
719
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
720
|
+
|
721
|
+
For more information, see the original paper:
|
722
|
+
10.48550/arXiv.2008.05788
|
631
723
|
|
632
724
|
Parameters:
|
633
725
|
y_true (np.array):
|
@@ -640,6 +732,8 @@ def time_tolerant_precision(y_true: np.array, y_pred: np.array, t: int) -> float
|
|
640
732
|
Returns:
|
641
733
|
float: The time tolerant precision score, which is the ratio of true positives to the sum of true positives and false positives.
|
642
734
|
"""
|
735
|
+
validate_binary_inputs(y_true, y_pred)
|
736
|
+
|
643
737
|
if np.sum(y_pred) == 0:
|
644
738
|
return 0
|
645
739
|
m = Time_Tolerant(len(y_true),y_true,y_pred, d=t)
|
@@ -651,11 +745,14 @@ def time_tolerant_f_score(y_true: np.array, y_pred: np.array, t: int, beta=1):
|
|
651
745
|
Calculate time tolerant F-score for anomaly detection in time series.
|
652
746
|
This metric is based on the standard F-score, but applies a temporal adjustment
|
653
747
|
to the predictions before computing it. Specifically, a predicted anomalous point is considered
|
654
|
-
a true positive if it lies within a temporal window of size
|
748
|
+
a true positive if it lies within a temporal window of size :math:`{\\tau}` around any ground-truth anomalous point.
|
655
749
|
This allows for small temporal deviations in the predictions to be tolerated.The adjusted predictions are then used
|
656
750
|
to compute the standard point-wise F-Score.
|
657
751
|
|
658
|
-
Implementation of https://
|
752
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
753
|
+
|
754
|
+
For more information, see the original paper:
|
755
|
+
10.48550/arXiv.2008.05788
|
659
756
|
|
660
757
|
Parameters:
|
661
758
|
y_true (np.array):
|
@@ -672,6 +769,8 @@ def time_tolerant_f_score(y_true: np.array, y_pred: np.array, t: int, beta=1):
|
|
672
769
|
float: The time tolerant F-score, which is the harmonic mean of precision and recall, adjusted by the beta value.
|
673
770
|
|
674
771
|
"""
|
772
|
+
validate_binary_inputs(y_true, y_pred)
|
773
|
+
|
675
774
|
precision = time_tolerant_precision(y_true,y_pred,t)
|
676
775
|
recall = time_tolerant_recall(y_true,y_pred,t)
|
677
776
|
if precision==0 or recall==0:
|
@@ -687,9 +786,11 @@ def range_based_recall(y_true: np.array, y_pred: np.array, alpha: float, bias='f
|
|
687
786
|
rather than individual points. For each true anomaly range, it computes a score that rewards
|
688
787
|
(1) detecting the existence of the range, (2) the proportion of overlap, and (3) penalties or
|
689
788
|
bonuses based on the position and fragmentation of predicted segments. These components are
|
690
|
-
weighted by
|
789
|
+
weighted by :math:`{\\alpha}` (existence vs. overlap) and further shaped by customizable bias functions
|
691
790
|
for positional and cardinality factors.
|
692
791
|
|
792
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
793
|
+
|
693
794
|
For more information, see the original paper:
|
694
795
|
https://proceedings.neurips.cc/paper_files/paper/2018/file/8f468c873a32bb0619eaeb2050ba45d1-Paper.pdf
|
695
796
|
|
@@ -699,7 +800,7 @@ def range_based_recall(y_true: np.array, y_pred: np.array, alpha: float, bias='f
|
|
699
800
|
y_pred (np.array):
|
700
801
|
The predicted binary labels for the time series data.
|
701
802
|
alpha (float):
|
702
|
-
Relative importance of existence reward. 0
|
803
|
+
Relative importance of existence reward. 0 \\leq alpha \\leq 1.
|
703
804
|
bias (str):
|
704
805
|
Positional bias. This should be "flat", "front", "middle", or "back".
|
705
806
|
cardinality_mode (str, optional):
|
@@ -708,6 +809,8 @@ def range_based_recall(y_true: np.array, y_pred: np.array, alpha: float, bias='f
|
|
708
809
|
Returns:
|
709
810
|
float: The range-based recall score.
|
710
811
|
"""
|
812
|
+
validate_binary_inputs(y_true, y_pred)
|
813
|
+
|
711
814
|
if np.sum(y_pred) == 0:
|
712
815
|
return 0
|
713
816
|
m = Range_PR(len(y_true),y_true,y_pred,cardinality=cardinality_mode, alpha=alpha,bias=bias)
|
@@ -723,7 +826,11 @@ def range_based_precision(y_true: np.array, y_pred: np.array, alpha: float, bias
|
|
723
826
|
predicted anomaly range is evaluated for (1) overlap with any true ranges, (2) the size of
|
724
827
|
that overlap, and (3) positional and fragmentation effects via bias functions. Cardinality
|
725
828
|
penalties can be applied when a single true range is covered by multiple predicted ranges.
|
829
|
+
These components are weighted by :math:`{\\alpha}` (existence vs. overlap) and further shaped by customizable bias functions
|
830
|
+
for positional and cardinality factors.
|
726
831
|
|
832
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
833
|
+
|
727
834
|
For more information, see the original paper:
|
728
835
|
https://proceedings.neurips.cc/paper_files/paper/2018/file/8f468c873a32bb0619eaeb2050ba45d1-Paper.pdf
|
729
836
|
|
@@ -733,7 +840,7 @@ def range_based_precision(y_true: np.array, y_pred: np.array, alpha: float, bias
|
|
733
840
|
y_pred (np.array):
|
734
841
|
The predicted binary labels for the time series data.
|
735
842
|
alpha (float):
|
736
|
-
Relative importance of existence reward. 0
|
843
|
+
Relative importance of existence reward. 0 \\leq alpha \\leq 1.
|
737
844
|
bias (str):
|
738
845
|
Positional bias. This should be "flat", "front", "middle", or "back".
|
739
846
|
cardinality_mode (str, optional):
|
@@ -742,6 +849,8 @@ def range_based_precision(y_true: np.array, y_pred: np.array, alpha: float, bias
|
|
742
849
|
Returns:
|
743
850
|
float: The range-based precision score.
|
744
851
|
"""
|
852
|
+
validate_binary_inputs(y_true, y_pred)
|
853
|
+
|
745
854
|
if np.sum(y_pred) == 0:
|
746
855
|
return 0
|
747
856
|
m = Range_PR(len(y_true),y_true,y_pred,cardinality=cardinality_mode, alpha=alpha,bias=bias)
|
@@ -761,6 +870,8 @@ def range_based_f_score(y_true: np.array, y_pred: np.array, p_alpha: float, r_al
|
|
761
870
|
weighting, positional bias, and cardinality factors—allowing fine-grained control over how
|
762
871
|
both missed detections and false alarms are penalized in a temporal context.
|
763
872
|
|
873
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
874
|
+
|
764
875
|
For more information, see the original paper:
|
765
876
|
https://proceedings.neurips.cc/paper_files/paper/2018/file/8f468c873a32bb0619eaeb2050ba45d1-Paper.pdf
|
766
877
|
|
@@ -770,8 +881,10 @@ def range_based_f_score(y_true: np.array, y_pred: np.array, p_alpha: float, r_al
|
|
770
881
|
The ground truth binary labels for the time series data.
|
771
882
|
y_pred (np.array):
|
772
883
|
The predicted binary labels for the time series data.
|
773
|
-
|
774
|
-
Relative importance of existence reward. 0
|
884
|
+
p_alpha (float):
|
885
|
+
Relative importance of existence reward for precision. 0 \\leq alpha \\leq 1.
|
886
|
+
r_alpha (float):
|
887
|
+
Relative importance of existence reward for recall. 0 \\leq alpha \\leq 1.
|
775
888
|
p_bias (str):
|
776
889
|
Positional bias for precision. This should be "flat", "front", "middle", or "back".
|
777
890
|
r_bias (str):
|
@@ -785,6 +898,8 @@ def range_based_f_score(y_true: np.array, y_pred: np.array, p_alpha: float, r_al
|
|
785
898
|
Returns:
|
786
899
|
float: The range-based F-score, which is the harmonic mean of precision and recall, adjusted by the beta value.
|
787
900
|
"""
|
901
|
+
validate_binary_inputs(y_true, y_pred)
|
902
|
+
|
788
903
|
if np.sum(y_pred) == 0:
|
789
904
|
return 0
|
790
905
|
f = ts_fscore(y_true, y_pred, beta=beta, p_alpha=p_alpha, r_alpha=r_alpha, cardinality=cardinality_mode, p_bias=p_bias, r_bias=r_bias)
|
@@ -799,35 +914,42 @@ def ts_aware_recall(y_true: np.array, y_pred: np.array, alpha: float, delta: flo
|
|
799
914
|
|
800
915
|
This metric is based on the range_based_recall, but introduces two key modifications.
|
801
916
|
First, a predicted anomalous segment is only counted as a true positive if it covers at least a fraction
|
802
|
-
|
803
|
-
length
|
917
|
+
:math:`{\\theta}` of the ground‑truth anomaly range. Second, each labeled anomaly is extended by a tolerance window of
|
918
|
+
length :math:`{\\delta}` at its end, within which any overlap contribution decays linearly from full weight down to zero.
|
804
919
|
Unlike the original range-based formulation, this variant omits cardinality and positional bias terms,
|
805
920
|
focusing solely on overlap fraction and end‑tolerance decay.
|
806
921
|
|
922
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
923
|
+
|
924
|
+
For more information, see the original paper:
|
925
|
+
https://doi.org/10.1145/3357384.3358118
|
926
|
+
|
807
927
|
Parameters:
|
808
928
|
y_true (np.array):
|
809
929
|
The ground truth binary labels for the time series data.
|
810
930
|
y_pred (np.array):
|
811
931
|
The predicted binary labels for the time series data.
|
812
932
|
alpha (float):
|
813
|
-
Relative importance of the existence reward versus overlap reward (0
|
933
|
+
Relative importance of the existence reward versus overlap reward (0 \\leq :math:`{\\alpha}` \\leq 1).
|
814
934
|
delta (float):
|
815
935
|
Tolerance window length at the end of each true anomaly segment.
|
816
|
-
- If past_range is True,
|
817
|
-
length to extend. E.g.,
|
818
|
-
- If past_range is False,
|
936
|
+
- If past_range is True, :math:`{\\delta}` must be a float in (0, 1], representing the fraction of the segment’s
|
937
|
+
length to extend. E.g., :math:`{\\delta}` = 0.5 extends a segment of length 10 by 5 time steps.
|
938
|
+
- If past_range is False, :math:`{\\delta}` must be a non-negative integer, representing an absolute number of
|
819
939
|
time steps to extend each segment.
|
820
940
|
theta (float):
|
821
|
-
Minimum fraction (0
|
941
|
+
Minimum fraction (0 \\leq :math:`{\\theta}` \\leq 1) of the true anomaly range that must be overlapped by
|
822
942
|
predictions for the segment to count as detected.
|
823
943
|
past_range (bool):
|
824
|
-
Determines how
|
825
|
-
- True:
|
826
|
-
- False:
|
944
|
+
Determines how :math:`{\\delta}` is interpreted.
|
945
|
+
- True: :math:`{\\delta}` is treated as a fractional extension of each segment’s length.
|
946
|
+
- False: :math:`{\\delta}` is treated as an absolute number of time steps.
|
827
947
|
|
828
948
|
Returns:
|
829
949
|
float: The time series aware recall score.
|
830
950
|
"""
|
951
|
+
validate_binary_inputs(y_true, y_pred)
|
952
|
+
|
831
953
|
m = TaF(len(y_true),y_true,y_pred,alpha=alpha,theta=theta,delta=delta,past_range=past_range)
|
832
954
|
return m.recall()
|
833
955
|
|
@@ -840,35 +962,42 @@ def ts_aware_precision(y_true: np.array, y_pred: np.array,alpha: float, delta: f
|
|
840
962
|
|
841
963
|
This metric is based on the range_based_precision, but introduces two key modifications.
|
842
964
|
First, a predicted anomalous segment is only counted as a true positive if it covers at least a fraction
|
843
|
-
|
844
|
-
length
|
965
|
+
:math:`{\\theta}` of the ground‑truth anomaly range. Second, each labeled anomaly is extended by a tolerance window of
|
966
|
+
length :math:`{\\delta}` at its end, within which any overlap contribution decays linearly from full weight down to zero.
|
845
967
|
Unlike the original range-based formulation, this variant omits cardinality and positional bias terms,
|
846
968
|
focusing solely on overlap fraction and end‑tolerance decay.
|
847
969
|
|
970
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
971
|
+
|
972
|
+
For more information, see the original paper:
|
973
|
+
https://doi.org/10.1145/3357384.3358118
|
974
|
+
|
848
975
|
Parameters:
|
849
976
|
y_true (np.array):
|
850
977
|
The ground truth binary labels for the time series data.
|
851
978
|
y_pred (np.array):
|
852
979
|
The predicted binary labels for the time series data.
|
853
980
|
alpha (float):
|
854
|
-
Relative importance of the existence reward versus overlap reward (0
|
981
|
+
Relative importance of the existence reward versus overlap reward (0 \\leq :math:`{\\alpha}` \\leq 1).
|
855
982
|
delta (float):
|
856
983
|
Tolerance window length at the end of each true anomaly segment.
|
857
|
-
- If past_range is True,
|
858
|
-
length to extend. E.g.,
|
859
|
-
- If past_range is False,
|
984
|
+
- If past_range is True, :math:`{\\delta}` must be a float in (0, 1], representing the fraction of the segment’s
|
985
|
+
length to extend. E.g., :math:`{\\delta}` = 0.5 extends a segment of length 10 by 5 time steps.
|
986
|
+
- If past_range is False, :math:`{\\delta}` must be a non-negative integer, representing an absolute number of
|
860
987
|
time steps to extend each segment.
|
861
988
|
theta (float):
|
862
|
-
Minimum fraction (0
|
989
|
+
Minimum fraction (0 \\leq :math:`{\\theta}` \\leq 1) of the true anomaly range that must be overlapped by
|
863
990
|
predictions for the segment to count as detected.
|
864
991
|
past_range (bool):
|
865
|
-
Determines how
|
866
|
-
- True:
|
867
|
-
- False:
|
992
|
+
Determines how :math:`{\\delta}` is interpreted.
|
993
|
+
- True: :math:`{\\delta}` is treated as a fractional extension of each segment’s length.
|
994
|
+
- False: :math:`{\\delta}` is treated as an absolute number of time steps.
|
868
995
|
|
869
996
|
Returns:
|
870
997
|
float: The time series aware precision score.
|
871
998
|
"""
|
999
|
+
validate_binary_inputs(y_true, y_pred)
|
1000
|
+
|
872
1001
|
m = TaF(len(y_true),y_true,y_pred,alpha=alpha,theta=theta,delta=delta,past_range=past_range)
|
873
1002
|
return m.precision()
|
874
1003
|
|
@@ -882,36 +1011,45 @@ def ts_aware_f_score(y_true: np.array, y_pred: np.array, beta: float, alpha: flo
|
|
882
1011
|
|
883
1012
|
This metric is based on the range_based_f_score, but introduces two key modifications.
|
884
1013
|
First, a predicted anomalous segment is only counted as a true positive if it covers at least a fraction
|
885
|
-
|
886
|
-
length
|
1014
|
+
:math:`{\\theta}` of the ground‑truth anomaly range. Second, each labeled anomaly is extended by a tolerance window of
|
1015
|
+
length :math:`{\\delta}` at its end, within which any overlap contribution decays linearly from full weight down to zero.
|
887
1016
|
Unlike the original range-based formulation, this variant omits cardinality and positional bias terms,
|
888
1017
|
focusing solely on overlap fraction and end‑tolerance decay.
|
889
1018
|
|
1019
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
1020
|
+
|
1021
|
+
For more information, see the original paper:
|
1022
|
+
https://doi.org/10.1145/3357384.3358118
|
1023
|
+
|
890
1024
|
Parameters:
|
891
1025
|
y_true (np.array):
|
892
1026
|
The ground truth binary labels for the time series data.
|
893
1027
|
y_pred (np.array):
|
894
1028
|
The predicted binary labels for the time series data.
|
1029
|
+
beta (float):
|
1030
|
+
The beta value, which determines the weight of precision in the combined score.
|
1031
|
+
Default is 1, which gives equal weight to precision and recall.
|
895
1032
|
alpha (float):
|
896
|
-
Relative importance of the existence reward versus overlap reward (0
|
1033
|
+
Relative importance of the existence reward versus overlap reward (0 \\leq :math:`{\\alpha}` \\leq 1).
|
897
1034
|
delta (float):
|
898
1035
|
Tolerance window length at the end of each true anomaly segment.
|
899
|
-
- If past_range is True,
|
900
|
-
length to extend. E.g.,
|
901
|
-
- If past_range is False,
|
1036
|
+
- If past_range is True, :math:`{\\delta}` must be a float in (0, 1], representing the fraction of the segment’s
|
1037
|
+
length to extend. E.g., :math:`{\\delta}` = 0.5 extends a segment of length 10 by 5 time steps.
|
1038
|
+
- If past_range is False, :math:`{\\delta}` must be a non-negative integer, representing an absolute number of
|
902
1039
|
time steps to extend each segment.
|
903
1040
|
theta (float):
|
904
|
-
Minimum fraction (0
|
1041
|
+
Minimum fraction (0 \\leq :math:`{\\theta}` \\leq 1) of the true anomaly range that must be overlapped by
|
905
1042
|
predictions for the segment to count as detected.
|
906
1043
|
past_range (bool):
|
907
|
-
Determines how
|
908
|
-
- True:
|
909
|
-
- False:
|
1044
|
+
Determines how :math:`{\\delta}` is interpreted.
|
1045
|
+
- True: :math:`{\\delta}` is treated as a fractional extension of each segment’s length.
|
1046
|
+
- False: :math:`{\\delta}` is treated as an absolute number of time steps.
|
910
1047
|
|
911
1048
|
Returns:
|
912
1049
|
float: The time series aware F-score, which is the harmonic mean of precision and recall, adjusted by the beta value.
|
913
1050
|
"""
|
914
|
-
|
1051
|
+
validate_binary_inputs(y_true, y_pred)
|
1052
|
+
|
915
1053
|
m = TaF(len(y_true),y_true,y_pred,alpha=alpha,theta=theta,delta=delta,past_range=past_range)
|
916
1054
|
precision = m.precision()
|
917
1055
|
recall = m.recall()
|
@@ -929,10 +1067,13 @@ def enhanced_ts_aware_recall(y_true: np.array, y_pred: np.array, theta: float):
|
|
929
1067
|
Calculate enhanced time series aware recall for anomaly detection in time series.
|
930
1068
|
|
931
1069
|
This metric is similar to the range-based recall in that it accounts for both detection existence
|
932
|
-
and overlap proportion. Additionally, it requires that a significant fraction
|
933
|
-
segment be detected
|
934
|
-
|
935
|
-
|
1070
|
+
and overlap proportion. Additionally, it requires that a significant fraction :math:`{\\theta}` of each true anomaly
|
1071
|
+
segment be detected.
|
1072
|
+
|
1073
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
1074
|
+
|
1075
|
+
For more information, see the original paper:
|
1076
|
+
https://doi.org/10.1145/3477314.3507024
|
936
1077
|
|
937
1078
|
Parameters:
|
938
1079
|
y_true (np.array):
|
@@ -940,12 +1081,14 @@ def enhanced_ts_aware_recall(y_true: np.array, y_pred: np.array, theta: float):
|
|
940
1081
|
y_pred (np.array):
|
941
1082
|
The predicted binary labels for the time series data.
|
942
1083
|
theta (float):
|
943
|
-
Minimum fraction (0
|
1084
|
+
Minimum fraction (0 \\leq :math:`{\\theta}` \\leq 1) of a true segment that must be overlapped
|
944
1085
|
by predictions to count as detected.
|
945
1086
|
|
946
1087
|
Returns:
|
947
1088
|
float: The time series aware recall score.
|
948
1089
|
"""
|
1090
|
+
validate_binary_inputs(y_true, y_pred)
|
1091
|
+
|
949
1092
|
if np.sum(y_pred) == 0:
|
950
1093
|
return 0
|
951
1094
|
m = eTaF(len(y_true),y_true,y_pred,theta_p=theta)
|
@@ -958,11 +1101,14 @@ def enhanced_ts_aware_precision(y_true: np.array, y_pred: np.array, theta: float
|
|
958
1101
|
"""
|
959
1102
|
Calculate enhanced time series aware precision for anomaly detection in time series.
|
960
1103
|
|
961
|
-
This metric is similar to the range-based precision
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
1104
|
+
This metric is similar to the range-based precision. Additionally, it requires that a significant fraction :math:`{\\theta}`
|
1105
|
+
of each predicted segment overlaps with the ground truth. Finally, precision contributions from each event are weighted by
|
1106
|
+
the square root of the true segment’s length, providing a compromise between point-wise and segment-wise approaches.
|
1107
|
+
|
1108
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
1109
|
+
|
1110
|
+
For more information, see the original paper:
|
1111
|
+
https://doi.org/10.1145/3477314.3507024
|
966
1112
|
|
967
1113
|
Parameters:
|
968
1114
|
y_true (np.array):
|
@@ -970,12 +1116,14 @@ def enhanced_ts_aware_precision(y_true: np.array, y_pred: np.array, theta: float
|
|
970
1116
|
y_pred (np.array):
|
971
1117
|
The predicted binary labels for the time series data.
|
972
1118
|
theta (float):
|
973
|
-
Minimum fraction (0
|
974
|
-
by
|
1119
|
+
Minimum fraction (0 \\leq :math:`{\\theta}` \\leq 1) of a predicted segment that must be overlapped
|
1120
|
+
by ground truth to count as detected.
|
975
1121
|
|
976
1122
|
Returns:
|
977
1123
|
float: The time series aware precision score.
|
978
1124
|
"""
|
1125
|
+
validate_binary_inputs(y_true, y_pred)
|
1126
|
+
|
979
1127
|
if np.sum(y_pred) == 0:
|
980
1128
|
return 0
|
981
1129
|
m = eTaF(len(y_true),y_true,y_pred,theta_p=theta)
|
@@ -990,23 +1138,33 @@ def enhanced_ts_aware_f_score(y_true: np.array, y_pred: np.array, theta_p: float
|
|
990
1138
|
Calculate enhanced time series aware F-score for anomaly detection in time series.
|
991
1139
|
|
992
1140
|
This metric is similar to the range-based F-score in that it accounts for both detection existence
|
993
|
-
and overlap proportion. Additionally, it requires that a significant fraction
|
994
|
-
segment be detected, and that a significant fraction
|
1141
|
+
and overlap proportion. Additionally, it requires that a significant fraction :math:`{\\theta_r}` of each true anomaly
|
1142
|
+
segment be detected, and that a significant fraction :math:`{\\theta_p}` of each predicted segment overlaps with the
|
995
1143
|
ground truth. Finally, F-score contributions from each event are weighted by the square root of the
|
996
1144
|
true segment’s length, providing a compromise between point-wise and segment-wise approaches.
|
997
1145
|
|
1146
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
1147
|
+
|
1148
|
+
For more information, see the original paper:
|
1149
|
+
https://doi.org/10.1145/3477314.3507024
|
1150
|
+
|
998
1151
|
Parameters:
|
999
1152
|
y_true (np.array):
|
1000
1153
|
The ground truth binary labels for the time series data.
|
1001
1154
|
y_pred (np.array):
|
1002
1155
|
The predicted binary labels for the time series data.
|
1003
|
-
|
1004
|
-
Minimum fraction (0
|
1156
|
+
theta_p (float):
|
1157
|
+
Minimum fraction (0 \\leq :math:`{\\theta_p}` \\leq 1) of a predicted segment that must be overlapped
|
1158
|
+
by ground truth to count as detected.
|
1159
|
+
theta_r (float):
|
1160
|
+
Minimum fraction (0 \\leq :math:`{\\theta_r}` \\leq 1) of a true segment that must be overlapped
|
1005
1161
|
by predictions to count as detected.
|
1006
1162
|
|
1007
1163
|
Returns:
|
1008
1164
|
float: The time series aware F-score, which is the harmonic mean of precision and recall, adjusted by the beta value.
|
1009
1165
|
"""
|
1166
|
+
validate_binary_inputs(y_true, y_pred)
|
1167
|
+
|
1010
1168
|
if np.sum(y_pred) == 0:
|
1011
1169
|
return 0
|
1012
1170
|
m = eTaF(len(y_true),y_true,y_pred,theta_p=theta_p, theta_r=theta_r)
|
@@ -1022,6 +1180,11 @@ def affiliation_based_recall(y_true: np.array, y_pred: np.array):
|
|
1022
1180
|
It computes the average distance from each ground truth anomaly point to the nearest
|
1023
1181
|
predicted anomaly point.
|
1024
1182
|
|
1183
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
1184
|
+
|
1185
|
+
For more information, see the original paper:
|
1186
|
+
https://dl.acm.org/doi/10.1145/3534678.3539339
|
1187
|
+
|
1025
1188
|
Parameters:
|
1026
1189
|
y_true (np.array):
|
1027
1190
|
The ground truth binary labels for the time series data.
|
@@ -1031,6 +1194,8 @@ def affiliation_based_recall(y_true: np.array, y_pred: np.array):
|
|
1031
1194
|
Returns:
|
1032
1195
|
float: The affiliation based recall score.
|
1033
1196
|
"""
|
1197
|
+
validate_binary_inputs(y_true, y_pred)
|
1198
|
+
|
1034
1199
|
if np.sum(y_pred) == 0:
|
1035
1200
|
return 0
|
1036
1201
|
m = Affiliation(len(y_true),y_true,y_pred)
|
@@ -1046,6 +1211,11 @@ def affiliation_based_precision(y_true: np.array, y_pred: np.array):
|
|
1046
1211
|
It computes the average distance from each predicted anomaly point to the nearest
|
1047
1212
|
ground truth anomaly point.
|
1048
1213
|
|
1214
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
1215
|
+
|
1216
|
+
For more information, see the original paper:
|
1217
|
+
https://dl.acm.org/doi/10.1145/3534678.3539339
|
1218
|
+
|
1049
1219
|
Parameters:
|
1050
1220
|
y_true (np.array):
|
1051
1221
|
The ground truth binary labels for the time series data.
|
@@ -1056,6 +1226,8 @@ def affiliation_based_precision(y_true: np.array, y_pred: np.array):
|
|
1056
1226
|
Returns:
|
1057
1227
|
float: The affiliation based precision score.
|
1058
1228
|
"""
|
1229
|
+
validate_binary_inputs(y_true, y_pred)
|
1230
|
+
|
1059
1231
|
if np.sum(y_pred) == 0:
|
1060
1232
|
return 0
|
1061
1233
|
m = Affiliation(len(y_true),y_true,y_pred)
|
@@ -1068,11 +1240,16 @@ def affiliation_based_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
|
1068
1240
|
Calculate affiliation based F-score for anomaly detection in time series.
|
1069
1241
|
|
1070
1242
|
This metric combines the affiliation-based precision and recall into a single score
|
1071
|
-
using the harmonic mean, adjusted by a weight
|
1243
|
+
using the harmonic mean, adjusted by a weight :math:`{\\beta}` to control the relative importance
|
1072
1244
|
of recall versus precision. Since both precision and recall are distance-based,
|
1073
1245
|
the F-score reflects a balance between how well predicted anomalies align with true
|
1074
1246
|
anomalies and vice versa.
|
1075
1247
|
|
1248
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
1249
|
+
|
1250
|
+
For more information, see the original paper:
|
1251
|
+
https://dl.acm.org/doi/10.1145/3534678.3539339
|
1252
|
+
|
1076
1253
|
Parameters:
|
1077
1254
|
y_true (np.array):
|
1078
1255
|
The ground truth binary labels for the time series data.
|
@@ -1085,6 +1262,8 @@ def affiliation_based_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
|
1085
1262
|
Returns:
|
1086
1263
|
float: The affiliation based F-score.
|
1087
1264
|
"""
|
1265
|
+
validate_binary_inputs(y_true, y_pred)
|
1266
|
+
|
1088
1267
|
if np.sum(y_pred) == 0:
|
1089
1268
|
return 0
|
1090
1269
|
m = Affiliation(len(y_true),y_true,y_pred)
|
@@ -1100,6 +1279,11 @@ def nab_score(y_true: np.array, y_pred: np.array):
|
|
1100
1279
|
positively to the score, with earlier detections receiving higher rewards. In contrast, every false
|
1101
1280
|
positive prediction contributes negatively.
|
1102
1281
|
|
1282
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
1283
|
+
|
1284
|
+
For more information, see the original paper:
|
1285
|
+
https://doi.org/10.1109/ICMLA.2015.141
|
1286
|
+
|
1103
1287
|
Parameters:
|
1104
1288
|
y_true (np.array):
|
1105
1289
|
The ground truth binary labels for the time series data.
|
@@ -1110,7 +1294,8 @@ def nab_score(y_true: np.array, y_pred: np.array):
|
|
1110
1294
|
Returns:
|
1111
1295
|
float: The nab score.
|
1112
1296
|
"""
|
1113
|
-
|
1297
|
+
validate_binary_inputs(y_true, y_pred)
|
1298
|
+
|
1114
1299
|
m = NAB_score(len(y_true),y_true,y_pred)
|
1115
1300
|
return m.get_score()
|
1116
1301
|
|
@@ -1122,6 +1307,10 @@ def temporal_distance(y_true: np.array, y_pred: np.array, distance: int = 0):
|
|
1122
1307
|
the closest predicted anomaly point, and from each predicted anomaly point to the
|
1123
1308
|
closest labelled anomaly point.
|
1124
1309
|
|
1310
|
+
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
1311
|
+
|
1312
|
+
For more information, see the original paper:
|
1313
|
+
https://sciendo.com/article/10.2478/ausi-2019-0008
|
1125
1314
|
|
1126
1315
|
Parameters:
|
1127
1316
|
y_true (np.array):
|
@@ -1137,7 +1326,8 @@ def temporal_distance(y_true: np.array, y_pred: np.array, distance: int = 0):
|
|
1137
1326
|
Returns:
|
1138
1327
|
float: The temporal distance.
|
1139
1328
|
"""
|
1140
|
-
|
1329
|
+
validate_binary_inputs(y_true, y_pred)
|
1330
|
+
|
1141
1331
|
m = Temporal_Distance(len(y_true),y_true,y_pred,distance=distance)
|
1142
1332
|
return m.get_score()
|
1143
1333
|
|
@@ -1145,8 +1335,8 @@ def average_detection_count(y_true: np.array, y_pred: np.array):
|
|
1145
1335
|
"""
|
1146
1336
|
Calculate average detection count for anomaly detection in time series.
|
1147
1337
|
|
1148
|
-
This metric computes, for each ground-truth anomalous segment,
|
1149
|
-
are predicted as anomalous. It then averages these
|
1338
|
+
This metric computes, for each ground-truth anomalous segment, the percentage of points within that segment
|
1339
|
+
that are predicted as anomalous. It then averages these percentages across all true anomaly events,
|
1150
1340
|
providing an estimate of detection coverage per event.
|
1151
1341
|
|
1152
1342
|
For more information, see the original paper:
|
@@ -1162,10 +1352,11 @@ def average_detection_count(y_true: np.array, y_pred: np.array):
|
|
1162
1352
|
Returns:
|
1163
1353
|
float: The average detection count score.
|
1164
1354
|
"""
|
1165
|
-
|
1355
|
+
validate_binary_inputs(y_true, y_pred)
|
1356
|
+
|
1166
1357
|
b = Binary_detection(len(y_true),y_true,y_pred)
|
1167
1358
|
azs = b.get_gt_anomalies_segmentwise()
|
1168
|
-
a_points = b.
|
1359
|
+
a_points = b.get_predicted_anomalies_ptwise()
|
1169
1360
|
|
1170
1361
|
counts = []
|
1171
1362
|
for az in azs:
|
@@ -1173,7 +1364,7 @@ def average_detection_count(y_true: np.array, y_pred: np.array):
|
|
1173
1364
|
for ap in a_points:
|
1174
1365
|
if ap >= az[0] and ap <= az[1]:
|
1175
1366
|
count+=1
|
1176
|
-
counts.append(count)
|
1367
|
+
counts.append(count/(az[1] - az[0] + 1)) # Normalize by segment length
|
1177
1368
|
|
1178
1369
|
return np.mean(counts)
|
1179
1370
|
|
@@ -1182,7 +1373,7 @@ def absolute_detection_distance(y_true: np.array, y_pred: np.array):
|
|
1182
1373
|
Calculate absolute detection distance for anomaly detection in time series.
|
1183
1374
|
|
1184
1375
|
This metric computes, for each predicted anomaly point that overlaps a ground-truth anomaly segment,
|
1185
|
-
the distance from that point to the temporal center of the corresponding segment. It then sums all
|
1376
|
+
the relative distance from that point to the temporal center of the corresponding segment. It then sums all
|
1186
1377
|
those distances and divides by the total number of such matching predicted points, yielding the
|
1187
1378
|
mean distance to segment centers for correctly detected points.
|
1188
1379
|
|
@@ -1199,17 +1390,19 @@ def absolute_detection_distance(y_true: np.array, y_pred: np.array):
|
|
1199
1390
|
Returns:
|
1200
1391
|
float: The absolute detection distance.
|
1201
1392
|
"""
|
1202
|
-
|
1393
|
+
validate_binary_inputs(y_true, y_pred)
|
1394
|
+
|
1203
1395
|
b = Binary_detection(len(y_true),y_true,y_pred)
|
1204
1396
|
azs = b.get_gt_anomalies_segmentwise()
|
1205
|
-
a_points = b.
|
1206
|
-
|
1397
|
+
a_points = b.get_predicted_anomalies_ptwise()
|
1398
|
+
if len(a_points) == 0:
|
1399
|
+
return float('inf')
|
1207
1400
|
distance = 0
|
1208
1401
|
for az in azs:
|
1209
1402
|
for ap in a_points:
|
1210
1403
|
if ap >= az[0] and ap <= az[1]:
|
1211
1404
|
center = int((az[0] + az[1]) / 2)
|
1212
|
-
distance+=abs(ap - center)
|
1405
|
+
distance+=abs(ap - center)/max(1,int((az[0] + az[1]) / 2))
|
1213
1406
|
|
1214
1407
|
return distance/len(a_points)
|
1215
1408
|
|
@@ -1250,6 +1443,8 @@ def total_detected_in_range(y_true: np.array, y_pred: np.array, k: int):
|
|
1250
1443
|
Returns:
|
1251
1444
|
float: The total detected in range score.
|
1252
1445
|
"""
|
1446
|
+
validate_binary_inputs(y_true, y_pred)
|
1447
|
+
|
1253
1448
|
if np.sum(y_pred) == 0:
|
1254
1449
|
return 0
|
1255
1450
|
em,da,ma,_ = counting_method(y_true, y_pred, k)
|
@@ -1294,6 +1489,8 @@ def detection_accuracy_in_range(y_true: np.array, y_pred: np.array, k: int):
|
|
1294
1489
|
Returns:
|
1295
1490
|
float: The detection accuracy in range score.
|
1296
1491
|
"""
|
1492
|
+
validate_binary_inputs(y_true, y_pred)
|
1493
|
+
|
1297
1494
|
if np.sum(y_pred) == 0:
|
1298
1495
|
return 0
|
1299
1496
|
em,da,_,fa = counting_method(y_true, y_pred, k)
|
@@ -1347,6 +1544,8 @@ def weighted_detection_difference(y_true: np.array, y_pred: np.array, k: int):
|
|
1347
1544
|
Returns:
|
1348
1545
|
float: The weighted detection difference.
|
1349
1546
|
"""
|
1547
|
+
validate_binary_inputs(y_true, y_pred)
|
1548
|
+
|
1350
1549
|
if np.sum(y_pred) == 0:
|
1351
1550
|
return 0
|
1352
1551
|
|
@@ -1393,6 +1592,8 @@ def binary_pate(y_true: np.array, y_pred: np.array, early: int, delay: int):
|
|
1393
1592
|
treated as false positives, and missed intervals as false negatives. The final score balances these
|
1394
1593
|
weighted detections into a single measure of performance.
|
1395
1594
|
|
1595
|
+
Implementation of https://arxiv.org/abs/2405.12096
|
1596
|
+
|
1396
1597
|
For more information, see the original paper:
|
1397
1598
|
https://arxiv.org/abs/2405.12096
|
1398
1599
|
|
@@ -1409,7 +1610,8 @@ def binary_pate(y_true: np.array, y_pred: np.array, early: int, delay: int):
|
|
1409
1610
|
Returns:
|
1410
1611
|
float: The PATE score.
|
1411
1612
|
"""
|
1412
|
-
|
1613
|
+
validate_binary_inputs(y_true, y_pred)
|
1614
|
+
|
1413
1615
|
return PATE(y_true, y_pred, early, delay, binary_scores=True)
|
1414
1616
|
|
1415
1617
|
def mean_time_to_detect(y_true: np.array, y_pred: np.array):
|
@@ -1418,13 +1620,13 @@ def mean_time_to_detect(y_true: np.array, y_pred: np.array):
|
|
1418
1620
|
|
1419
1621
|
This metric quantifies the average detection delay across all true anomaly events.
|
1420
1622
|
For each ground-truth anomaly segment, let i be the index where the segment starts,
|
1421
|
-
and let j
|
1623
|
+
and let :math:`{j \geq i}` be the first index within that segment where the model predicts an anomaly.
|
1422
1624
|
The detection delay for that event is defined as:
|
1423
1625
|
|
1424
1626
|
.. math::
|
1425
|
-
\Delta = j - i
|
1627
|
+
\Delta t = j - i
|
1426
1628
|
|
1427
|
-
The MTTD is the mean of all such
|
1629
|
+
The MTTD is the mean of all such :math:`{\Delta t}` values, one per true anomaly segment, and expresses
|
1428
1630
|
the average number of time steps between the true onset of an anomaly and its first detection.
|
1429
1631
|
|
1430
1632
|
Parameters:
|
@@ -1433,12 +1635,10 @@ def mean_time_to_detect(y_true: np.array, y_pred: np.array):
|
|
1433
1635
|
y_pred (np.array):
|
1434
1636
|
The predicted binary labels for the time series data.
|
1435
1637
|
|
1436
|
-
For more information, see the original paper:
|
1437
|
-
https://arxiv.org/pdf/2211.05244
|
1438
|
-
|
1439
1638
|
Returns:
|
1440
1639
|
float: The mean time to detect.
|
1441
1640
|
"""
|
1641
|
+
validate_binary_inputs(y_true, y_pred)
|
1442
1642
|
|
1443
1643
|
b = Binary_detection(len(y_true),y_true,y_pred)
|
1444
1644
|
a_events = b.get_gt_anomalies_segmentwise()
|