Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Principle:Online ml River Anomaly Scoring Interface

From Leeroopedia


Knowledge Sources River River Docs
Domains Online Machine Learning, Anomaly Detection, API Design, Design Patterns
Last Updated 2026-02-08 16:00 GMT

Overview

Abstract interface for online anomaly detectors defining the score_one/learn_one contract for streaming anomaly scoring, establishing the common pattern that all River anomaly detectors must implement.

Description

The Anomaly Scoring Interface is the foundational design pattern underlying all anomaly detection in River. It defines a two-method contract that every anomaly detector must satisfy:

  • learn_one(x: dict) -> None -- Update the model with a single observation.
  • score_one(x: dict) -> float -- Return an anomaly score for a single observation, where high scores indicate anomalies and low scores indicate normal observations.

This interface is intentionally minimal and consistent with River's broader philosophy of one-observation-at-a-time processing. It enables composability: any anomaly detector can be wrapped by an AnomalyFilter (ThresholdFilter or QuantileFilter), plugged into a pipeline, or evaluated with progressive_val_score.

The interface is extended by the AnomalyFilter abstract class, which adds:

  • classify(score: float) -> bool -- Convert a continuous score to a binary label.
  • A protect_anomaly_detector mechanism that conditionally gates learning.

This is a Pattern Doc -- it documents the interface that users must implement when creating custom anomaly detectors or consume when using built-in detectors.

Usage

The anomaly scoring interface applies when:

  • You are building a custom anomaly detector and need to know which methods to implement
  • You want to understand how River's anomaly detection ecosystem fits together
  • You need to compose anomaly detectors with filters, pipelines, or evaluation functions
  • You are designing the score-classify-alert-learn deployment loop

Theoretical Basis

The AnomalyDetector contract:

class AnomalyDetector(base.Estimator):
    """An anomaly detector."""

    def learn_one(self, x: dict) -> None:
        """Update the model with a single observation.

        Parameters
        ----------
        x : dict
            A dictionary of features.
        """
        ...

    def score_one(self, x: dict) -> float:
        """Return an outlier score.

        A high score is indicative of an anomaly.
        A low score corresponds to a normal observation.

        Parameters
        ----------
        x : dict
            A dictionary of features.

        Returns
        -------
        float
            An anomaly score.
        """
        ...

The AnomalyFilter extension:

class AnomalyFilter(base.Wrapper, base.Estimator):
    """Wraps an AnomalyDetector with binary classification."""

    def __init__(self, anomaly_detector, protect_anomaly_detector=True):
        ...

    def classify(self, score: float) -> bool:
        """Classify a score as anomalous (True) or normal (False)."""
        ...

    def score_one(self, *args, **kwargs) -> float:
        """Delegates to wrapped anomaly_detector.score_one."""
        return self.anomaly_detector.score_one(*args, **kwargs)

    def learn_one(self, *args, **learn_kwargs) -> None:
        """Conditionally updates the wrapped detector."""
        if self.protect_anomaly_detector and not self.classify(self.score_one(*args)):
            self.anomaly_detector.learn_one(*args, **learn_kwargs)

Canonical deployment pattern:

The recommended deployment loop for anomaly detection in River follows this sequence:

for each observation x:
    1. SCORE:    score = model.score_one(x)
    2. CLASSIFY: is_anomaly = filter.classify(score)
    3. ALERT:    if is_anomaly: trigger_alert(x, score)
    4. LEARN:    model.learn_one(x)  # or filter.learn_one(x) with protection

Key design decisions:

  • Score before learn: The observation is scored before the model learns from it, ensuring the prediction is made on unseen data (progressive validation).
  • High = anomalous: All River anomaly detectors follow the convention that higher scores indicate more anomalous observations. (Note: OneClassSVM.score_one returns raw decision function values where lower = more anomalous, but when wrapped in a QuantileFilter, the classification still works correctly.)
  • Unsupervised: learn_one takes only features (no target), making anomaly detection fully unsupervised.
  • Composable: Detectors can be piped into filters, which can be piped into supervised models.

Implementors of the interface:

Class Type Score Range
anomaly.HalfSpaceTrees AnomalyDetector [0, 1]
anomaly.OneClassSVM AnomalyDetector unbounded (raw decision function)
anomaly.ThresholdFilter AnomalyFilter delegates to wrapped detector
anomaly.QuantileFilter AnomalyFilter delegates to wrapped detector

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment