Skip to content

Repository files navigation

Score events. Learn continuously. Adapt to the stream.

PyPI version Supported Python versions CI status Documentation status MIT license

Documentation · Quickstart · Model guide · API reference · Changelog

aberrant is a typed Python library for unsupervised anomaly detection on data that arrives one event at a time. Its models share a compact online interface: score_one(x) evaluates the current event and learn_one(x) updates the model. This lets an application adapt continuously without coordinating an external batch-retraining loop.

Most models consume a dict[str, float], while graph and time-aware models document their required keys explicitly. Detector state, warm-up behavior, memory policy, and score scale remain model-specific rather than being hidden behind a batch-estimator abstraction.

Note

ABERRANT is pre-1.0 and under active development. Public APIs may change as the model contracts and implementations mature.

Why ABERRANT?

  • Use one streaming contract across isolation forests, distance methods, sketches, graph detectors, online statistics, SVMs, time-series methods, and reconstruction models.
  • Choose the right state strategy from sliding windows, bounded sketches, fading summaries, and model-specific incremental updates.
  • Compose online preprocessing with detectors using | pipelines.
  • Separate detection from policy with drift detectors and static or adaptive score thresholds.
  • Run repeatable experiments with registry-backed benchmark streams and a validated local dataset cache.
  • Extend without framework coupling through typed, structural transformer and model protocols. The distribution includes py.typed metadata.

Installation

ABERRANT requires Python 3.10 or newer and is continuously tested on CPython 3.10, 3.11, and 3.12.

pip install aberrant
Optional extras
Extra Adds
eval scikit-learn metrics for model evaluation
dl the PyTorch-backed Autoencoder
faiss the FAISS similarity-search engine used by models such as KNN
benchmark River and pytest-benchmark
docs the documentation build toolchain
dev linting, typing, testing, and development dependencies
all all optional and development dependencies

For example:

pip install "aberrant[eval,faiss]"

Quick start

The following core-only example learns a scaled isolation forest from a synthetic stream. The first 64 events warm up the pipeline; every later event is scored before it is learned.

import numpy as np

from aberrant.model.iforest import OnlineIsolationForest
from aberrant.transform.preprocessing import StandardScaler

rng = np.random.default_rng(42)
stream = np.vstack(
    [
        rng.normal(size=(400, 2)),
        rng.normal(loc=5.0, size=(20, 2)),
    ]
)

detector = StandardScaler() | OnlineIsolationForest(
    num_trees=25,
    window_size=256,
    seed=42,
)

scores = []
for step, values in enumerate(stream):
    event = {"x": float(values[0]), "y": float(values[1])}

    if step >= 64:
        scores.append((step, detector.score_one(event)))

    detector.learn_one(event)

for step, score in sorted(scores, key=lambda item: item[1], reverse=True)[:5]:
    print(f"event={step}, anomaly_score={score:.3f}")

Higher scores are more anomalous under the common model contract, but their numeric range and calibration differ by detector. Compare or threshold scores only according to the selected model's documented semantics.

Choose a starting point

Goal Start with
General multivariate detection OnlineIsolationForest or another isolation-forest variant
Local-neighborhood or density anomalies LocalOutlierFactor, KNN, SDOStream, or a cell-based detector
Compact projection or frequency sketches StreamingLODA, MStream, or StreamingRSHash
Anomalous edges and graph evolution AnoEdgeL, ISCONNA, MIDAS, or SignedGraphSketchDetector
Discords in a scalar time series XLagDAMP
Interpretable rolling statistics Univariate and multivariate moving statistics
Adaptive margin-based detection Online SVM models
Learned reconstruction error OnlineAutoencoderEnsemble or the optional PyTorch Autoencoder
Detecting distribution drift ADWIN, KSWIN, or PageHinkley
Turning a score into an alert signal QuantileThreshold or ThresholdModel

See the model guide for inputs, score interpretation, warm-up behavior, and memory characteristics.

Included public model families
Family Implementations
Isolation forest ASDIsolationForest, HalfSpaceTrees, MondrianIsolationForest, OnlineIsolationForest, RandomCutForest, StreamRandomHistogramForest, XStream
Distance CellNeighborhoodDetector, KNN, LocalOutlierFactor, SDOStream, StationaryRegionNeighborDetector
Sketch MStream, StreamingLODA, StreamingRSHash
Graph AnoEdgeL, ISCONNA, MIDAS, SignedGraphSketchDetector
Time series XLagDAMP
SVM GraphGatedOneClassSVM, IncrementalOneClassSVMAdaptiveKernel
Statistical MovingAverage, MovingAverageAbsoluteDeviation, MovingGeometricAverage, MovingHarmonicAverage, MovingInterquartileRange, MovingKurtosis, MovingMedian, MovingQuantile, MovingSkewness, MovingVariance, MovingCorrelationCoefficient, MovingCovariance, MovingMahalanobisDistance
Reconstruction OnlineAutoencoderEnsemble, optional Autoencoder
Score policy QuantileThreshold, ThresholdModel
Baselines NullModel, RandomModel
Drift detection ADWIN, KSWIN, PageHinkley

Pipelines and custom components

Transformers compose left to right, with at most one terminal model:

from aberrant.model.iforest import OnlineIsolationForest
from aberrant.transform import IncrementalPCA, StandardScaler

detector = (
    StandardScaler()
    | IncrementalPCA(n_components=3, n0=100)
    | OnlineIsolationForest(window_size=512, seed=42)
)

Any custom object satisfying TransformerProtocol or ModelProtocol can join a pipeline; subclassing an ABERRANT base class is optional. Read the pipeline guide for lifecycle and composition rules.

Streaming datasets

The dataset API downloads, validates, and caches registered benchmark data, then exposes it as feature dictionaries and evaluation labels:

from itertools import islice

from aberrant.model.iforest import OnlineIsolationForest
from aberrant.stream.dataset import Dataset, load

dataset = load(Dataset.SHUTTLE)
detector = OnlineIsolationForest(num_trees=25, window_size=512, seed=42)

for event, label in islice(dataset.stream(), 100):
    score = detector.score_one(event)
    detector.learn_one(event)
    print(f"label={label!r}, anomaly_score={score:.3f}")

Labels are provided for evaluation; unsupervised detectors learn only from the event mapping. Cache location and download behavior are configurable through the streaming guide.

Update and scoring semantics

Important

For an honest prequential evaluation, call score_one(event) before learn_one(event). Scoring does not call any component's learn_one or incorporate the candidate into learned reference state. During Pipeline.learn_one, each transformer first learns the event and then passes its post-update transform to the next stage. Score scales and warm-up behavior are model-specific, so a single numeric threshold is not portable across detector families.

The evaluation guide covers warm-up separation, label leakage, and useful metrics for imbalanced anomaly streams.

Project

Read the documentation, browse the examples, or report a problem in the issue tracker. Contributions are welcome; start with the contributing guide.

ABERRANT is distributed under the MIT License.

Releases

Used by

Contributors

Languages