Skip to content

Repository files navigation

Tiny Anomaly Lab

Tiny Anomaly Lab is an anomaly-detection workbench for small time-series data.

It runs one experiment on bundled data and writes a reproducible interactive report. The lab shows the feature pipeline, leakage-safe evaluation, model cards, feature contributions, and an interactive chart.

Scope

The lab targets a few hundred rows with a timestamp, two sensor channels and a known anomaly label. It is a teaching and review tool. It is not a production control system.

Stack

  • Polars reads and shapes the data.
  • scikit-learn trains the detectors and the scaler.
  • Plotly renders a self-contained HTML report.

The project uses only established, open-source dependencies. No paid service, secret or network call is needed for the demo or for the tests.

Architecture

Module Task
data.py Loads the bundled CSV and validates the schema.
features.py Builds causal rolling and lag features.
split.py Splits the feature frame by time only.
models.py Holds the detector registry, scorers and contributions.
evaluate.py Computes ranking and threshold metrics.
export.py Writes scores and flagged rows to CSV.
model_card.py Renders a Markdown model card.
report.py Writes a self-contained Plotly HTML report.
experiment.py Runs one experiment from start to finish.
__main__.py Exposes the command line interface.

The experiment runs these modules in one pipeline. The data step loads the CSV. The feature step adds causal rows. The split step divides rows by time. The model step fits the detector and contribution method. The evaluate step scores and flags rows. The report and export steps write the output files.

Leakage-safety model

The detector is fit on the calibration window only. The scaler is fit on the calibration window only. The threshold comes from calibration scores, not from evaluation labels. All features use past and current rows only.

Each feature at row t uses values from row t or earlier rows. Rolling means and standard deviations run on a shifted series, so a score at t could have been produced live at time t.

The calibration window may carry labelled anomalies. By default the lab drops those rows before it fits the detector. This step uses training-time labels only. It never reads the evaluation window.

Install

Use a virtual environment.

python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS and Linux
source .venv/bin/activate
pip install -e ".[dev]"

Pin a set of dependencies when you need one.

pip freeze > requirements.txt

Quick start

Run the built-in experiment.

tiny-anomaly-lab --output output

Or call the package as a module.

python -m tiny_anomaly_lab --output output

The command writes output/report.html, output/model_card.md, output/scores.csv and output/flagged_rows.csv. Open the report in a web browser. No server and no network are needed.

Detectors

Three detectors ship with the lab.

  • isolation_forest wraps the scikit-learn Isolation Forest.
  • zscore_rule scores the largest standardised residual.
  • mahalanobis scores the correlation-aware Mahalanobis distance.

Pick the detector with a flag.

tiny-anomaly-lab --detector mahalanobis --output output

Local feature contribution

Each detector can attribute its row score to the input features. The lab uses this in two places: a contribution panel in the report and a top_feature column in the flagged-rows CSV.

  • zscore_rule: contribution is the absolute standardised residual. The largest value marks the feature that drove the score.
  • mahalanobis: contribution is a signed exact split of the squared distance. Row contributions sum to the squared score. A negative value shows a feature that offsets the distance through correlation.
  • isolation_forest: no additive decomposition ships with the lab. The report omits the contribution panel for this detector.

CSV export

Two CSV files sit next to the report.

  • scores.csv holds every feature-frame row with its score, flag and a contrib_ column per feature.
  • flagged_rows.csv holds the flagged evaluation rows with the raw value columns, the score, the threshold and the dominant contributor.

Configuration

Flag Default Meaning
--detector isolation_forest Detector name.
--calibration-fraction 0.5 Share of rows used for calibration.
--contamination 0.05 Expected anomaly share.
--window 6 Rolling window in hours.
--lags 1 24 Lag offsets in hours.
--random-state 7 Seed for the detector.
--source-csv builtin Optional CSV path.
--output output Directory for the artifacts.

Bundled data

The file tiny_anomaly_lab/data/sensor_sample.csv holds 336 hourly rows. It spans 14 days of synthetic sensor data. It injects four anomaly types: an isolated spike, a six-hour level shift, a four-hour flatline and a variance burst. Seventeen rows carry the anomaly label.

Regenerate the file with a fixed seed.

python scripts/build_dataset.py

Sample output

This output comes from the default run on the bundled data.

Detector: isolation_forest
ROC AUC: 0.7082  Average precision: 0.3970
Flagged 9 rows in evaluation (TP=3, FP=6).
Report: output\report.html
Model card: output\model_card.md
Scores: output\scores.csv
Flagged rows: output\flagged_rows.csv

This output comes from the z-score rule run.

Detector: zscore_rule
ROC AUC: 0.7151  Average precision: 0.5175
Flagged 4 rows in evaluation (TP=3, FP=1).

This output comes from the Mahalanobis run.

Detector: mahalanobis
ROC AUC: 0.6938  Average precision: 0.4756
Flagged 6 rows in evaluation (TP=3, FP=3).

A committed sample lives under examples/sample_run/. Open examples/sample_run/report.html to view the interactive figure. The examples/sample_run_mahalanobis/ folder holds the same artifacts for the Mahalanobis detector, including a contribution panel and signed contributions in flagged_rows.csv.

The model card records the detector, the data windows, the leakage controls, the metrics, the per-feature contribution method, the intended use and the limitations.

Tests

Run the deterministic test suite.

python -m pytest -q

Run the linter.

ruff check .

The suite covers data loading, causal features, the split, the metrics, the detectors, the per-feature contributions, the CSV export, the experiment, the model card and the report.

Limitations

The bundled dataset is synthetic and small. Results are illustrative. Isolation Forest scores shift when the random state or the scikit-learn version changes. Causal rolling features lag true change points by the window length. The detector assumes the calibration window is close to normal operation. The Mahalanobis covariance uses a shrinkage estimate that trades bias for stability on small windows, and its signed contributions can hide a feature behind a correlated partner.

Project layout

tiny_anomaly_lab/      Source package.
  data/                Bundled CSV.
tests/                 Deterministic test suite.
scripts/               Dataset builder.
examples/              Committed sample artifacts.
.github/workflows/     Continuous integration.

Roadmap

Later releases stay independent of this one.

Done in this release:

  • Add a multivariate detector beside the two current scorers.
  • Add local feature contribution for the z-score rule and the new detector.
  • Add CSV export of the flagged rows and the scores.

Still open:

  • Add a stream evaluation that replays rows one at a time.
  • Add a container image for a fully reproducible run.

License

MIT.

About

An explainable anomaly-detection workbench for small time-series datasets with reproducible experiments and a browser-based report.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages