Metadata-Version: 2.4
Name: tsanomaly
Version: 0.4.1
Summary: A Python library for autonomous, explainable, real-time anomaly detection on time-series metrics
Author: Visakh Unni
License: Apache-2.0
Project-URL: Homepage, https://github.com/visakhunnikrishnan/tsanomaly
Project-URL: Repository, https://github.com/visakhunnikrishnan/tsanomaly
Project-URL: Issues, https://github.com/visakhunnikrishnan/tsanomaly/issues
Project-URL: Changelog, https://github.com/visakhunnikrishnan/tsanomaly/blob/main/CHANGELOG.md
Keywords: anomaly-detection,time-series,monitoring,outlier-detection,changepoint,conformal-prediction,seasonality,streaming
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Classifier: Topic :: System :: Monitoring
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.24
Requires-Dist: scipy>=1.10
Requires-Dist: pandas>=2.0
Requires-Dist: pydantic>=2.5
Requires-Dist: tomli>=2.0; python_version < "3.11"
Requires-Dist: typing_extensions>=4.1; python_version < "3.11"
Provides-Extra: plot
Requires-Dist: matplotlib>=3.7; extra == "plot"
Provides-Extra: dev
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: pytest-cov>=4.1; extra == "dev"
Requires-Dist: ruff<0.16,>=0.15; extra == "dev"
Requires-Dist: mypy>=1.8; extra == "dev"
Dynamic: license-file

# tsanomaly

**A Python library for autonomous, explainable, real-time anomaly detection on time-series metrics.**

[![CI](https://github.com/visakhunnikrishnan/tsanomaly/actions/workflows/ci.yml/badge.svg)](https://github.com/visakhunnikrishnan/tsanomaly/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/tsanomaly)](https://pypi.org/project/tsanomaly/)
[![Python versions](https://img.shields.io/pypi/pyversions/tsanomaly)](https://pypi.org/project/tsanomaly/)
[![License](https://img.shields.io/pypi/l/tsanomaly)](https://github.com/visakhunnikrishnan/tsanomaly/blob/main/LICENSE)

```
pip install tsanomaly
tsanomaly detect metrics.csv     # or straight from the terminal
```

## Why tsanomaly

- **Nothing to configure** - feed it raw metrics; the sampling interval, daily/weekly
  patterns, model choice, and expected range are learned per metric. No thresholds
  to set or maintain.
- **Few false alarms** - the expected range is continuously checked against what
  actually happens (adaptive conformal inference), and how rare a deviation is comes
  from the metric's own history (extreme value theory), not a bell-curve assumption
  that breaks on real data.
- **One threshold works everywhere** - every anomaly gets a 0-100 score from how far,
  how long, and how persistent. A 90 means the same rarity on any metric, so you can
  rank and alert across metrics with a single cutoff.
- **A level shift alerts once** - when a metric permanently moves (a deploy, a config
  change), you get one "new normal" finding and the baseline re-anchors, not days of
  repeat alerts.
- **Related alerts arrive as one incident** - metrics that break together are grouped
  into a single finding, ordered by which moved first: a starting point for root
  cause.
- **Built for streaming** - O(1) per-sample updates, out-of-order tolerance, an
  opened/escalated/closed alert lifecycle with pluggable sinks, silent-metric
  detection, checkpoint/restore.
- **Every alert explains itself** - the expected range it broke, the score breakdown,
  what the model learned from which data, and the value that would *not* have
  alerted.

## Quickstart

```python
import pandas as pd
import tsanomaly as tsa

# any long frame with metric / timestamp / value columns
history = pd.read_csv("payments.csv", parse_dates=["ts"])

det = tsa.Detector.auto()
det.fit(history)                      # learn normal, per metric
result = det.detect(new_data)         # scored, explained anomalies

print(result.summary())
for anomaly in result.alerts(min_score=70):
    print(anomaly.explain().to_text())
```

Output (NYC taxi ridership around the January 2015 blizzard):

```
learned seasonality: day (strength 0.67), week (strength 0.84)

`nyc.taxi.passengers` dropped to 7076 (expected 15912.1 to 27621.4)
    for 30.5 h starting 2014-11-27 05:30 UTC - score 100.   # Thanksgiving
`nyc.taxi.passengers` dropped to 4729 (expected 17111.8 to 26890.1)
    for 9.5 h starting 2015-01-26 14:30 UTC - score 100.    # blizzard arrives
`nyc.taxi.passengers` dropped to 570 (expected 7971.81 to 24646.4)
    for 16.0 h starting 2015-01-27 06:00 UTC - score 100.   # blizzard travel ban
```

<img src="https://raw.githubusercontent.com/visakhunnikrishnan/tsanomaly/main/examples/images/quickstart.png" alt="quickstart: NYC taxi ridership with detected anomalies" width="820">

## Examples

- [quickstart.py](https://github.com/visakhunnikrishnan/tsanomaly/blob/main/examples/quickstart.py)
- [cnc_vibration.py](https://github.com/visakhunnikrishnan/tsanomaly/blob/main/examples/cnc_vibration.py)
- [streaming_alerts.py](https://github.com/visakhunnikrishnan/tsanomaly/blob/main/examples/streaming_alerts.py)
- [traffic_incident.py](https://github.com/visakhunnikrishnan/tsanomaly/blob/main/examples/traffic_incident.py)
- [root_cause.py](https://github.com/visakhunnikrishnan/tsanomaly/blob/main/examples/root_cause.py)
- [gallery.py](https://github.com/visakhunnikrishnan/tsanomaly/blob/main/examples/gallery.py)
- [adaptive_envelopes.py](https://github.com/visakhunnikrishnan/tsanomaly/blob/main/examples/adaptive_envelopes.py)

<img src="https://raw.githubusercontent.com/visakhunnikrishnan/tsanomaly/main/examples/images/cnc_vibration.png" alt="CNC mill vibration with the two Bosch-labeled bad cycles surfaced" width="820">

## Documentation

- **[Usage guide](https://github.com/visakhunnikrishnan/tsanomaly/blob/main/docs/usage.md)** - data formats, batch & streaming APIs, configuration,
  persistence, incidents, events, feedback, evaluation utilities.
- **[Architecture](https://github.com/visakhunnikrishnan/tsanomaly/blob/main/docs/architecture.md)** - the full pipeline.
- **[Examples](https://github.com/visakhunnikrishnan/tsanomaly/tree/main/examples/)**

## How it works

<img src="https://raw.githubusercontent.com/visakhunnikrishnan/tsanomaly/main/docs/images/pipeline.png" alt="the tsanomaly pipeline" width="860">

For more details, refer to [docs/architecture.md](https://github.com/visakhunnikrishnan/tsanomaly/blob/main/docs/architecture.md).

## Acknowledgements

The autonomous per-metric architecture is inspired by ideas in Anodot's published
patents, implemented here with different, modern mechanisms - see the
[acknowledgements in docs/architecture.md](https://github.com/visakhunnikrishnan/tsanomaly/blob/main/docs/architecture.md#acknowledgements).

## License

Apache-2.0
