tsadmetrics 0.1.10__py3-none-any.whl → 0.1.11__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 +43 -0
- tests/test_binary.py +6 -6
- tsadmetrics/binary_metrics.py +375 -60
- tsadmetrics/metric_utils.py +18 -5
- tsadmetrics/non_binary_metrics.py +142 -16
- tsadmetrics/utils.py +1 -1
- {tsadmetrics-0.1.10.dist-info → tsadmetrics-0.1.11.dist-info}/METADATA +1 -1
- {tsadmetrics-0.1.10.dist-info → tsadmetrics-0.1.11.dist-info}/RECORD +10 -9
- {tsadmetrics-0.1.10.dist-info → tsadmetrics-0.1.11.dist-info}/top_level.txt +1 -0
- {tsadmetrics-0.1.10.dist-info → tsadmetrics-0.1.11.dist-info}/WHEEL +0 -0
docs/conf.py
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# Configuration file for the Sphinx documentation builder.
|
2
|
+
#
|
3
|
+
# For the full list of built-in configuration values, see the documentation:
|
4
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
5
|
+
|
6
|
+
# -- Project information -----------------------------------------------------
|
7
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
8
|
+
import os
|
9
|
+
import sys
|
10
|
+
sys.path.insert(0, os.path.abspath('../../'))
|
11
|
+
|
12
|
+
|
13
|
+
project = 'TSADmetrics'
|
14
|
+
copyright = '2025, Pedro Rafael Velasco Priego'
|
15
|
+
author = 'Pedro Rafael Velasco Priego'
|
16
|
+
release = 'MIT'
|
17
|
+
|
18
|
+
# -- General configuration ---------------------------------------------------
|
19
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
20
|
+
|
21
|
+
extensions = [
|
22
|
+
'sphinx.ext.autodoc',
|
23
|
+
'sphinx.ext.viewcode',
|
24
|
+
'sphinx.ext.napoleon'
|
25
|
+
]
|
26
|
+
|
27
|
+
intersphinx_mapping = {
|
28
|
+
'python': ('https://docs.python.org/3/', None),
|
29
|
+
'sphinx': ('https://www.sphinx-doc.org/en/master/', None),
|
30
|
+
}
|
31
|
+
intersphinx_disabled_domains = ['std']
|
32
|
+
|
33
|
+
templates_path = ['_templates']
|
34
|
+
exclude_patterns = []
|
35
|
+
|
36
|
+
epub_show_urls = 'footnote'
|
37
|
+
html_theme = 'sphinx_rtd_theme'
|
38
|
+
html_static_path = ['_static']
|
39
|
+
# -- Options for HTML output -------------------------------------------------
|
40
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
41
|
+
|
42
|
+
html_theme = 'sphinx_rtd_theme'
|
43
|
+
html_static_path = ['_static']
|
tests/test_binary.py
CHANGED
@@ -454,19 +454,19 @@ class TestEnhancedTSAwareMetrics(unittest.TestCase):
|
|
454
454
|
"""
|
455
455
|
Prueba para la función ts_aware_f_score.
|
456
456
|
"""
|
457
|
-
f_score = round(enhanced_ts_aware_f_score(self.y_true1, self.y_pred1,
|
457
|
+
f_score = round(enhanced_ts_aware_f_score(self.y_true1, self.y_pred1, 0.5, 0.1),2)
|
458
458
|
expected_f_score = 0.67
|
459
459
|
self.assertAlmostEqual(f_score, expected_f_score, places=4)
|
460
460
|
|
461
|
-
f_score = round(enhanced_ts_aware_f_score(self.y_true1, self.y_pred2,
|
461
|
+
f_score = round(enhanced_ts_aware_f_score(self.y_true1, self.y_pred2, 0.5, 0.1),2)
|
462
462
|
expected_f_score = 0.72
|
463
463
|
self.assertAlmostEqual(f_score, expected_f_score, places=4)
|
464
464
|
|
465
|
-
f_score = round(enhanced_ts_aware_f_score(self.y_true2, self.y_pred21,
|
465
|
+
f_score = round(enhanced_ts_aware_f_score(self.y_true2, self.y_pred21, 0.5, 0.1),2)
|
466
466
|
expected_f_score = 0.77
|
467
467
|
self.assertAlmostEqual(f_score, expected_f_score, places=4)
|
468
468
|
|
469
|
-
f_score = round(enhanced_ts_aware_f_score(self.y_true2, self.y_pred22,
|
469
|
+
f_score = round(enhanced_ts_aware_f_score(self.y_true2, self.y_pred22, 0.5, 0.1),2)
|
470
470
|
expected_f_score = 0.67
|
471
471
|
self.assertAlmostEqual(f_score, expected_f_score, places=4)
|
472
472
|
|
@@ -474,12 +474,12 @@ class TestEnhancedTSAwareMetrics(unittest.TestCase):
|
|
474
474
|
try:
|
475
475
|
y_true = np.random.choice([0, 1], size=(100,))
|
476
476
|
y_pred = np.zeros(100)
|
477
|
-
enhanced_ts_aware_f_score(y_true, y_pred,
|
477
|
+
enhanced_ts_aware_f_score(y_true, y_pred, random.random(), random.random())
|
478
478
|
for _ in range(100):
|
479
479
|
y_true = np.random.choice([0, 1], size=(100,))
|
480
480
|
y_pred = np.random.choice([0, 1], size=(100,))
|
481
481
|
|
482
|
-
f_score = enhanced_ts_aware_f_score(y_true, y_pred,
|
482
|
+
f_score = enhanced_ts_aware_f_score(y_true, y_pred, random.random(), random.random())
|
483
483
|
except Exception as e:
|
484
484
|
self.fail(f"enhanced_ts_aware_f_score raised an exception {e}")
|
485
485
|
|
tsadmetrics/binary_metrics.py
CHANGED
@@ -9,6 +9,8 @@ from pate.PATE_metric import PATE
|
|
9
9
|
def point_wise_recall(y_true: np.array, y_pred: np.array):
|
10
10
|
"""
|
11
11
|
Calculate point-wise recall for anomaly detection in time series.
|
12
|
+
Esta métrica consiste en el recall clásico, sin tener en cuenta el contexto
|
13
|
+
temporal.
|
12
14
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
13
15
|
|
14
16
|
Parameters:
|
@@ -21,7 +23,6 @@ def point_wise_recall(y_true: np.array, y_pred: np.array):
|
|
21
23
|
m = Pointwise_metrics(len(y_true),y_true,y_pred)
|
22
24
|
m.set_confusion()
|
23
25
|
TP,FN = m.tp,m.fn
|
24
|
-
#TP, _, FP, FN = get_tp_tn_fp_fn_point_wise(y_true, y_pred)
|
25
26
|
if TP == 0:
|
26
27
|
return 0
|
27
28
|
return TP / (TP + FN)
|
@@ -29,6 +30,8 @@ def point_wise_recall(y_true: np.array, y_pred: np.array):
|
|
29
30
|
def point_wise_precision(y_true: np.array, y_pred: np.array):
|
30
31
|
"""
|
31
32
|
Calculate point-wise precision for anomaly detection in time series.
|
33
|
+
Esta métrica consiste en la precisión clásica, sin tener en cuenta el contexto
|
34
|
+
temporal.
|
32
35
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
33
36
|
|
34
37
|
Parameters:
|
@@ -38,7 +41,6 @@ def point_wise_precision(y_true: np.array, y_pred: np.array):
|
|
38
41
|
Returns:
|
39
42
|
float: The point-wise precision score, which is the ratio of true positives to the sum of true positives and false positives.
|
40
43
|
"""
|
41
|
-
#TP, _, FP, FN = get_tp_tn_fp_fn_point_wise(y_true, y_pred)
|
42
44
|
m = Pointwise_metrics(len(y_true),y_true,y_pred)
|
43
45
|
m.set_confusion()
|
44
46
|
TP,FP = m.tp,m.fp
|
@@ -49,6 +51,8 @@ def point_wise_precision(y_true: np.array, y_pred: np.array):
|
|
49
51
|
def point_wise_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
50
52
|
"""
|
51
53
|
Calculate point-wise F-score for anomaly detection in time series.
|
54
|
+
Esta métrica consiste en la F-score clásica, sin tener en cuenta el contexto
|
55
|
+
temporal.
|
52
56
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
53
57
|
|
54
58
|
Parameters:
|
@@ -71,7 +75,12 @@ def point_wise_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
|
71
75
|
|
72
76
|
def point_adjusted_recall(y_true: np.array, y_pred: np.array):
|
73
77
|
"""
|
74
|
-
|
78
|
+
This metric is based on the standard recall score, but applies a temporal adjustment
|
79
|
+
to the predictions before computing it. Specifically, for each ground-truth anomalous segment,
|
80
|
+
if at least one point within that segment is predicted as anomalous, all points in the segment
|
81
|
+
are marked as correctly detected. The adjusted predictions are then compared to the ground-truth
|
82
|
+
labels using the standard point-wise recall formulation.
|
83
|
+
|
75
84
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
76
85
|
|
77
86
|
Parameters:
|
@@ -84,7 +93,6 @@ def point_adjusted_recall(y_true: np.array, y_pred: np.array):
|
|
84
93
|
if np.sum(y_pred) == 0:
|
85
94
|
return 0
|
86
95
|
m = PointAdjust(len(y_true),y_true,y_pred)
|
87
|
-
#m.adjust()
|
88
96
|
TP,FN = m.tp,m.fn
|
89
97
|
if TP == 0:
|
90
98
|
return 0
|
@@ -93,6 +101,11 @@ def point_adjusted_recall(y_true: np.array, y_pred: np.array):
|
|
93
101
|
def point_adjusted_precision(y_true: np.array, y_pred: np.array):
|
94
102
|
"""
|
95
103
|
Calculate point-adjusted precision for anomaly detection in time series.
|
104
|
+
This metric is based on the standard precision score, but applies a temporal adjustment
|
105
|
+
to the predictions before computing it. Specifically, for each ground-truth anomalous segment,
|
106
|
+
if at least one point within that segment is predicted as anomalous, all points in the segment
|
107
|
+
are marked as correctly detected. The adjusted predictions are then compared to the ground-truth
|
108
|
+
labels using the standard point-wise precision formulation.
|
96
109
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
97
110
|
|
98
111
|
Parameters:
|
@@ -105,7 +118,6 @@ def point_adjusted_precision(y_true: np.array, y_pred: np.array):
|
|
105
118
|
if np.sum(y_pred) == 0:
|
106
119
|
return 0
|
107
120
|
m = PointAdjust(len(y_true),y_true,y_pred)
|
108
|
-
#m.adjust()
|
109
121
|
TP,FP = m.tp,m.fp
|
110
122
|
if TP == 0:
|
111
123
|
return 0
|
@@ -114,6 +126,11 @@ def point_adjusted_precision(y_true: np.array, y_pred: np.array):
|
|
114
126
|
def point_adjusted_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
115
127
|
"""
|
116
128
|
Calculate point-adjusted F-score for anomaly detection in time series.
|
129
|
+
This metric is based on the standard F-score, but applies a temporal adjustment
|
130
|
+
to the predictions before computing it. Specifically, for each ground-truth anomalous segment,
|
131
|
+
if at least one point within that segment is predicted as anomalous, all points in the segment
|
132
|
+
are marked as correctly detected. The adjusted predictions are then compared to the ground-truth
|
133
|
+
labels using the standard point-wise F-Score formulation.
|
117
134
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
118
135
|
|
119
136
|
Parameters:
|
@@ -138,12 +155,17 @@ def point_adjusted_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
|
138
155
|
def delay_th_point_adjusted_recall(y_true: np.array, y_pred: np.array, k: int):
|
139
156
|
"""
|
140
157
|
Calculate delay thresholded point-adjusted recall for anomaly detection in time series.
|
158
|
+
This metric is based on the standard recall score, but applies a temporal adjustment
|
159
|
+
to the predictions before computing it. Specifically, for each ground-truth anomalous segment,
|
160
|
+
if at least one point within the first k time steps of the segment is predicted as anomalous,
|
161
|
+
all points in the segment are marked as correctly detected. The adjusted predictions are then
|
162
|
+
used to compute the standard point-wise recall formulation.
|
141
163
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
142
164
|
|
143
165
|
Parameters:
|
144
166
|
y_true (np.array): The ground truth binary labels for the time series data.
|
145
167
|
y_pred (np.array): The predicted binary labels for the time series data.
|
146
|
-
k (int):
|
168
|
+
k (int): Maximum number of time steps from the start of an anomaly segment within which a prediction must occur for the segment to be considered detected.
|
147
169
|
|
148
170
|
Returns:
|
149
171
|
float: The delay thresholded point-adjusted recall score, which is the ratio of true positives to the sum of true positives and false negatives.
|
@@ -159,12 +181,17 @@ def delay_th_point_adjusted_recall(y_true: np.array, y_pred: np.array, k: int):
|
|
159
181
|
def delay_th_point_adjusted_precision(y_true: np.array, y_pred: np.array, k: int):
|
160
182
|
"""
|
161
183
|
Calculate delay thresholded point-adjusted precision for anomaly detection in time series.
|
184
|
+
This metric is based on the standard precision score, but applies a temporal adjustment
|
185
|
+
to the predictions before computing it. Specifically, for each ground-truth anomalous segment,
|
186
|
+
if at least one point within the first k time steps of the segment is predicted as anomalous,
|
187
|
+
all points in the segment are marked as correctly detected. The adjusted predictions are then
|
188
|
+
used to compute the standard point-wise precision fromulation.
|
162
189
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
163
190
|
|
164
191
|
Parameters:
|
165
192
|
y_true (np.array): The ground truth binary labels for the time series data.
|
166
193
|
y_pred (np.array): The predicted binary labels for the time series data.
|
167
|
-
k (int):
|
194
|
+
k (int): Maximum number of time steps from the start of an anomaly segment within which a prediction must occur for the segment to be considered detected.
|
168
195
|
|
169
196
|
Returns:
|
170
197
|
float: The delay thresholded point-adjusted precision score, which is the ratio of true positives to the sum of true positives and false positives.
|
@@ -180,12 +207,18 @@ def delay_th_point_adjusted_precision(y_true: np.array, y_pred: np.array, k: int
|
|
180
207
|
def delay_th_point_adjusted_f_score(y_true: np.array, y_pred: np.array, k: int, beta=1):
|
181
208
|
"""
|
182
209
|
Calculate delay thresholded point-adjusted F-score for anomaly detection in time series.
|
210
|
+
This metric is based on the standard F-score, but applies a temporal adjustment
|
211
|
+
to the predictions before computing it. Specifically, for each ground-truth anomalous segment,
|
212
|
+
if at least one point within the first k time steps of the segment is predicted as anomalous,
|
213
|
+
all points in the segment are marked as correctly detected. The adjusted predictions are then
|
214
|
+
used to compute the standard point-wise F-Score formulation.
|
215
|
+
|
183
216
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
184
217
|
|
185
218
|
Parameters:
|
186
219
|
y_true (np.array): The ground truth binary labels for the time series data.
|
187
220
|
y_pred (np.array): The predicted binary labels for the time series data.
|
188
|
-
k (int):
|
221
|
+
k (int): Maximum number of time steps from the start of an anomaly segment within which a prediction must occur for the segment to be considered detected.
|
189
222
|
beta (float): The beta value, which determines the weight of precision in the combined score.
|
190
223
|
Default is 1, which gives equal weight to precision and recall.
|
191
224
|
|
@@ -204,6 +237,12 @@ def delay_th_point_adjusted_f_score(y_true: np.array, y_pred: np.array, k: int,
|
|
204
237
|
def point_adjusted_at_k_recall(y_true: np.array, y_pred: np.array, k: float):
|
205
238
|
"""
|
206
239
|
Calculate k percent point-adjusted at K% recall for anomaly detection in time series.
|
240
|
+
This metric is based on the standard recall score, but applies a temporal adjustment
|
241
|
+
to the predictions before computing it. Specifically, for each ground-truth anomalous segment,
|
242
|
+
if at least K% of the points within that segment are predicted as anomalous, all points in
|
243
|
+
the segment are marked as correctly detected. Otherwise, the entire segment is treated as
|
244
|
+
missed, even if some points were correctly predicted. The adjusted predictions are then used
|
245
|
+
to compute the standard point-wise recall.
|
207
246
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
208
247
|
|
209
248
|
Parameters:
|
@@ -224,6 +263,12 @@ def point_adjusted_at_k_recall(y_true: np.array, y_pred: np.array, k: float):
|
|
224
263
|
def point_adjusted_at_k_precision(y_true: np.array, y_pred: np.array, k: float):
|
225
264
|
"""
|
226
265
|
Calculate point-adjusted at K% precision for anomaly detection in time series.
|
266
|
+
This metric is based on the standard precision score, but applies a temporal adjustment
|
267
|
+
to the predictions before computing it. Specifically, for each ground-truth anomalous segment,
|
268
|
+
if at least K% of the points within that segment are predicted as anomalous, all points in
|
269
|
+
the segment are marked as correctly detected. Otherwise, the entire segment is treated as
|
270
|
+
missed, even if some points were correctly predicted. The adjusted predictions are then used
|
271
|
+
to compute the standard point-wise precision.
|
227
272
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
228
273
|
|
229
274
|
Parameters:
|
@@ -234,7 +279,6 @@ def point_adjusted_at_k_precision(y_true: np.array, y_pred: np.array, k: float):
|
|
234
279
|
Returns:
|
235
280
|
float: The point-adjusted precision score, which is the ratio of true positives to the sum of true positives and false positives.
|
236
281
|
"""
|
237
|
-
#TP, _, FP, _ = get_tp_tn_fp_fn_point_adjusted_at_k(y_true, y_pred, k)
|
238
282
|
m = PointAdjustKPercent(len(y_true),y_true,y_pred,k=k)
|
239
283
|
TP,FP = m.tp,m.fp
|
240
284
|
if TP == 0:
|
@@ -244,6 +288,12 @@ def point_adjusted_at_k_precision(y_true: np.array, y_pred: np.array, k: float):
|
|
244
288
|
def point_adjusted_at_k_f_score(y_true: np.array, y_pred: np.array, k: float, beta=1):
|
245
289
|
"""
|
246
290
|
Calculate point-adjusted at K% F-score for anomaly detection in time series.
|
291
|
+
This metric is based on the standard F-Score, but applies a temporal adjustment
|
292
|
+
to the predictions before computing it. Specifically, for each ground-truth anomalous segment,
|
293
|
+
if at least K% of the points within that segment are predicted as anomalous, all points in
|
294
|
+
the segment are marked as correctly detected. Otherwise, the entire segment is treated as
|
295
|
+
missed, even if some points were correctly predicted. The adjusted predictions are then used
|
296
|
+
to compute the standard F-Score precision.
|
247
297
|
Implementation of https://link.springer.com/article/10.1007/s10618-023-00988-8
|
248
298
|
|
249
299
|
Parameters:
|
@@ -268,6 +318,14 @@ def point_adjusted_at_k_f_score(y_true: np.array, y_pred: np.array, k: float, be
|
|
268
318
|
def latency_sparsity_aw_recall(y_true: np.array, y_pred: np.array, ni: int):
|
269
319
|
"""
|
270
320
|
Calculate latency and sparsity aware recall for anomaly detection in time series.
|
321
|
+
This metric is based on the standard recall, but applies a temporal adjustment
|
322
|
+
to the predictions before computing it. Specifically, for each ground-truth anomalous segment,
|
323
|
+
all points in the segment are marked as correctly detected only after the first true positive
|
324
|
+
is predicted within that segment. This encourages early detection by delaying credit for correct
|
325
|
+
predictions until the anomaly is initially detected. Additionally, to reduce the impact of
|
326
|
+
scattered false positives, predictions are subsampled using a sparsity factor n, so that
|
327
|
+
only one prediction is considered every n time steps. The adjusted predictions are then used
|
328
|
+
to compute the standard point-wise recall.
|
271
329
|
Implementation of https://dl.acm.org/doi/10.1145/3447548.3467174
|
272
330
|
|
273
331
|
Parameters:
|
@@ -289,6 +347,14 @@ def latency_sparsity_aw_recall(y_true: np.array, y_pred: np.array, ni: int):
|
|
289
347
|
def latency_sparsity_aw_precision(y_true: np.array, y_pred: np.array, ni: int):
|
290
348
|
"""
|
291
349
|
Calculate latency and sparsity aware precision for anomaly detection in time series.
|
350
|
+
This metric is based on the standard precision, but applies a temporal adjustment
|
351
|
+
to the predictions before computing it. Specifically, for each ground-truth anomalous segment,
|
352
|
+
all points in the segment are marked as correctly detected only after the first true positive
|
353
|
+
is predicted within that segment. This encourages early detection by delaying credit for correct
|
354
|
+
predictions until the anomaly is initially detected. Additionally, to reduce the impact of
|
355
|
+
scattered false positives, predictions are subsampled using a sparsity factor n, so that
|
356
|
+
only one prediction is considered every n time steps. The adjusted predictions are then used
|
357
|
+
to compute the standard point-wise precision.
|
292
358
|
Implementation of https://dl.acm.org/doi/10.1145/3447548.3467174
|
293
359
|
|
294
360
|
Parameters:
|
@@ -310,6 +376,15 @@ def latency_sparsity_aw_precision(y_true: np.array, y_pred: np.array, ni: int):
|
|
310
376
|
def latency_sparsity_aw_f_score(y_true: np.array, y_pred: np.array, ni: int, beta=1):
|
311
377
|
"""
|
312
378
|
Calculate latency and sparsity aware F-score for anomaly detection in time series.
|
379
|
+
This metric is based on the standard F-score, but applies a temporal adjustment
|
380
|
+
to the predictions before computing it. Specifically, for each ground-truth anomalous segment,
|
381
|
+
all points in the segment are marked as correctly detected only after the first true positive
|
382
|
+
is predicted within that segment. This encourages early detection by delaying credit for correct
|
383
|
+
predictions until the anomaly is initially detected. Additionally, to reduce the impact of
|
384
|
+
scattered false positives, predictions are subsampled using a sparsity factor n, so that
|
385
|
+
only one prediction is considered every n time steps. The adjusted predictions are then used
|
386
|
+
to compute the standard point-wise F-score.
|
387
|
+
|
313
388
|
Implementation of https://dl.acm.org/doi/10.1145/3447548.3467174
|
314
389
|
|
315
390
|
Parameters:
|
@@ -335,6 +410,14 @@ def latency_sparsity_aw_f_score(y_true: np.array, y_pred: np.array, ni: int, bet
|
|
335
410
|
def segment_wise_recall(y_true: np.array, y_pred: np.array):
|
336
411
|
"""
|
337
412
|
Calculate segment-wise recall for anomaly detection in time series.
|
413
|
+
This metric is based on the standard recall, but applies a temporal adjustment
|
414
|
+
to the predictions before computing it. Specifically, each contiguous segment of anomalous points
|
415
|
+
is treated as a single unit. A true positive is counted if at least one point in a ground-truth
|
416
|
+
anomalous segment is predicted as anomalous. A false negative is counted if no point in the segment
|
417
|
+
is detected, and a false positive is recorded for each predicted anomalous segment that does not
|
418
|
+
overlap with any ground-truth anomaly. The final recall is computed using these adjusted
|
419
|
+
segment-level counts.
|
420
|
+
|
338
421
|
Implementation of https://arxiv.org/pdf/1802.04431
|
339
422
|
|
340
423
|
Parameters:
|
@@ -344,7 +427,6 @@ def segment_wise_recall(y_true: np.array, y_pred: np.array):
|
|
344
427
|
Returns:
|
345
428
|
float: The segment-wise recall score, which is the ratio of true positives to the sum of true positives and false negatives.
|
346
429
|
"""
|
347
|
-
#TP, _, FN = get_tp_fp_fn_segment_wise(y_true, y_pred)
|
348
430
|
m = Segmentwise_metrics(len(y_true),y_true,y_pred)
|
349
431
|
TP,FN = m.tp,m.fn
|
350
432
|
if TP == 0:
|
@@ -354,6 +436,13 @@ def segment_wise_recall(y_true: np.array, y_pred: np.array):
|
|
354
436
|
def segment_wise_precision(y_true: np.array, y_pred: np.array):
|
355
437
|
"""
|
356
438
|
Calculate segment-wise precision for anomaly detection in time series.
|
439
|
+
This metric is based on the standard precision, but applies a temporal adjustment
|
440
|
+
to the predictions before computing it. Specifically, each contiguous segment of anomalous points
|
441
|
+
is treated as a single unit. A true positive is counted if at least one point in a ground-truth
|
442
|
+
anomalous segment is predicted as anomalous. A false negative is counted if no point in the segment
|
443
|
+
is detected, and a false positive is recorded for each predicted anomalous segment that does not
|
444
|
+
overlap with any ground-truth anomaly. The final precision is computed using these adjusted
|
445
|
+
segment-level counts.
|
357
446
|
Implementation of https://arxiv.org/pdf/1802.04431
|
358
447
|
|
359
448
|
Parameters:
|
@@ -363,7 +452,6 @@ def segment_wise_precision(y_true: np.array, y_pred: np.array):
|
|
363
452
|
Returns:
|
364
453
|
float: The segment-wise precision score, which is the ratio of true positives to the sum of true positives and false positives.
|
365
454
|
"""
|
366
|
-
#TP, FP, _ = get_tp_fp_fn_segment_wise(y_true, y_pred)
|
367
455
|
m = Segmentwise_metrics(len(y_true),y_true,y_pred)
|
368
456
|
TP,FP = m.tp,m.fp
|
369
457
|
if TP == 0:
|
@@ -373,6 +461,13 @@ def segment_wise_precision(y_true: np.array, y_pred: np.array):
|
|
373
461
|
def segment_wise_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
374
462
|
"""
|
375
463
|
Calculate segment-wise F-score for anomaly detection in time series.
|
464
|
+
This metric is based on the standard F-score, but applies a temporal adjustment
|
465
|
+
to the predictions before computing it. Specifically, each contiguous segment of anomalous points
|
466
|
+
is treated as a single unit. A true positive is counted if at least one point in a ground-truth
|
467
|
+
anomalous segment is predicted as anomalous. A false negative is counted if no point in the segment
|
468
|
+
is detected, and a false positive is recorded for each predicted anomalous segment that does not
|
469
|
+
overlap with any ground-truth anomaly. The final F-score is computed using these adjusted
|
470
|
+
segment-level counts.
|
376
471
|
Implementation of https://arxiv.org/pdf/1802.04431
|
377
472
|
|
378
473
|
Parameters:
|
@@ -400,6 +495,11 @@ def segment_wise_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
|
400
495
|
def composite_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
401
496
|
"""
|
402
497
|
Calculate composite F-score for anomaly detection in time series.
|
498
|
+
This metric combines aspects of the point_wise_f_score and the segment_wise_f_score.
|
499
|
+
It is defined as the harmonic mean of point_wise_precision and segment_wise_recall.
|
500
|
+
The use of point-wise precision ensures that false positives are properly penalized,
|
501
|
+
a feature that segment-wise metrics typically lack.
|
502
|
+
|
403
503
|
Implementation of https://ieeexplore.ieee.org/document/9525836
|
404
504
|
|
405
505
|
Parameters:
|
@@ -414,10 +514,10 @@ def composite_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
|
414
514
|
"""
|
415
515
|
m = Composite_f(len(y_true),y_true,y_pred)
|
416
516
|
#Point wise precision
|
417
|
-
precision = m.precision()
|
517
|
+
precision = m.precision()
|
418
518
|
|
419
519
|
#Segment wise recall
|
420
|
-
recall = m.recall()
|
520
|
+
recall = m.recall()
|
421
521
|
|
422
522
|
if precision==0 or recall==0:
|
423
523
|
return 0
|
@@ -427,6 +527,12 @@ def composite_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
|
427
527
|
def time_tolerant_recall(y_true: np.array, y_pred: np.array, t: int) -> float:
|
428
528
|
"""
|
429
529
|
Calculate time tolerant recall for anomaly detection in time series.
|
530
|
+
This metric is based on the standard recall, but applies a temporal adjustment
|
531
|
+
to the predictions before computing it. Specifically, a predicted anomalous point is considered
|
532
|
+
a true positive if it lies within a temporal window of size τ around any ground-truth anomalous point.
|
533
|
+
This allows for small temporal deviations in the predictions to be tolerated. The adjusted predictions are then used
|
534
|
+
to compute the standard point-wise recall.
|
535
|
+
|
430
536
|
Implementation of https://arxiv.org/pdf/1802.04431
|
431
537
|
|
432
538
|
Parameters:
|
@@ -446,6 +552,12 @@ def time_tolerant_recall(y_true: np.array, y_pred: np.array, t: int) -> float:
|
|
446
552
|
def time_tolerant_precision(y_true: np.array, y_pred: np.array, t: int) -> float:
|
447
553
|
"""
|
448
554
|
Calculate time tolerant precision for anomaly detection in time series.
|
555
|
+
This metric is based on the standard precision, but applies a temporal adjustment
|
556
|
+
to the predictions before computing it. Specifically, a predicted anomalous point is considered
|
557
|
+
a true positive if it lies within a temporal window of size τ around any ground-truth anomalous point.
|
558
|
+
This allows for small temporal deviations in the predictions to be tolerated. The adjusted predictions are then used
|
559
|
+
to compute the standard point-wise precision.
|
560
|
+
|
449
561
|
Implementation of https://arxiv.org/pdf/1802.04431
|
450
562
|
|
451
563
|
Parameters:
|
@@ -462,9 +574,15 @@ def time_tolerant_precision(y_true: np.array, y_pred: np.array, t: int) -> float
|
|
462
574
|
return m.precision()
|
463
575
|
|
464
576
|
|
465
|
-
def time_tolerant_f_score(y_true: np.array, y_pred: np.array,t: int, beta=1):
|
577
|
+
def time_tolerant_f_score(y_true: np.array, y_pred: np.array, t: int, beta=1):
|
466
578
|
"""
|
467
579
|
Calculate time tolerant F-score for anomaly detection in time series.
|
580
|
+
This metric is based on the standard F-score, but applies a temporal adjustment
|
581
|
+
to the predictions before computing it. Specifically, a predicted anomalous point is considered
|
582
|
+
a true positive if it lies within a temporal window of size τ around any ground-truth anomalous point.
|
583
|
+
This allows for small temporal deviations in the predictions to be tolerated.The adjusted predictions are then used
|
584
|
+
to compute the standard point-wise F-Score.
|
585
|
+
|
468
586
|
Implementation of https://arxiv.org/pdf/1802.04431
|
469
587
|
|
470
588
|
Parameters:
|
@@ -488,13 +606,23 @@ def time_tolerant_f_score(y_true: np.array, y_pred: np.array,t: int, beta=1):
|
|
488
606
|
def range_based_recall(y_true: np.array, y_pred: np.array, alpha: float, bias='flat', cardinality_mode='one'):
|
489
607
|
"""
|
490
608
|
Calculate range-based recall for anomaly detection in time series.
|
491
|
-
|
609
|
+
|
610
|
+
This metric extends standard recall by evaluating detection at the level of anomalous ranges
|
611
|
+
rather than individual points. For each true anomaly range, it computes a score that rewards
|
612
|
+
(1) detecting the existence of the range, (2) the proportion of overlap, and (3) penalties or
|
613
|
+
bonuses based on the position and fragmentation of predicted segments. These components are
|
614
|
+
weighted by α (existence vs. overlap) and further shaped by customizable bias functions
|
615
|
+
for positional and cardinality factors.
|
616
|
+
|
617
|
+
For more information, see the original paper:
|
618
|
+
https://proceedings.neurips.cc/paper_files/paper/2018/file/8f468c873a32bb0619eaeb2050ba45d1-Paper.pdf
|
619
|
+
|
492
620
|
Parameters:
|
493
621
|
y_true (np.array): The ground truth binary labels for the time series data.
|
494
622
|
y_pred (np.array): The predicted binary labels for the time series data.
|
495
|
-
alpha (float):
|
496
|
-
bias (str):
|
497
|
-
|
623
|
+
alpha (float): Relative importance of existence reward. 0 ≤ alpha ≤ 1.
|
624
|
+
bias (str): Positional bias. This should be "flat", "front", "middle", or "back".
|
625
|
+
cardinality_mode (str, optional): Cardinality type. This should be "one", "reciprocal" or "udf_gamma".
|
498
626
|
|
499
627
|
Returns:
|
500
628
|
float: The range-based recall score.
|
@@ -509,13 +637,21 @@ def range_based_recall(y_true: np.array, y_pred: np.array, alpha: float, bias='f
|
|
509
637
|
def range_based_precision(y_true: np.array, y_pred: np.array, alpha: float, bias='flat', cardinality_mode='one'):
|
510
638
|
"""
|
511
639
|
Calculate range-based precision for anomaly detection in time series.
|
640
|
+
|
641
|
+
This metric extends standard precision by scoring predictions at the range level. Each
|
642
|
+
predicted anomaly range is evaluated for (1) overlap with any true ranges, (2) the size of
|
643
|
+
that overlap, and (3) positional and fragmentation effects via bias functions. Cardinality
|
644
|
+
penalties can be applied when a single true range is covered by multiple predicted ranges.
|
645
|
+
|
646
|
+
For more information, see the original paper:
|
647
|
+
https://proceedings.neurips.cc/paper_files/paper/2018/file/8f468c873a32bb0619eaeb2050ba45d1-Paper.pdf
|
512
648
|
|
513
649
|
Parameters:
|
514
650
|
y_true (np.array): The ground truth binary labels for the time series data.
|
515
651
|
y_pred (np.array): The predicted binary labels for the time series data.
|
516
|
-
alpha (float):
|
517
|
-
bias (str):
|
518
|
-
|
652
|
+
alpha (float): Relative importance of existence reward. 0 ≤ alpha ≤ 1.
|
653
|
+
bias (str): Positional bias. This should be "flat", "front", "middle", or "back".
|
654
|
+
cardinality_mode (str, optional): Cardinality type. This should be "one", "reciprocal" or "udf_gamma".
|
519
655
|
|
520
656
|
Returns:
|
521
657
|
float: The range-based precision score.
|
@@ -534,15 +670,22 @@ def range_based_f_score(y_true: np.array, y_pred: np.array, p_alpha: float, r_al
|
|
534
670
|
"""
|
535
671
|
Calculate range-based F-score for anomaly detection in time series.
|
536
672
|
|
673
|
+
This metric combines range-based precision and range-based recall into a single harmonic mean.
|
674
|
+
It inherits all customizability of the underlying precision and recall—existence vs. overlap
|
675
|
+
weighting, positional bias, and cardinality factors—allowing fine-grained control over how
|
676
|
+
both missed detections and false alarms are penalized in a temporal context.
|
677
|
+
|
678
|
+
For more information, see the original paper:
|
679
|
+
https://proceedings.neurips.cc/paper_files/paper/2018/file/8f468c873a32bb0619eaeb2050ba45d1-Paper.pdf
|
680
|
+
|
681
|
+
|
537
682
|
Parameters:
|
538
683
|
y_true (np.array): The ground truth binary labels for the time series data.
|
539
684
|
y_pred (np.array): The predicted binary labels for the time series data.
|
540
|
-
alpha (float):
|
541
|
-
p_bias:
|
542
|
-
|
543
|
-
|
544
|
-
Positional bias for recall. This should be "flat", "front", "middle", or "back"
|
545
|
-
cardinality_mode (str, optional): ["one", "reciprocal", "udf_gamma"]. Defaults to "one".
|
685
|
+
alpha (float): Relative importance of existence reward. 0 ≤ alpha ≤ 1.
|
686
|
+
p_bias (str): Positional bias for precision. This should be "flat", "front", "middle", or "back".
|
687
|
+
r_bias (str): Positional bias for recall. This should be "flat", "front", "middle", or "back".
|
688
|
+
cardinality_mode (str, optional): Cardinality type. This should be "one", "reciprocal" or "udf_gamma".
|
546
689
|
beta (float): The beta value, which determines the weight of precision in the combined score.
|
547
690
|
Default is 1, which gives equal weight to precision and recall.
|
548
691
|
|
@@ -561,11 +704,27 @@ def ts_aware_recall(y_true: np.array, y_pred: np.array, alpha: float, delta: flo
|
|
561
704
|
"""
|
562
705
|
Calculate time series aware recall for anomaly detection in time series.
|
563
706
|
|
707
|
+
This metric is based on the range_based_recall, but introduces two key modifications.
|
708
|
+
First, a predicted anomalous segment is only counted as a true positive if it covers at least a fraction
|
709
|
+
θ of the ground‑truth anomaly range. Second, each labeled anomaly is extended by a tolerance window of
|
710
|
+
length δ at its end, within which any overlap contribution decays linearly from full weight down to zero.
|
711
|
+
Unlike the original range-based formulation, this variant omits cardinality and positional bias terms,
|
712
|
+
focusing solely on overlap fraction and end‑tolerance decay.
|
713
|
+
|
564
714
|
Parameters:
|
565
715
|
y_true (np.array): The ground truth binary labels for the time series data.
|
566
716
|
y_pred (np.array): The predicted binary labels for the time series data.
|
567
|
-
alpha (float):
|
568
|
-
|
717
|
+
alpha (float): Relative importance of the existence reward versus overlap reward (0 ≤ α ≤ 1).
|
718
|
+
delta (float): Tolerance window length at the end of each true anomaly segment.
|
719
|
+
- If past_range is True, δ must be a float in (0, 1], representing the fraction of the segment’s
|
720
|
+
length to extend. E.g., δ = 0.5 extends a segment of length 10 by 5 time steps.
|
721
|
+
- If past_range is False, δ must be a non-negative integer, representing an absolute number of
|
722
|
+
time steps to extend each segment.
|
723
|
+
theta (float): Minimum fraction (0 ≤ θ ≤ 1) of the true anomaly range that must be overlapped by
|
724
|
+
predictions for the segment to count as detected.
|
725
|
+
past_range (bool): Determines how δ is interpreted.
|
726
|
+
- True: δ is treated as a fractional extension of each segment’s length.
|
727
|
+
- False: δ is treated as an absolute number of time steps.
|
569
728
|
|
570
729
|
Returns:
|
571
730
|
float: The time series aware recall score.
|
@@ -579,12 +738,28 @@ def ts_aware_recall(y_true: np.array, y_pred: np.array, alpha: float, delta: flo
|
|
579
738
|
def ts_aware_precision(y_true: np.array, y_pred: np.array,alpha: float, delta: float, theta: float, past_range: bool = False):
|
580
739
|
"""
|
581
740
|
Calculate time series aware precision for anomaly detection in time series.
|
741
|
+
|
742
|
+
This metric is based on the range_based_precision, but introduces two key modifications.
|
743
|
+
First, a predicted anomalous segment is only counted as a true positive if it covers at least a fraction
|
744
|
+
θ of the ground‑truth anomaly range. Second, each labeled anomaly is extended by a tolerance window of
|
745
|
+
length δ at its end, within which any overlap contribution decays linearly from full weight down to zero.
|
746
|
+
Unlike the original range-based formulation, this variant omits cardinality and positional bias terms,
|
747
|
+
focusing solely on overlap fraction and end‑tolerance decay.
|
582
748
|
|
583
749
|
Parameters:
|
584
750
|
y_true (np.array): The ground truth binary labels for the time series data.
|
585
751
|
y_pred (np.array): The predicted binary labels for the time series data.
|
586
|
-
alpha (float):
|
587
|
-
|
752
|
+
alpha (float): Relative importance of the existence reward versus overlap reward (0 ≤ α ≤ 1).
|
753
|
+
delta (float): Tolerance window length at the end of each true anomaly segment.
|
754
|
+
- If past_range is True, δ must be a float in (0, 1], representing the fraction of the segment’s
|
755
|
+
length to extend. E.g., δ = 0.5 extends a segment of length 10 by 5 time steps.
|
756
|
+
- If past_range is False, δ must be a non-negative integer, representing an absolute number of
|
757
|
+
time steps to extend each segment.
|
758
|
+
theta (float): Minimum fraction (0 ≤ θ ≤ 1) of the true anomaly range that must be overlapped by
|
759
|
+
predictions for the segment to count as detected.
|
760
|
+
past_range (bool): Determines how δ is interpreted.
|
761
|
+
- True: δ is treated as a fractional extension of each segment’s length.
|
762
|
+
- False: δ is treated as an absolute number of time steps.
|
588
763
|
|
589
764
|
Returns:
|
590
765
|
float: The time series aware precision score.
|
@@ -600,13 +775,27 @@ def ts_aware_f_score(y_true: np.array, y_pred: np.array, beta: float, alpha: flo
|
|
600
775
|
"""
|
601
776
|
Calculate time series aware F-score for anomaly detection in time series.
|
602
777
|
|
778
|
+
This metric is based on the range_based_f_score, but introduces two key modifications.
|
779
|
+
First, a predicted anomalous segment is only counted as a true positive if it covers at least a fraction
|
780
|
+
θ of the ground‑truth anomaly range. Second, each labeled anomaly is extended by a tolerance window of
|
781
|
+
length δ at its end, within which any overlap contribution decays linearly from full weight down to zero.
|
782
|
+
Unlike the original range-based formulation, this variant omits cardinality and positional bias terms,
|
783
|
+
focusing solely on overlap fraction and end‑tolerance decay.
|
784
|
+
|
603
785
|
Parameters:
|
604
786
|
y_true (np.array): The ground truth binary labels for the time series data.
|
605
787
|
y_pred (np.array): The predicted binary labels for the time series data.
|
606
|
-
alpha (float):
|
607
|
-
|
608
|
-
|
609
|
-
|
788
|
+
alpha (float): Relative importance of the existence reward versus overlap reward (0 ≤ α ≤ 1).
|
789
|
+
delta (float): Tolerance window length at the end of each true anomaly segment.
|
790
|
+
- If past_range is True, δ must be a float in (0, 1], representing the fraction of the segment’s
|
791
|
+
length to extend. E.g., δ = 0.5 extends a segment of length 10 by 5 time steps.
|
792
|
+
- If past_range is False, δ must be a non-negative integer, representing an absolute number of
|
793
|
+
time steps to extend each segment.
|
794
|
+
theta (float): Minimum fraction (0 ≤ θ ≤ 1) of the true anomaly range that must be overlapped by
|
795
|
+
predictions for the segment to count as detected.
|
796
|
+
past_range (bool): Determines how δ is interpreted.
|
797
|
+
- True: δ is treated as a fractional extension of each segment’s length.
|
798
|
+
- False: δ is treated as an absolute number of time steps.
|
610
799
|
|
611
800
|
Returns:
|
612
801
|
float: The time series aware F-score, which is the harmonic mean of precision and recall, adjusted by the beta value.
|
@@ -628,10 +817,17 @@ def enhanced_ts_aware_recall(y_true: np.array, y_pred: np.array, theta: float):
|
|
628
817
|
"""
|
629
818
|
Calculate enhanced time series aware recall for anomaly detection in time series.
|
630
819
|
|
820
|
+
This metric is similar to the range-based recall in that it accounts for both detection existence
|
821
|
+
and overlap proportion. Additionally, it requires that a significant fraction θ of each true anomaly
|
822
|
+
segment be detected, and that a significant fraction γ of each predicted segment overlaps with the
|
823
|
+
ground truth. Finally, recall contributions from each event are weighted by the square root of the
|
824
|
+
true segment’s length, providing a compromise between point-wise and segment-wise approaches.
|
825
|
+
|
631
826
|
Parameters:
|
632
827
|
y_true (np.array): The ground truth binary labels for the time series data.
|
633
828
|
y_pred (np.array): The predicted binary labels for the time series data.
|
634
|
-
|
829
|
+
theta (float): Minimum fraction (0 ≤ θ ≤ 1) of a true segment that must be overlapped
|
830
|
+
by predictions to count as detected.
|
635
831
|
|
636
832
|
Returns:
|
637
833
|
float: The time series aware recall score.
|
@@ -648,10 +844,17 @@ def enhanced_ts_aware_precision(y_true: np.array, y_pred: np.array, theta: float
|
|
648
844
|
"""
|
649
845
|
Calculate enhanced time series aware precision for anomaly detection in time series.
|
650
846
|
|
847
|
+
This metric is similar to the range-based precision in that it accounts for both detection existence
|
848
|
+
and overlap proportion. Additionally, it requires that a significant fraction θ of each true anomaly
|
849
|
+
segment be detected, and that a significant fraction γ of each predicted segment overlaps with the
|
850
|
+
ground truth. Finally, precision contributions from each event are weighted by the square root of the
|
851
|
+
true segment’s length, providing a compromise between point-wise and segment-wise approaches.
|
852
|
+
|
651
853
|
Parameters:
|
652
854
|
y_true (np.array): The ground truth binary labels for the time series data.
|
653
855
|
y_pred (np.array): The predicted binary labels for the time series data.
|
654
|
-
|
856
|
+
theta (float): Minimum fraction (0 ≤ θ ≤ 1) of a true segment that must be overlapped
|
857
|
+
by predictions to count as detected.
|
655
858
|
|
656
859
|
Returns:
|
657
860
|
float: The time series aware precision score.
|
@@ -665,15 +868,21 @@ def enhanced_ts_aware_precision(y_true: np.array, y_pred: np.array, theta: float
|
|
665
868
|
|
666
869
|
|
667
870
|
|
668
|
-
def enhanced_ts_aware_f_score(y_true: np.array, y_pred: np.array,
|
871
|
+
def enhanced_ts_aware_f_score(y_true: np.array, y_pred: np.array, theta_p: float, theta_r: float):
|
669
872
|
"""
|
670
873
|
Calculate enhanced time series aware F-score for anomaly detection in time series.
|
874
|
+
|
875
|
+
This metric is similar to the range-based F-score in that it accounts for both detection existence
|
876
|
+
and overlap proportion. Additionally, it requires that a significant fraction θ of each true anomaly
|
877
|
+
segment be detected, and that a significant fraction γ of each predicted segment overlaps with the
|
878
|
+
ground truth. Finally, F-score contributions from each event are weighted by the square root of the
|
879
|
+
true segment’s length, providing a compromise between point-wise and segment-wise approaches.
|
671
880
|
|
672
881
|
Parameters:
|
673
882
|
y_true (np.array): The ground truth binary labels for the time series data.
|
674
883
|
y_pred (np.array): The predicted binary labels for the time series data.
|
675
|
-
|
676
|
-
|
884
|
+
theta (float): Minimum fraction (0 ≤ θ ≤ 1) of a true segment that must be overlapped
|
885
|
+
by predictions to count as detected.
|
677
886
|
|
678
887
|
Returns:
|
679
888
|
float: The time series aware F-score, which is the harmonic mean of precision and recall, adjusted by the beta value.
|
@@ -689,14 +898,16 @@ def affiliation_based_recall(y_true: np.array, y_pred: np.array):
|
|
689
898
|
"""
|
690
899
|
Calculate affiliation based recall for anomaly detection in time series.
|
691
900
|
|
901
|
+
This metric evaluates how well each labeled anomaly is affiliated with predicted points.
|
902
|
+
It computes the average distance from each ground truth anomaly point to the nearest
|
903
|
+
predicted anomaly point.
|
904
|
+
|
692
905
|
Parameters:
|
693
906
|
y_true (np.array): The ground truth binary labels for the time series data.
|
694
907
|
y_pred (np.array): The predicted binary labels for the time series data.
|
695
|
-
beta (float): The beta value, which determines the weight of precision in the combined score.
|
696
|
-
Default is 1, which gives equal weight to precision and recall.
|
697
908
|
|
698
909
|
Returns:
|
699
|
-
float: The
|
910
|
+
float: The affiliation based recall score.
|
700
911
|
"""
|
701
912
|
if np.sum(y_pred) == 0:
|
702
913
|
return 0
|
@@ -709,14 +920,17 @@ def affiliation_based_precision(y_true: np.array, y_pred: np.array):
|
|
709
920
|
"""
|
710
921
|
Calculate affiliation based F-score for anomaly detection in time series.
|
711
922
|
|
923
|
+
This metric evaluates how well each predicted anomaly is affiliated with labeled points.
|
924
|
+
It computes the average distance from each predicted anomaly point to the nearest
|
925
|
+
ground truth anomaly point.
|
926
|
+
|
712
927
|
Parameters:
|
713
928
|
y_true (np.array): The ground truth binary labels for the time series data.
|
714
929
|
y_pred (np.array): The predicted binary labels for the time series data.
|
715
|
-
|
716
|
-
Default is 1, which gives equal weight to precision and recall.
|
930
|
+
|
717
931
|
|
718
932
|
Returns:
|
719
|
-
float: The
|
933
|
+
float: The affiliation based precision score.
|
720
934
|
"""
|
721
935
|
if np.sum(y_pred) == 0:
|
722
936
|
return 0
|
@@ -729,14 +943,20 @@ def affiliation_based_f_score(y_true: np.array, y_pred: np.array, beta=1):
|
|
729
943
|
"""
|
730
944
|
Calculate affiliation based F-score for anomaly detection in time series.
|
731
945
|
|
946
|
+
This metric combines the affiliation-based precision and recall into a single score
|
947
|
+
using the harmonic mean, adjusted by a weight β to control the relative importance
|
948
|
+
of recall versus precision. Since both precision and recall are distance-based,
|
949
|
+
the F-score reflects a balance between how well predicted anomalies align with true
|
950
|
+
anomalies and vice versa.
|
951
|
+
|
732
952
|
Parameters:
|
733
953
|
y_true (np.array): The ground truth binary labels for the time series data.
|
734
954
|
y_pred (np.array): The predicted binary labels for the time series data.
|
735
955
|
beta (float): The beta value, which determines the weight of precision in the combined score.
|
736
|
-
|
956
|
+
|
737
957
|
|
738
958
|
Returns:
|
739
|
-
float: The
|
959
|
+
float: The affiliation based F-score.
|
740
960
|
"""
|
741
961
|
if np.sum(y_pred) == 0:
|
742
962
|
return 0
|
@@ -748,13 +968,18 @@ def nab_score(y_true: np.array, y_pred: np.array):
|
|
748
968
|
"""
|
749
969
|
Calculate NAB score for anomaly detection in time series.
|
750
970
|
|
971
|
+
This metric rewards early and accurate detections of anomalies while penalizing false positives.
|
972
|
+
For each ground truth anomaly segment, only the first correctly predicted anomaly point contributes
|
973
|
+
positively to the score, with earlier detections receiving higher rewards. In contrast, every false
|
974
|
+
positive prediction contributes negatively.
|
975
|
+
|
751
976
|
Parameters:
|
752
977
|
y_true (np.array): The ground truth binary labels for the time series data.
|
753
978
|
y_pred (np.array): The predicted binary labels for the time series data.
|
754
979
|
|
755
980
|
|
756
981
|
Returns:
|
757
|
-
float: The nab score
|
982
|
+
float: The nab score.
|
758
983
|
"""
|
759
984
|
|
760
985
|
m = NAB_score(len(y_true),y_true,y_pred)
|
@@ -764,6 +989,11 @@ def temporal_distance(y_true: np.array, y_pred: np.array, distance: int = 0):
|
|
764
989
|
"""
|
765
990
|
Calculate temporal distane for anomaly detection in time series.
|
766
991
|
|
992
|
+
This metric computes the sum of the distances from each labelled anomaly point to
|
993
|
+
the closest predicted anomaly point, and from each predicted anomaly point to the
|
994
|
+
closest labelled anomaly point.
|
995
|
+
|
996
|
+
|
767
997
|
Parameters:
|
768
998
|
y_true (np.array): The ground truth binary labels for the time series data.
|
769
999
|
y_pred (np.array): The predicted binary labels for the time series data.
|
@@ -773,7 +1003,7 @@ def temporal_distance(y_true: np.array, y_pred: np.array, distance: int = 0):
|
|
773
1003
|
|
774
1004
|
|
775
1005
|
Returns:
|
776
|
-
float: The temporal distance
|
1006
|
+
float: The temporal distance.
|
777
1007
|
"""
|
778
1008
|
|
779
1009
|
m = Temporal_Distance(len(y_true),y_true,y_pred,distance=distance)
|
@@ -783,13 +1013,20 @@ def average_detection_count(y_true: np.array, y_pred: np.array):
|
|
783
1013
|
"""
|
784
1014
|
Calculate average detection count for anomaly detection in time series.
|
785
1015
|
|
1016
|
+
This metric computes, for each ground-truth anomalous segment, how many points within that segment
|
1017
|
+
are predicted as anomalous. It then averages these counts across all true anomaly events,
|
1018
|
+
providing an estimate of detection coverage per event.
|
1019
|
+
|
1020
|
+
For more information, see the original paper:
|
1021
|
+
https://ceur-ws.org/Vol-1226/paper31.pdf
|
1022
|
+
|
786
1023
|
Parameters:
|
787
1024
|
y_true (np.array): The ground truth binary labels for the time series data.
|
788
1025
|
y_pred (np.array): The predicted binary labels for the time series data.
|
789
1026
|
|
790
1027
|
|
791
1028
|
Returns:
|
792
|
-
float: The average detection count.
|
1029
|
+
float: The average detection count score.
|
793
1030
|
"""
|
794
1031
|
|
795
1032
|
b = Binary_detection(len(y_true),y_true,y_pred)
|
@@ -810,10 +1047,17 @@ def absolute_detection_distance(y_true: np.array, y_pred: np.array):
|
|
810
1047
|
"""
|
811
1048
|
Calculate absolute detection distance for anomaly detection in time series.
|
812
1049
|
|
1050
|
+
This metric computes, for each predicted anomaly point that overlaps a ground-truth anomaly segment,
|
1051
|
+
the distance from that point to the temporal center of the corresponding segment. It then sums all
|
1052
|
+
those distances and divides by the total number of such matching predicted points, yielding the
|
1053
|
+
mean distance to segment centers for correctly detected points.
|
1054
|
+
|
813
1055
|
Parameters:
|
814
1056
|
y_true (np.array): The ground truth binary labels for the time series data.
|
815
1057
|
y_pred (np.array): The predicted binary labels for the time series data.
|
816
1058
|
|
1059
|
+
For more information, see the original paper:
|
1060
|
+
https://ceur-ws.org/Vol-1226/paper31.pdf
|
817
1061
|
|
818
1062
|
Returns:
|
819
1063
|
float: The absolute detection distance.
|
@@ -837,13 +1081,28 @@ def total_detected_in_range(y_true: np.array, y_pred: np.array, k: int):
|
|
837
1081
|
"""
|
838
1082
|
Calculate total detected in range for anomaly detection in time series.
|
839
1083
|
|
1084
|
+
This metric measures the proportion of true anomaly events that are correctly detected.
|
1085
|
+
It is defined as:
|
1086
|
+
TDIR = (EM + DA) / (EM + DA + MA)
|
1087
|
+
|
1088
|
+
Where:
|
1089
|
+
EM (Exact Match) = number of predicted anomaly segments that exactly match a true anomaly segment.
|
1090
|
+
DA (Detected Anomaly)= number of true anomaly points not exactly matched where at least one prediction falls
|
1091
|
+
within a window [i-k, i+k] around the true point index i or within the true segment range.
|
1092
|
+
FA (False Anomaly) = number of predicted anomaly segments that do not overlap any true anomaly segment
|
1093
|
+
even within a k-step tolerance window around true points.
|
1094
|
+
|
1095
|
+
For more information, see the original paper:
|
1096
|
+
https://acta.sapientia.ro/content/docs/evaluation-metrics-for-anomaly-detection.pdf
|
1097
|
+
|
840
1098
|
Parameters:
|
841
1099
|
y_true (np.array): The ground truth binary labels for the time series data.
|
842
1100
|
y_pred (np.array): The predicted binary labels for the time series data.
|
843
|
-
k (int):
|
1101
|
+
k (int): Half-window size for tolerance around each true anomaly point. A prediction within k
|
1102
|
+
time steps of a true point counts toward detection.
|
844
1103
|
|
845
1104
|
Returns:
|
846
|
-
float: The total detected in range.
|
1105
|
+
float: The total detected in range score.
|
847
1106
|
"""
|
848
1107
|
if np.sum(y_pred) == 0:
|
849
1108
|
return 0
|
@@ -857,10 +1116,25 @@ def detection_accuracy_in_range(y_true: np.array, y_pred: np.array, k: int):
|
|
857
1116
|
"""
|
858
1117
|
Calculate detection accuracy in range for anomaly detection in time series.
|
859
1118
|
|
1119
|
+
This metric measures the proportion of predicted anomaly events that correspond to true anomalies.
|
1120
|
+
It is defined as:
|
1121
|
+
DAIR = (EM + DA) / (EM + DA + FA)
|
1122
|
+
|
1123
|
+
Where:
|
1124
|
+
EM (Exact Match) = number of predicted anomaly segments that exactly match a true anomaly segment.
|
1125
|
+
DA (Detected Anomaly)= number of true anomaly points not exactly matched where at least one prediction falls
|
1126
|
+
within a window [i-k, i+k] around the true point index i or within the true segment range.
|
1127
|
+
FA (False Anomaly) = number of predicted anomaly segments that do not overlap any true anomaly segment
|
1128
|
+
even within a k-step tolerance window around true points.
|
1129
|
+
|
1130
|
+
For more information, see the original paper:
|
1131
|
+
https://acta.sapientia.ro/content/docs/evaluation-metrics-for-anomaly-detection.pdf
|
1132
|
+
|
860
1133
|
Parameters:
|
861
1134
|
y_true (np.array): The ground truth binary labels for the time series data.
|
862
1135
|
y_pred (np.array): The predicted binary labels for the time series data.
|
863
|
-
k (int):
|
1136
|
+
k (int): Half-window size for tolerance around each true anomaly point. A prediction within k
|
1137
|
+
time steps of a true point counts toward detection.
|
864
1138
|
|
865
1139
|
Returns:
|
866
1140
|
float: The total detected in range.
|
@@ -876,7 +1150,28 @@ def detection_accuracy_in_range(y_true: np.array, y_pred: np.array, k: int):
|
|
876
1150
|
def weighted_detection_difference(y_true: np.array, y_pred: np.array, k: int):
|
877
1151
|
"""
|
878
1152
|
Calculate weighted detection difference for anomaly detection in time series.
|
879
|
-
|
1153
|
+
|
1154
|
+
For each true anomaly segment, each point in the segment is assigned a weight based on a
|
1155
|
+
Gaussian function centered at the segment’s midpoint: points closer to the center receive higher
|
1156
|
+
weights, which decay with distance according to the standard deviation sigma. These weights form
|
1157
|
+
the basis for scoring both correct detections and false alarms.
|
1158
|
+
|
1159
|
+
WS (Weighted Sum) is defined as the sum of Gaussian weights for all predicted anomaly points that
|
1160
|
+
fall within any true anomaly segment (extended by delta time steps at the ends).
|
1161
|
+
WF (False Alarm Weight) is the sum of Gaussian weights for all predicted anomaly points that do
|
1162
|
+
not overlap any true anomaly segment (within the same extension).
|
1163
|
+
|
1164
|
+
The final score is:
|
1165
|
+
WDD = WS - WF*FA
|
1166
|
+
|
1167
|
+
Where:
|
1168
|
+
WS = Σ weights_true_predictions
|
1169
|
+
WF = Σ weights_false_positives
|
1170
|
+
FA (False Anomaly) = number of predicted anomaly segments that do not overlap any true anomaly segment
|
1171
|
+
even within a k-step tolerance window around true points.
|
1172
|
+
|
1173
|
+
For more information, see the original paper:
|
1174
|
+
https://acta.sapientia.ro/content/docs/evaluation-metrics-for-anomaly-detection.pdf
|
880
1175
|
|
881
1176
|
Parameters:
|
882
1177
|
y_true (np.array): The ground truth binary labels for the time series data.
|
@@ -923,7 +1218,17 @@ def weighted_detection_difference(y_true: np.array, y_pred: np.array, k: int):
|
|
923
1218
|
def binary_pate(y_true: np.array, y_pred: np.array, early: int, delay: int):
|
924
1219
|
"""
|
925
1220
|
Calculate PATE score for anomaly detection in time series.
|
926
|
-
|
1221
|
+
|
1222
|
+
PATE evaluates predictions by assigning weighted scores based on temporal proximity
|
1223
|
+
to true anomaly intervals. It uses buffer zones around each true anomaly: an early buffer of length
|
1224
|
+
`early` preceding the interval and a delay buffer of length `delay` following it. Detections within
|
1225
|
+
the true interval receive full weight, while those in the early or delay buffers receive linearly
|
1226
|
+
decaying weights based on distance from the interval edges. Predictions outside these zones are
|
1227
|
+
treated as false positives, and missed intervals as false negatives. The final score balances these
|
1228
|
+
weighted detections into a single measure of performance.
|
1229
|
+
|
1230
|
+
For more information, see the original paper:
|
1231
|
+
https://arxiv.org/abs/2405.12096
|
927
1232
|
|
928
1233
|
Parameters:
|
929
1234
|
y_true (np.array): The ground truth binary labels for the time series data.
|
@@ -940,12 +1245,22 @@ def binary_pate(y_true: np.array, y_pred: np.array, early: int, delay: int):
|
|
940
1245
|
def mean_time_to_detect(y_true: np.array, y_pred: np.array):
|
941
1246
|
"""
|
942
1247
|
Calculate mean time to detect for anomaly detection in time series.
|
943
|
-
|
1248
|
+
|
1249
|
+
This metric quantifies the average detection delay across all true anomaly events.
|
1250
|
+
For each ground-truth anomaly segment, let i be the index where the segment starts,
|
1251
|
+
and let j ≥ i be the first index within that segment where the model predicts an anomaly.
|
1252
|
+
The detection delay for that event is defined as:
|
1253
|
+
Δ = j - i
|
1254
|
+
The MTTD is the mean of all such Δ values, one per true anomaly segment, and expresses
|
1255
|
+
the average number of time steps between the true onset of an anomaly and its first detection.
|
944
1256
|
|
945
1257
|
Parameters:
|
946
1258
|
y_true (np.array): The ground truth binary labels for the time series data.
|
947
1259
|
y_pred (np.array): The predicted binary labels for the time series data.
|
948
1260
|
|
1261
|
+
For more information, see the original paper:
|
1262
|
+
https://arxiv.org/pdf/2211.05244
|
1263
|
+
|
949
1264
|
Returns:
|
950
1265
|
float: The mean time to detect.
|
951
1266
|
"""
|
@@ -953,10 +1268,10 @@ def mean_time_to_detect(y_true: np.array, y_pred: np.array):
|
|
953
1268
|
b = Binary_detection(len(y_true),y_true,y_pred)
|
954
1269
|
a_events = b.get_gt_anomalies_segmentwise()
|
955
1270
|
t_sum = 0
|
956
|
-
for _
|
957
|
-
for i in range(
|
1271
|
+
for a,_ in a_events:
|
1272
|
+
for i in range(a,len(y_pred)):
|
958
1273
|
if y_pred[i] == 1:
|
959
|
-
t_sum+=i-
|
1274
|
+
t_sum+=i-a
|
960
1275
|
break
|
961
1276
|
|
962
1277
|
return t_sum/len(a_events)
|
tsadmetrics/metric_utils.py
CHANGED
@@ -262,16 +262,29 @@ def transform_to_full_series(length: int, anomalies: np.array):
|
|
262
262
|
|
263
263
|
def counting_method(y_true: np.array, y_pred: np.array, k: int):
|
264
264
|
em,da,ma,fa = 0,0,0,0
|
265
|
-
for
|
265
|
+
for i_gt in range(len(y_true)):
|
266
|
+
i_pa = i_gt
|
267
|
+
gt = y_true[i_gt]
|
268
|
+
pa = y_pred[i_pa]
|
266
269
|
if gt==1 and pa==1:
|
267
270
|
em+=1
|
268
271
|
elif gt==0 and pa==1:
|
269
272
|
fa+=1
|
270
|
-
|
273
|
+
elif gt==1 and pa==0:
|
274
|
+
anom_range = y_pred[i_gt-k:i_pa+k+1]
|
275
|
+
detected = False
|
276
|
+
for r in anom_range:
|
277
|
+
if r==1:
|
278
|
+
em+=1
|
279
|
+
detected=True
|
280
|
+
break
|
281
|
+
if not detected:
|
282
|
+
ma+=1
|
283
|
+
elif gt==0 and pa==0:
|
271
284
|
pass
|
272
|
-
b = DelayThresholdedPointAdjust(len(y_true),y_true,y_pred,k=k)
|
273
|
-
da = b.tp-em
|
274
|
-
ma = b.fn
|
285
|
+
# b = DelayThresholdedPointAdjust(len(y_true),y_true,y_pred,k=k)
|
286
|
+
# da = b.tp-em
|
287
|
+
# ma = b.fn
|
275
288
|
|
276
289
|
return em,da,ma,fa
|
277
290
|
|
@@ -1,16 +1,42 @@
|
|
1
1
|
import numpy as np
|
2
2
|
from ._tsadeval.metrics import *
|
3
|
-
from .metric_utils import transform_to_full_series
|
4
3
|
from sklearn.metrics import auc
|
5
|
-
from .binary_metrics import point_adjusted_precision, point_adjusted_recall, segment_wise_precision, segment_wise_recall
|
6
4
|
from pate.PATE_metric import PATE
|
7
|
-
def precision_at_k(y_true : np.array
|
8
|
-
|
5
|
+
def precision_at_k(y_true : np.array, y_anomaly_scores: np.array):
|
6
|
+
"""
|
7
|
+
Calculate the precision at k score for anomaly detection in time series.
|
8
|
+
|
9
|
+
This metric evaluates how many of the top-k points (with highest anomaly scores)
|
10
|
+
actually correspond to true anomalies. It is particularly useful when we are
|
11
|
+
interested in identifying the most anomalous points, without needing to set a
|
12
|
+
fixed threshold.
|
13
|
+
|
14
|
+
The value of k is automatically set to the number of true anomalies present in
|
15
|
+
y_true. That is, k = sum(y_true).
|
16
|
+
|
17
|
+
Parameters:
|
18
|
+
y_true (np.array): The ground truth binary labels for the time series data.
|
19
|
+
y_anomaly_scores (np.array): The predicted anomaly scores for the time series data.
|
20
|
+
"""
|
9
21
|
m = PatK_pw(y_true,y_anomaly_scores)
|
10
22
|
|
11
23
|
return m.get_score()
|
12
24
|
|
13
|
-
def auc_roc_pw(y_true : np.array
|
25
|
+
def auc_roc_pw(y_true : np.array, y_anomaly_scores: np.array):
|
26
|
+
"""
|
27
|
+
Calculate the AUC-ROC score for anomaly detection in time series.
|
28
|
+
|
29
|
+
This is the standard Area Under the Receiver Operating Characteristic Curve (AUC-ROC),
|
30
|
+
computed in a point-wise manner. That is, each point in the time series is treated
|
31
|
+
independently when calculating true positives, false positives, and false negatives.
|
32
|
+
|
33
|
+
Parameters:
|
34
|
+
y_true (np.array): Ground-truth binary labels for the time series (0 = normal, 1 = anomaly).
|
35
|
+
y_anomaly_scores (np.array): Continuous anomaly scores assigned to each point in the series.
|
36
|
+
|
37
|
+
Returns:
|
38
|
+
float: AUC-ROC score.
|
39
|
+
"""
|
14
40
|
|
15
41
|
m = AUC_ROC(y_true,y_anomaly_scores)
|
16
42
|
|
@@ -18,7 +44,20 @@ def auc_roc_pw(y_true : np.array ,y_anomaly_scores: np.array):
|
|
18
44
|
|
19
45
|
|
20
46
|
def auc_pr_pw(y_true : np.array ,y_anomaly_scores: np.array):
|
21
|
-
|
47
|
+
"""
|
48
|
+
Calculate the AUC-PR score for anomaly detection in time series.
|
49
|
+
|
50
|
+
This is the standard Area Under the Precision-Recall Curve (AUC-PR),
|
51
|
+
computed in a point-wise manner. That is, each point in the time series is treated
|
52
|
+
independently when calculating precision and recall.
|
53
|
+
|
54
|
+
Parameters:
|
55
|
+
y_true (np.array): Ground-truth binary labels for the time series (0 = normal, 1 = anomaly).
|
56
|
+
y_anomaly_scores (np.array): Continuous anomaly scores assigned to each point in the series.
|
57
|
+
|
58
|
+
Returns:
|
59
|
+
float: AUC-PR score.
|
60
|
+
"""
|
22
61
|
m = AUC_PR_pw(y_true,y_anomaly_scores)
|
23
62
|
|
24
63
|
return m.get_score()
|
@@ -26,6 +65,25 @@ def auc_pr_pw(y_true : np.array ,y_anomaly_scores: np.array):
|
|
26
65
|
|
27
66
|
|
28
67
|
def auc_pr_pa(y_true: np.array, y_anomaly_scores: np.array):
|
68
|
+
"""
|
69
|
+
Calculate the AUC-PR score using point-adjusted evaluation for anomaly detection in time series.
|
70
|
+
|
71
|
+
This is the standard Area Under the Precision-Recall Curve (AUC-PR), but instead of computing
|
72
|
+
precision and recall point-wise, it uses a point-adjusted approach. Specifically, for each
|
73
|
+
ground-truth anomalous segment, if at least one point within that segment is predicted as anomalous,
|
74
|
+
the entire segment is considered correctly detected. The adjusted predictions are then compared
|
75
|
+
to the ground-truth labels to compute true positives, false positives, and false negatives,
|
76
|
+
which are used to construct the PR curve.
|
77
|
+
|
78
|
+
Parameters:
|
79
|
+
y_true (np.array): Ground-truth binary labels for the time series (0 = normal, 1 = anomaly).
|
80
|
+
y_anomaly_scores (np.array): Continuous anomaly scores assigned to each point in the series.
|
81
|
+
|
82
|
+
Returns:
|
83
|
+
float: AUC-PR score (with point-adjusted evaluation).
|
84
|
+
"""
|
85
|
+
|
86
|
+
|
29
87
|
precisions = [1]
|
30
88
|
recalls = [0]
|
31
89
|
tps,fps,fns = [],[],[]
|
@@ -96,6 +154,25 @@ def auc_pr_pa(y_true: np.array, y_anomaly_scores: np.array):
|
|
96
154
|
|
97
155
|
|
98
156
|
def auc_pr_sw(y_true: np.array, y_anomaly_scores: np.array):
|
157
|
+
"""
|
158
|
+
Calculate the AUC-PR score using segment-wise evaluation for anomaly detection in time series.
|
159
|
+
|
160
|
+
This is the standard Area Under the Precision-Recall Curve (AUC-PR), but it uses a segment-wise
|
161
|
+
adjustment when computing precision and recall. In this evaluation, each contiguous segment of
|
162
|
+
anomalous ground-truth points is treated as a single unit. A true positive is counted if at least
|
163
|
+
one predicted anomaly overlaps with the segment. A false negative occurs when a segment is
|
164
|
+
completely missed, and a false positive is recorded for each predicted anomalous segment
|
165
|
+
that does not overlap with any ground-truth anomaly. These adjusted counts are then used
|
166
|
+
to compute precision and recall for constructing the PR curve.
|
167
|
+
|
168
|
+
Parameters:
|
169
|
+
y_true (np.array): Ground-truth binary labels for the time series (0 = normal, 1 = anomaly).
|
170
|
+
y_anomaly_scores (np.array): Continuous anomaly scores assigned to each point in the series.
|
171
|
+
|
172
|
+
Returns:
|
173
|
+
float: AUC-PR score (with segment-wise evaluation).
|
174
|
+
"""
|
175
|
+
|
99
176
|
precisions = [1]
|
100
177
|
recalls = [0]
|
101
178
|
tps,fps,fns = [],[],[]
|
@@ -185,14 +262,51 @@ def auc_pr_sw(y_true: np.array, y_anomaly_scores: np.array):
|
|
185
262
|
|
186
263
|
|
187
264
|
def vus_roc(y_true : np.array ,y_anomaly_scores: np.array, window=4):
|
188
|
-
|
265
|
+
"""
|
266
|
+
Calculate the VUS-ROC (Volume Under the ROC Surface) score for anomaly detection in time series.
|
267
|
+
|
268
|
+
This metric extends the classical AUC-ROC by introducing a temporal tolerance parameter `l`, which
|
269
|
+
smooths the binary ground-truth labels. The idea is to allow a flexible evaluation that tolerates
|
270
|
+
small misalignments in the detection of anomalies. The final score is computed by integrating
|
271
|
+
the ROC-AUC over different values of the tolerance parameter, from 0 to `window`, thus producing
|
272
|
+
a volume under the ROC surface.
|
273
|
+
|
274
|
+
Parameters:
|
275
|
+
y_true (np.array): Ground-truth binary labels (0 = normal, 1 = anomaly).
|
276
|
+
y_anomaly_scores (np.array): Anomaly scores for each time point.
|
277
|
+
window (int): Maximum temporal tolerance `l` used to smooth the evaluation.
|
278
|
+
|
279
|
+
Returns:
|
280
|
+
float: VUS-ROC score.
|
281
|
+
|
282
|
+
For more information, see the original paper:
|
283
|
+
https://dl.acm.org/doi/10.14778/3551793.3551830
|
284
|
+
"""
|
189
285
|
m = VUS_ROC(y_true,y_anomaly_scores,max_window=window)
|
190
286
|
|
191
287
|
return m.get_score()
|
192
288
|
|
193
289
|
|
194
290
|
def vus_pr(y_true : np.array ,y_anomaly_scores: np.array, window=4):
|
195
|
-
|
291
|
+
"""
|
292
|
+
Calculate the VUS-PR (Volume Under the PR Surface) score for anomaly detection in time series.
|
293
|
+
|
294
|
+
This metric is an extension of the classical AUC-PR, incorporating a temporal tolerance parameter `l`
|
295
|
+
that smooths the binary ground-truth labels. It allows for some flexibility in the detection of
|
296
|
+
anomalies that are temporally close to the true events. The final metric integrates the PR-AUC
|
297
|
+
over several levels of temporal tolerance (from 0 to `window`), yielding a volume under the PR surface.
|
298
|
+
|
299
|
+
Parameters:
|
300
|
+
y_true (np.array): Ground-truth binary labels (0 = normal, 1 = anomaly).
|
301
|
+
y_anomaly_scores (np.array): Anomaly scores for each time point.
|
302
|
+
window (int): Maximum temporal tolerance `l` used to smooth the evaluation.
|
303
|
+
|
304
|
+
Returns:
|
305
|
+
float: VUS-PR score.
|
306
|
+
|
307
|
+
For more information, see the original paper:
|
308
|
+
https://dl.acm.org/doi/10.14778/3551793.3551830
|
309
|
+
"""
|
196
310
|
m = VUS_PR(y_true,y_anomaly_scores,max_window=window)
|
197
311
|
|
198
312
|
return m.get_score()
|
@@ -200,17 +314,29 @@ def vus_pr(y_true : np.array ,y_anomaly_scores: np.array, window=4):
|
|
200
314
|
|
201
315
|
def real_pate(y_true: np.array, y_anomaly_scores: np.array, early: int, delay: int):
|
202
316
|
"""
|
203
|
-
Calculate PATE score for anomaly detection in time series.
|
204
|
-
|
317
|
+
Calculate PATE score for anomaly detection in time series using real-valued anomaly scores.
|
318
|
+
|
319
|
+
This version of PATE evaluates real-valued anomaly scores by assigning weights to predictions
|
320
|
+
based on their temporal proximity to the true anomaly intervals. It defines an early buffer of
|
321
|
+
length `early` before each anomaly and a delay buffer of length `delay` after it. Detections with
|
322
|
+
high scores within the anomaly interval receive full weight, while those in the buffer zones are
|
323
|
+
assigned linearly decaying weights depending on their distance from the interval. Scores outside
|
324
|
+
these zones contribute to false positives, and intervals with insufficient detection are penalized
|
325
|
+
as false negatives.
|
326
|
+
|
327
|
+
The final PATE score aggregates these weighted contributions across all time steps, yielding
|
328
|
+
a smooth performance measure that is sensitive to both the timing and confidence of the predictions.
|
329
|
+
|
330
|
+
For more information, see the original paper:
|
331
|
+
https://arxiv.org/abs/2405.12096
|
205
332
|
|
206
333
|
Parameters:
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
334
|
+
y_true (np.array): Ground truth binary labels (0 = normal, 1 = anomaly).
|
335
|
+
y_anomaly_scores (np.array): Real-valued anomaly scores for each time point.
|
336
|
+
early (int): Length of the early buffer zone before each anomaly interval.
|
337
|
+
delay (int): Length of the delay buffer zone after each anomaly interval.
|
211
338
|
|
212
339
|
Returns:
|
213
|
-
|
340
|
+
float: The real-valued PATE score.
|
214
341
|
"""
|
215
|
-
|
216
342
|
return PATE(y_true, y_anomaly_scores, early, delay, binary_scores=False)
|
tsadmetrics/utils.py
CHANGED
@@ -2,7 +2,7 @@ import numpy as np
|
|
2
2
|
import pandas as pd
|
3
3
|
import time
|
4
4
|
|
5
|
-
def compute_metrics(y_true: np.array,y_pred: np.array,metrics: list, metrics_params: dict, is_anomaly_score = False, verbose = False):
|
5
|
+
def compute_metrics(y_true: np.array,y_pred: np.array, metrics: list, metrics_params: dict, is_anomaly_score = False, verbose = False):
|
6
6
|
"""
|
7
7
|
Computes the specified metrics for the given true and predicted values.
|
8
8
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: tsadmetrics
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.11
|
4
4
|
Summary: =?unknown-8bit?q?Librer=C3=ADa_para_evaluaci=C3=B3n_de_detecci=C3=B3n_de_anomal=C3=ADas?= en series temporales
|
5
5
|
Home-page: https://github.com/pathsko/TSADmetrics
|
6
6
|
Author: Pedro Rafael Velasco Priego
|
@@ -1,3 +1,4 @@
|
|
1
|
+
docs/conf.py,sha256=skVqctOiByesc7wNDW5DpjyTxUCP0wxlpWA1fsJYZhk,1384
|
1
2
|
entorno/bin/activate_this.py,sha256=45dnJsdtOWIt5LtVSBmBfB8E7AlKcnhnZe9e3WGclak,1199
|
2
3
|
entorno/bin/rst2html.py,sha256=h4RydG-iAectsUra0lNFGwB4_1mngxrtPPgQrxUWQ3A,643
|
3
4
|
entorno/bin/rst2html4.py,sha256=Xiv3Zb1gk4jT7DYFVlf5w4LJtI5ZI3pW3b1KLxyPS5A,765
|
@@ -12,14 +13,14 @@ entorno/bin/rst2xetex.py,sha256=spisB81JgqAmMAkjdTaP8awFQS_Zuob9HIcbMi1kOS8,922
|
|
12
13
|
entorno/bin/rst2xml.py,sha256=uoIfpn3prnir2tzqdycsAjOg-OWw663XOK47IeHCZdY,651
|
13
14
|
entorno/bin/rstpep2html.py,sha256=sthYQHEgYfj4JqwG45URwVbRAs-HYuwKget7SUwp9fc,719
|
14
15
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
|
-
tests/test_binary.py,sha256=
|
16
|
+
tests/test_binary.py,sha256=dj9BsKBo5rpWw4JGiKKoVkg4rIW4YylTie2VxH2DAGo,29787
|
16
17
|
tests/test_non_binary.py,sha256=syANlwm0DKsL6geGeq6nQI6ZVe6T_YXWTyk2-Hmck4s,11308
|
17
18
|
tsadmetrics/__init__.py,sha256=MTWOa43fgOdkMNo5NglCReRnB8hoF0ob2PIvDziCNHw,1575
|
18
|
-
tsadmetrics/binary_metrics.py,sha256=
|
19
|
-
tsadmetrics/metric_utils.py,sha256=
|
20
|
-
tsadmetrics/non_binary_metrics.py,sha256=
|
19
|
+
tsadmetrics/binary_metrics.py,sha256=pEIe8s3_obGN1hHhfvQwg0BXKafs4lQ3l1-K03P3Ews,60067
|
20
|
+
tsadmetrics/metric_utils.py,sha256=fm8v0X37_AlqWpkcUT9r3680QsjLljrHe2YuXkRLAZ4,10873
|
21
|
+
tsadmetrics/non_binary_metrics.py,sha256=yo620BWZIq-OkBqQV7t7ynjGhcuX6QWQ6iq_7eJq9gI,13074
|
21
22
|
tsadmetrics/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
|
-
tsadmetrics/utils.py,sha256=
|
23
|
+
tsadmetrics/utils.py,sha256=15X_RkHdCxhu_-OH8fEm3gRVQ4tTMqCkNaQsQoloEYQ,2361
|
23
24
|
tsadmetrics/_tsadeval/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
25
|
tsadmetrics/_tsadeval/auc_roc_pr_plot.py,sha256=PHqJUXq2qI248XV9o04D8SsUJgowetaKq0Cu5bYrIAE,12689
|
25
26
|
tsadmetrics/_tsadeval/discontinuity_graph.py,sha256=Ci65l_DPi6HTtb8NvQJe1najgGrRuEpOMWvSyi2AeR0,4088
|
@@ -52,7 +53,7 @@ tsadmetrics/_tsadeval/prts/time_series_metrics/fscore.py,sha256=pJz4iuPyVGNvwsaR
|
|
52
53
|
tsadmetrics/_tsadeval/prts/time_series_metrics/precision.py,sha256=jLkcMg7UNl25SHtZUBGkP-RV8HsvaZCtjakryl7PFWU,3204
|
53
54
|
tsadmetrics/_tsadeval/prts/time_series_metrics/precision_recall.py,sha256=OhUJSm_I7VZ_gX_SSg8AYUq3_NW9rMIy7lAVsnOFw4Q,417
|
54
55
|
tsadmetrics/_tsadeval/prts/time_series_metrics/recall.py,sha256=LL-0pPer3ymovVRlktaHo5XDzpgiDhWOVfdPOzKR6og,3152
|
55
|
-
tsadmetrics-0.1.
|
56
|
-
tsadmetrics-0.1.
|
57
|
-
tsadmetrics-0.1.
|
58
|
-
tsadmetrics-0.1.
|
56
|
+
tsadmetrics-0.1.11.dist-info/METADATA,sha256=JrsyLRUVbWIhrBkE56hn3ALYUycm3j52kSmmcq8TMhA,831
|
57
|
+
tsadmetrics-0.1.11.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
58
|
+
tsadmetrics-0.1.11.dist-info/top_level.txt,sha256=s2VIr_ePl-WZbYt9FsYbsDGM7J-Qc5cgpwEOeQ3FVpM,31
|
59
|
+
tsadmetrics-0.1.11.dist-info/RECORD,,
|
File without changes
|