Skip to content

Commit 3d5c748

Browse files
authored
Merge pull request #16 from selimfirat/develop
Release v0.3.0
2 parents eaa3b7f + 2a4a4c2 commit 3d5c748

28 files changed

+597
-72
lines changed

CHANGES.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
v<0.1.0>, <08/15/2020> -- Initial release.
2-
v<0.2.0> <06/10/2023> -- Upgraded some libraries like numpy,pandas and small refactorings.
2+
v<0.2.0> <06/10/2023> -- Upgraded some libraries like numpy,pandas and small refactorings.
3+
v<0.3.0>, <05/23/2025> -- Updated dependencies to latest versions, improved documentation, added quick start example in README. Added Inqmad model. Special thanks to @TechyNilesh @Joaggi @onixlas.

MANIFEST.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
include README.rst
2+
include requirements.txt

README.rst

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,10 @@ Alternatively, you can install the library directly using the source code in Git
120120
**Required Dependencies:**
121121

122122

123-
* Python 3.8
124-
* numpy==1.23.5
125-
* scikit-learn>=1.3.0
126-
* scipy==1.10.0
123+
* Python 3.10+
124+
* numpy==2.0.2
125+
* scikit-learn==1.5.2
126+
* scipy==1.13.1
127127
* pyod==1.1.0
128128
* combo==0.1.3
129129

@@ -133,7 +133,37 @@ Alternatively, you can install the library directly using the source code in Git
133133
* rrcf==0.4.3 (Only required for `pysad.models.robust_random_cut_forest.RobustRandomCutForest`)
134134
* PyNomaly==0.3.3 (Only required for `pysad.models.loop.StreamLocalOutlierProbability`)
135135
* mmh3==2.5.1 (Only required for `pysad.models.xstream.xStream`)
136-
* pandas==2.0.3 (Only required for `pysad.utils.pandas_streamer.PandasStreamer`)
136+
* pandas==2.2.3 (Only required for `pysad.utils.pandas_streamer.PandasStreamer`)
137+
* jax>=0.6.1 (Only required for `pysad.models.inqmad.Inqmad`; required for NumPy 2.0+ compatibility)
138+
* jaxlib>=0.6.1 (Only required for `pysad.models.inqmad.Inqmad`; required for NumPy 2.0+ compatibility)
139+
140+
Examples
141+
========
142+
143+
Quick Start
144+
^^^^^^^^^^^^^^^^^^
145+
146+
Here's a simple example showing how to use PySAD for anomaly detection on streaming data:
147+
148+
.. code-block:: python
149+
150+
# Import modules.
151+
from pysad.evaluation import AUROCMetric
152+
from pysad.models import LODA
153+
from pysad.utils import Data
154+
155+
156+
model = LODA() # Init model
157+
metric = AUROCMetric() # Init area under receiver-operating- characteristics curve metric
158+
streaming_data = Data().get_iterator("arrhythmia.mat") # Get data streamer.
159+
160+
for x, y_true in streaming_data: # Stream data.
161+
anomaly_score = model.fit_score_partial(x) # Fit the instance to model and score the instance.
162+
163+
metric.update(y_true, anomaly_score) # Update the AUROC metric.
164+
165+
# Output the resulting AUROCMetric.
166+
print(f"Area under ROC metric is {metric.get()}.")
137167
138168
Quick Links
139169
============

README_template.rst

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,34 @@
77

88
.. include:: docs/installation.rst
99

10+
Examples
11+
========
12+
13+
Quick Start
14+
^^^^^^^^^^^^^^^^^^
15+
16+
Here's a simple example showing how to use PySAD for anomaly detection on streaming data:
17+
18+
.. code-block:: python
19+
20+
# Import modules.
21+
from pysad.evaluation import AUROCMetric
22+
from pysad.models import LODA
23+
from pysad.utils import Data
24+
25+
26+
model = LODA() # Init model
27+
metric = AUROCMetric() # Init area under receiver-operating- characteristics curve metric
28+
streaming_data = Data().get_iterator("arrhythmia.mat") # Get data streamer.
29+
30+
for x, y_true in streaming_data: # Stream data.
31+
anomaly_score = model.fit_score_partial(x) # Fit the instance to model and score the instance.
32+
33+
metric.update(y_true, anomaly_score) # Update the AUROC metric.
34+
35+
# Output the resulting AUROCMetric.
36+
print(f"Area under ROC metric is {metric.get()}.")
37+
1038
.. include:: docs/quick_links.rst
1139

1240
.. include:: docs/versioning.rst

_build_readme.py

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,53 @@
1+
import os
2+
import re
3+
4+
def process_literalinclude(path, language):
5+
# Make the path relative to the current directory if it starts with ../
6+
if path.startswith("../"):
7+
path = path[3:] # Remove the ../
8+
9+
if os.path.exists(path):
10+
with open(path, "r") as code_file:
11+
code = code_file.read()
12+
return f".. code-block:: {language}\n\n{code}\n\n"
13+
else:
14+
return f".. warning:: File {path} not found\n\n"
15+
116
res = ""
217
with open("README_template.rst", "r") as f:
3-
for line in f.readlines():
4-
line = line.strip("\n").replace(".. include:: ", "")
5-
if line.endswith(".rst"):
6-
tf = open(line, "r").read()
7-
res += tf.replace(".. literalinclude:: ../LICENSE", "").replace("<../LICENSE>", "<LICENSE>").replace(":class:", " ")
18+
lines = f.readlines()
19+
i = 0
20+
while i < len(lines):
21+
line = lines[i].strip("\n")
22+
i += 1
23+
24+
# Handle include directives
25+
if line.startswith(".. include:: "):
26+
include_path = line.replace(".. include:: ", "")
27+
if include_path.endswith(".rst"):
28+
with open(include_path, "r") as tf:
29+
content = tf.read()
30+
# Process literalinclude directives inside the included file
31+
content = re.sub(r'\.\. literalinclude:: (.*?)\n\s+:language: (.*?)\n',
32+
lambda m: process_literalinclude(m.group(1), m.group(2)), content)
33+
res += content.replace(".. literalinclude:: ../LICENSE", "").replace("<../LICENSE>", "<LICENSE>").replace(":class:", " ")
34+
# Handle literalinclude directives directly in the template
35+
elif line.startswith(".. literalinclude:: "):
36+
# Extract path and language
37+
path_match = re.match(r'\.\. literalinclude:: (.*)', line)
38+
if path_match:
39+
include_path = path_match.group(1)
40+
# Read the next line to get the language if available
41+
language = "python" # Default language
42+
if i < len(lines) and lines[i].strip().startswith(":language:"):
43+
language = lines[i].strip().replace(":language:", "").strip()
44+
i += 1 # Skip the language line since we've processed it
45+
46+
res += process_literalinclude(include_path, language)
847
else:
948
res += line + "\n"
1049

11-
print(res)
50+
print(res)
1251

1352
with open("README.rst", "w+") as f:
1453
f.write(res)

azure-pipelines.yml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,15 @@ trigger:
99

1010
strategy:
1111
matrix:
12-
linux38:
13-
imageName: "ubuntu-latest"
14-
python.version: '3.8'
15-
linux39:
16-
imageName: "ubuntu-latest"
17-
python.version: '3.9'
1812
linux310:
1913
imageName: "ubuntu-latest"
2014
python.version: '3.10'
2115
linux311:
2216
imageName: "ubuntu-latest"
2317
python.version: '3.11'
18+
linux312:
19+
imageName: "ubuntu-latest"
20+
python.version: '3.12'
2421

2522
maxParallel: 9
2623

deploy.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#!/usr/bin/env bash
22
rm -rf ./build/ ./dist/ ./pysad.egg-info/
3-
python setup.py sdist bdist_wheel
4-
python3 -m twine upload dist/*
3+
python3 -m build
4+
python3 -m twine upload dist/*

docs/api.rst

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Individual Anomaly Models
4343
models.ExactStorm
4444
models.HalfSpaceTrees
4545
models.IForestASD
46+
models.Inqmad
4647
models.KitNet
4748
models.KNNCAD
4849
models.LODA
@@ -169,14 +170,14 @@ Postprocessors
169170
:template: class.rst
170171
:toctree: generated
171172

172-
pysad.transform.postprocessing.AveragePostprocessor
173-
pysad.transform.postprocessing.MaxPostprocessor
174-
pysad.transform.postprocessing.MedianPostprocessor
175-
pysad.transform.postprocessing.ZScorePostprocessor
176-
pysad.transform.postprocessing.RunningAveragePostprocessor
177-
pysad.transform.postprocessing.RunningMaxPostprocessor
178-
pysad.transform.postprocessing.RunningMedianPostprocessor
179-
pysad.transform.postprocessing.RunningZScorePostprocessor
173+
transform.postprocessing.AveragePostprocessor
174+
transform.postprocessing.MaxPostprocessor
175+
transform.postprocessing.MedianPostprocessor
176+
transform.postprocessing.ZScorePostprocessor
177+
transform.postprocessing.RunningAveragePostprocessor
178+
transform.postprocessing.RunningMaxPostprocessor
179+
transform.postprocessing.RunningMedianPostprocessor
180+
transform.postprocessing.RunningZScorePostprocessor
180181

181182

182183
Statistics

docs/conf.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,8 @@
7676

7777
html_theme_options = {
7878
'canonical_url': '',
79-
'analytics_id': 'UA-XXXXXXX-1', # Provided by Google in your dashboard
8079
'logo_only': True,
81-
'display_version': False,
80+
'version_selector': False,
8281
'prev_next_buttons_location': 'bottom',
8382
'style_external_links': False,
8483
#'vcs_pageview_mode': '',
@@ -112,3 +111,5 @@
112111
# 'matplotlib': ('https://matplotlib.org/', None),
113112
#'sklearn': ('https://scikit-learn.org/stable', None)
114113
}
114+
115+
bibtex_bibfiles = ['refs.bib']

docs/examples.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
Examples
22
========
33

4+
Quick Start
5+
^^^^^^^^^^^^^^^^^^
6+
7+
Here's a simple example showing how to use PySAD for anomaly detection on streaming data:
8+
9+
.. literalinclude:: ../examples/example_usage_short.py
10+
:language: python
11+
412

513
Example Full Usage
614
^^^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)