"Give me the right scoring rule and I will make a coin flip look like a genius. That is not a boast. It is a warning about your metric."
A Skeptical AI Agent
The Big Picture
Every detector in this chapter produces the same output: a stream of scores, and, after a threshold, a stream of alarms. The hard part is not building the detector. It is deciding whether the detector is any good when you almost never have a clean, complete answer key to grade it against. Real sensor logs are labeled sparsely, late, and fuzzily: an operator marks the hour a pump failed, not the exact sample where the bearing first whispered; a clinician annotates the arrhythmia, not the ambiguous beats on either side. Into this vacuum the field poured a scoring convention called point adjust that looked reasonable and quietly broke evaluation for years, to the point where a random number generator could outscore carefully engineered models on published benchmarks. This section does two things. First, it dissects the point-adjust trap so you can recognize inflated results on sight. Second, it gives you an evaluation toolkit that survives incomplete labels: range-aware metrics, threshold-free curves that respect the extreme class imbalance, detection-delay accounting, and label-light protocols built on injected faults. Getting the metric right is not bookkeeping. A wrong metric silently selects the wrong model, and you ship it.
This section assumes the precision, recall, and threshold vocabulary from the residual view of Section 12.3, the base-rate reasoning of Chapter 4, and the leakage discipline of Chapter 5. The full benchmarking protocol it feeds into is developed in Chapter 65.
Why complete labels almost never exist
Point-wise anomaly labels for a long sensor stream are a fiction we rarely get to enjoy. Three structural reasons keep them incomplete. First, boundaries are ambiguous: an anomaly is a temporal event with a soft onset and offset, so no two annotators agree on the exact first and last anomalous sample, and asking them to is asking for noise. Second, anomalies are rare: a healthy machine may run for months between events, so the positive class is a fraction of a percent of samples, and a single mislabeled segment swings the score. Third, discovery is retrospective: you learn a fault occurred from a maintenance ticket or a patient outcome, timestamped to the shift or the day, not to the millisecond your detector cares about. The consequence is that we grade detectors against labels that mark events, coarse intervals of "something was wrong here", while the detector emits per-sample decisions. Any honest metric must bridge that granularity gap, and the way it bridges it is exactly where evaluation goes right or wrong.
The point-adjust trap
Point adjust was introduced with good intentions. The reasoning went: if a ground-truth anomaly spans samples \(t_0\) through \(t_1\), and the detector fires on even one sample inside that window, then in practice a human would have caught the whole event, so we should credit the detector for the entire segment. Concretely, before scoring, you rewrite the prediction: for each labeled anomaly segment, if any point in it is flagged, mark every point in it as flagged. Then compute ordinary point-wise precision, recall, and \(F_1\). It sounds humane. It is a disaster.
The problem is that segments are long and the adjustment is a giant credit multiplier. Suppose the labeled anomalies occupy contiguous runs averaging \(L\) samples each, and a detector flags points independently with probability \(p\). The chance it touches a given segment, and therefore harvests all \(L\) points of true-positive credit, is
$$\Pr(\text{segment hit}) \;=\; 1 - (1-p)^{L}.$$For \(L = 100\) and a trivial flag rate of \(p = 0.02\), that probability is already about \(0.87\). A detector that flags two percent of samples uniformly at random, with zero signal, sweeps up almost all of the recall while its false positives stay diffuse and cheap. The recovered recall is near one, precision looks respectable because the denominator is dominated by the credited segment points, and the resulting point-adjust \(F_1\) rivals or beats genuinely engineered detectors. This is not a hypothetical: the critique that a randomized score outperforms state-of-the-art models under point adjust is what forced the anomaly-detection community to abandon the protocol for headline numbers. The code below reproduces the effect in a dozen lines.
import numpy as np
def f1(pred, label):
tp = np.sum(pred & label); fp = np.sum(pred & ~label); fn = np.sum(~pred & label)
p = tp / (tp + fp + 1e-9); r = tp / (tp + fn + 1e-9)
return 2 * p * r / (p + r + 1e-9)
def point_adjust(pred, label): # the trap: any hit credits the whole segment
pred = pred.copy(); i = 0
while i < len(label):
if label[i]:
j = i
while j < len(label) and label[j]: j += 1
if pred[i:j].any(): pred[i:j] = True # inflate to full segment
i = j
else:
i += 1
return pred
rng = np.random.default_rng(0)
n = 20000
label = np.zeros(n, dtype=bool)
for s in rng.integers(0, n - 100, size=25): # 25 anomaly events, ~100 samples each
label[s:s + 100] = True
pred = rng.random(n) < 0.02 # a PURELY RANDOM detector, no signal at all
print("point-wise F1 :", round(f1(pred, label), 3))
print("point-adjust F1:", round(f1(point_adjust(pred, label), label), 3))
Key Insight
A benchmark number is only meaningful relative to what a trivial baseline scores on it. Before you trust any anomaly metric, run two null detectors through it: uniform random flagging at your operating rate, and an "all-anomaly" detector that flags everything. If either scores well, the metric is inflated and your model comparisons are noise dressed as progress. This "beat the coin flip" audit costs three lines and has saved more anomaly-detection papers from embarrassment than any clever architecture. The failure of point adjust is not that segment-level credit is wrong in principle; it is that crediting the full segment for a single touch decouples the score from how well the detector actually localizes the event.
Metrics that survive incomplete labels
If segment credit is the right instinct but full-segment credit is the trap, the fix is to make credit proportional and localized. Several families do this correctly. Range-based precision and recall (Tatbul and colleagues) generalize the point definitions to intervals, splitting recall into an existence term (did you detect the event at all) and an overlap term (how much of it), with a tunable bias for early or positional detection. Affiliation metrics (Huet and colleagues) score each prediction by its temporal distance to the nearest true anomaly and normalize against what a random baseline would achieve, so a coin flip scores zero by construction. For threshold-free comparison, the volume under the surface (VUS) family generalizes ROC and precision-recall area to anomaly ranges with a tolerance buffer, removing both the arbitrary threshold and the razor-edge boundary sensitivity in one move.
Two workhorse cautions apply to the classic curves you will reach for first. Prefer the area under the precision-recall curve over the area under the ROC curve, because ROC is seduced by the enormous true-negative count under extreme class imbalance and can look excellent while precision is dismal. And never report "best \(F_1\)", the \(F_1\) at the single threshold that maximizes it on the test set, as your result: choosing the threshold with the answer key in hand is threshold leakage, an optimistic peek that will not survive contact with a production stream where you must fix the threshold in advance. Set the threshold on a validation split or from a false-alarm budget, exactly as in Section 12.3, then report performance at that threshold.
Practical Example: a cloud-telemetry team unlearns its leaderboard
An infrastructure team monitors thousands of server key-performance-indicator streams (latency, error rate, queue depth) and had been ranking detector candidates by point-adjust \(F_1\) on a hand-labeled incident set. A new "detector" submitted as a joke, a fixed-period square wave ignoring the data entirely, landed second on the board. That triggered an audit. Rescored with affiliation precision-recall and a VUS-style threshold-free area, the joke submission collapsed to near the random floor, and the ranking of the real models reshuffled: the previous leader had been winning on segment-credit luck, not localization. The team adopted three rules. Report the random and all-positive baselines alongside every model. Fix thresholds on a time-ordered validation window, never on the test set. Track detection delay explicitly, because for their pager an alarm 40 minutes into an outage is nearly worthless even if it earns full segment credit. The reshuffle changed which model shipped. The fleet-scale version of this discipline is the subject of Chapter 69.
Evaluating with few labels, or none
When labels are scarce you still have levers. The most reliable is controlled fault injection: take verified-healthy data and synthesize anomalies with known onset, offset, and magnitude (spikes, level shifts, variance bursts, frozen sensors), then score against a label you authored precisely. This is the leakage-safe evaluation thread of this book applied to detection; the synthetic-data machinery is developed further in Chapter 55. Complement it with label-free operating characteristics: on healthy-only data you can measure the empirical false-alarm rate and mean time between false alarms directly, no anomaly labels required, which pins down half of the tradeoff by itself. For the detection half, weak or delayed labels (a maintenance ticket dated to the day) support event-level recall and detection delay, the lag from true onset to first alarm, which is often the metric operators care about most and which no amount of segment credit can fake. Finally, when scores carry calibrated uncertainty you can evaluate coverage rather than hard hits, connecting to the conformal machinery of Chapter 18.
Right Tool: range-aware metrics you should not hand-roll
Range-based and threshold-free anomaly metrics are fiddly to implement correctly (segment matching, buffered overlap, baseline normalization), and a subtle off-by-one in your segment loop is exactly how bad numbers get published. Libraries such as prts (range-based precision and recall) and the TSB-UAD evaluation suite (VUS and range-AUC) give you these as one-call functions: ts_precision(label, pred, alpha=0, ...) replaces roughly forty lines of interval bookkeeping with one, and the VUS routines hand back a threshold-free score directly from the raw anomaly scores. Let the library own the boundary arithmetic, and spend your attention on picking the metric and its bias parameters to match your operational cost, not on debugging overlap loops.
Exercise
Extend the code above. (1) Sweep the random flag rate \(p\) over \(\{0.005, 0.01, 0.02, 0.05\}\) and plot point-adjust \(F_1\) against \(p\); overlay the theoretical segment-hit probability \(1-(1-p)^L\) and confirm the inflation tracks it. (2) Implement event-level recall (a segment counts as detected only if flagged) and detection delay (samples from segment start to first flag), and show that a real residual detector from Section 12.3 beats the random baseline on delay even where point-adjust \(F_1\) cannot tell them apart. (3) Compute area under the precision-recall curve and area under the ROC curve on the same imbalanced stream and explain, from the base rate, why ROC looks far more flattering.
Self-Check
- Explain in one sentence why a purely random detector can achieve a high point-adjust \(F_1\), and identify the exact step in the protocol responsible.
- Why is reporting the "best \(F_1\)" chosen on the test set a form of leakage, and what should you report instead?
- You have healthy data in abundance but only three roughly dated fault events. Name two quantities you can still evaluate rigorously and one you cannot trust.
What's Next
In Section 12.7, we turn the evaluation lens toward the human on the other end of the alarm. A detector with a beautiful precision-recall curve can still be operationally useless if it pages an engineer every ten minutes, so we make the false-alarm budget a first-class economic quantity: how alert fatigue is measured, how a threshold trades detection against operator trust, and how to price an alarm so the system stays worth listening to.