You have a metric — requests per second, queue depth, a sensor reading — you
suspect it occasionally misbehaves, and you have no record of when it did.
hazure finds those moments: rule-based and unsupervised detectors that learn
what "normal" looks like from the series itself, and that say where it stopped
holding.
Any pandas, polars or pyarrow object with a time axis goes in, and the answer
comes back in the same flavour. At runtime it needs narwhals and numpy and
nothing else; every heavier dependency is an extra, imported lazily by the
algorithm that needs it.
pip install hazure[pandas]
import numpy as np
import pandas as pd
from hazure.detection import SeasonalDetector
from hazure.events import to_events
# Hourly traffic with a daily rhythm — and one afternoon that went wrong.
rng = np.random.default_rng(0)
index = pd.date_range("2024-03-01", periods=24 * 21, freq="h", name="time")
daily = 40 * np.sin(2 * np.pi * np.arange(len(index)) / 24)
traffic = pd.Series(100 + daily + rng.normal(0, 3, len(index)), index=index, name="rps")
traffic.iloc[300:306] = 20.0
labels = SeasonalDetector(period=24).fit_detect(traffic)
print(to_events(labels))
# Events([2024-03-13T12:00:00..2024-03-13T17:59:59.999999999])
labels sits on traffic's own index — 1.0 anomalous, 0.0 normal, NaN
unknown — and the six flagged hours are exactly the six that were planted.
Everything is one of five composable component types (Scorer, Threshold,
Detector, Aggregator, Transformer), chained with Pipeline and wired with
Graph when the model branches.
On a series that is still arriving
Fit once on a period you are willing to call normal, then feed observations in as
they come. Stream runs the same fitted component over a buffer of recent
history, so the online answer is the batch answer rather than a second
implementation of it — and prime refuses to start if the buffer is too short for
what the component looks back over, instead of quietly computing from a window
that was never full.
from hazure import Stream
detector = SeasonalDetector(period=24).fit(traffic)
stream = Stream(detector, history=48).prime(traffic)
stream.update("2024-03-22T00:00", 105.0) # in line with the fortnight -> 0.0
stream.update("2024-03-22T01:00", 12.0) # not in line with it -> 1.0
Where to draw the line
Every threshold is parameterised by something, and none of those somethings is
"the answer I want". Two ways to get one. PotThreshold takes the false-alarm
probability directly — it fits a generalised Pareto to the tail of the training
scores, so the fence can be placed where exceedance has probability 1e-4, beyond
the largest score ever observed. And budget_threshold needs no labels at all:
give it the number of alerts a week anyone will read, and it lowers the fence as
far as that allows and no further.
Documentation
https://ykus4.github.io/hazure/
- Quickstart — one planted anomaly end to end: detect, convert to intervals, score, plot.
- Guide — which detector suits which kind of anomaly, and the two behaviours that surprise people most.
- How it works — the mathematics of every scorer, threshold and metric, and where each one's assumptions run out.
- API reference — every public name.
Details
- Python 3.11 and newer.
- Fully typed;
mypy --strictclean. - MIT licensed.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hazure-0.1.0.tar.gz.
File metadata
- Download URL: hazure-0.1.0.tar.gz
- Upload date:
- Size: 929.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
49a700eeec538bc78aff4bad8dc99fd00373091d37b303021dfbba7da4266a1c
|
|
| MD5 |
5ffc756ef760d4db36e8613850807d1b
|
|
| BLAKE2b-256 |
cb8d729cf182c1c50db5568d9df1c884980827bfd68a931d5c234027bc40b442
|
Provenance
The following attestation bundles were made for hazure-0.1.0.tar.gz:
Publisher:
release.yml on ykus4/hazure
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hazure-0.1.0.tar.gz -
Subject digest:
49a700eeec538bc78aff4bad8dc99fd00373091d37b303021dfbba7da4266a1c - Sigstore transparency entry: 2311944080
- Sigstore integration time:
-
Permalink:
ykus4/hazure@a1ba61d060b597a9997ebbb6263973e7abd4f0f5 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/ykus4
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a1ba61d060b597a9997ebbb6263973e7abd4f0f5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file hazure-0.1.0-py3-none-any.whl.
File metadata
- Download URL: hazure-0.1.0-py3-none-any.whl
- Upload date:
- Size: 247.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
70db3f86683401d4689287e2b510480ca18b6349ad7428b29aa5efcb84fbd318
|
|
| MD5 |
d306d1bb9b5dd86d7511623df2317b5e
|
|
| BLAKE2b-256 |
7ce3789b8cca383a9375817d8193063209a8ef967fc8b359b68533b3c4e784fe
|
Provenance
The following attestation bundles were made for hazure-0.1.0-py3-none-any.whl:
Publisher:
release.yml on ykus4/hazure
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hazure-0.1.0-py3-none-any.whl -
Subject digest:
70db3f86683401d4689287e2b510480ca18b6349ad7428b29aa5efcb84fbd318 - Sigstore transparency entry: 2311944093
- Sigstore integration time:
-
Permalink:
ykus4/hazure@a1ba61d060b597a9997ebbb6263973e7abd4f0f5 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/ykus4
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a1ba61d060b597a9997ebbb6263973e7abd4f0f5 -
Trigger Event:
push
-
Statement type: