NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #2413 most downloaded on PyPI
A Python library for anomaly detection across tabular, time series, graph, text, image, and audio data. 61 detectors, benchmark-backed ADEngine orchestration, and an agentic workflow for AI agents.
Last release 17 days ago
17 Sep 2026
Release timing varies
gaps range from 9 days to 3 months
Most releases are documented
notes for 52 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
8 years old
117 releases · first in 2018
A maintenance release focused on estimator compatibility, numerical correctness, and documentation. No new detector or dependency is introduced.
A maintenance release focused on estimator compatibility, numerical correctness, and documentation. No new detector or dependency is introduced.
k for cloning and use contamination to derive the fitted threshold and binary labels. k still controls the radius-scan early stop. #707, fixes #194.pearsonr_mat utility when there are more rows than features; previously some correlations incorrectly remained 1. #731.BaseDeepLearningDetector.fit. #740.logvar_clip as supplied to the constructor so sklearn.clone works, while validating the training value separately. #738.subset_size across fits instead of replacing the constructor argument with the first computed sample count. #737.n_components to the underlying estimator. #730.verbose=0. #735.pyod install skill created its skill directory. Detection checks the executable or user configuration instead. #723, fixes #715.sample_weight entry from GMM.fit documentation. #741.score_to_label as returning binary labels, not probabilities. #733.CITATION.cff on master, alongside contributor-workflow ignore rules and the todo/ drop box.LOCI's binary labels now follow the documented contamination-based threshold rather than a fixed k cutoff. Raw LOCI scores for a fixed k are unchanged by this fix; tied scores can still make the labeled fraction differ from the requested contamination.
Kernel PCA scores can change when n_components is specified because the limit is now honored. Sampling refits with a fractional subset_size now use the current training-set size. Previously uncomputed Pearson row pairs now receive their actual correlation values.
The ROD duplicate-weighting proposal #746 is not included.
Thanks to @Mohit-Ak, @VenishPaneliya, @Iams4kura, @busysofa15, @godarrenw, and @dishasharma23-prog.
Full changelog: v3.6.5...v3.6.6
One column per quarter.
fit() now emits a FutureWarning when a non-default n_jobs is supplied, announcing removal in v4.0.0. scikit-learn deprecated KMeans.n_jobs in 0.23, wh…
Three contributor bug fixes, plus maintainer follow-ups from a two-panel review and two rounds of /implement-review.
generate_data produced anomaly-free benchmarks for about one seed in ten (#706 by @Mohit-Ak, closes #141). The internal offset was drawn with randint(low=offset), which returns 0 roughly one time in ten for the default offset=10. Every labelled outlier then landed exactly on the origin. Over seeds 0 to 500, 46 of 501 integer random_state values produced an outlier block with exactly zero per-feature variance. KNN scored roc_auc of exactly 0.0 on seeds 41, 48, 50 and 85. The offset is now redrawn only when it comes out as 0.
Data from any seed that was not degenerate is unchanged. That was verified by an RNG call-sequence differential over 11,280 offset and seed combinations. It compared both the generated arrays and the final RandomState, and found zero regressions. The comparison is between the parent and patched code on one machine; generated values have never agreed bit-for-bit across platforms, since randn goes through a log that libm implementations round differently in the last ulp. Data from the 46 degenerate seeds necessarily changes, since its previous form was unusable.
generate_data now also accepts a float offset in the open interval (1, 2), which previously raised ValueError. An offset below 1 still raises, now as an explicit ValueError. The inlier spread does not scale with offset, so a smaller box would sit inside the inlier cloud and leave the labels anti-correlated with outlierness.
CBLOF.n_jobs was accepted but never stored (#719 by @bishtashish708, closes #713). get_params() reported None and sklearn.base.clone() dropped the value. It is now stored unmodified, restoring the estimator contract.
fit() now emits a FutureWarning when a non-default n_jobs is supplied, announcing removal in v4.0.0. scikit-learn deprecated KMeans.n_jobs in 0.23, where it already had no effect after the move to OpenMP, and removed it in 1.0. The value is no longer forwarded to KMeans under any scikit-learn version. Use OMP_NUM_THREADS, threadpoolctl, or a configured custom clustering_estimator instead. Detector output is unaffected.
ROD returned nan with a RuntimeWarning when a sample sat on the geometric median (#722 by @bishtashish708, closes #523). Such a sample has a zero-length displacement vector, so its rotation angle is undefined. The undefined angle is now excluded from the MinMaxScaler fit and the row is assigned its limiting cost of 0 directly.
A second case is now handled explicitly. When the geometric median falls on the coordinate origin, no rotation angle is defined for any row. That subspace emits a RuntimeWarning, and its costs are driven only by the distance from the geometric median.
random_state values listed above. All other seeds are bit-identical.decision_scores_ and labels_ change for any input containing a point at the geometric median. Scores on data with no such point are bit-identical.CBLOF emits a new FutureWarning for a non-default n_jobs. It repeats on each fit call rather than once per process, because scikit-learn's internal use of catch_warnings invalidates the caller's warning registry.generate_data no longer accepts offsets that were never scalars but which NumPy used to coerce, such as '2', b'2', and one-element sequences or arrays. Those forms were outside the documented contract in every released version.pyod/test/conftest.py guarded its torch import with except ImportError. A broken rather than absent install raises OSError instead, which aborted collection of the whole suite rather than skipping the torch-dependent modules. The guard now distinguishes the two: only ModuleNotFoundError for torch counts as absence. A broken install skips those 25 modules with a warning locally, and re-raises under CI. A silent skip there would let a job that promised full torch coverage pass while running none of it.
DevNet has no constructor docstring and exposes unused arguments (#714). pyod info infers Claude Code from a directory that pyod install skill itself creates (#715). A separate question about ROD's rotation reference direction is tracked in #726.
Full changelog: v3.6.4...v3.6.5
A documentation-accuracy release. No runtime behavior changes: an executable-AST comparison confirms the 43 touched model modules differ only in docst
A documentation-accuracy release. No runtime behavior changes: an executable-AST comparison confirms the 43 touched model modules differ only in docstrings.
An audit compared every constructor signature against its numpydoc block, attempted all 72 example scripts, and built the Sphinx site. What it found was mostly not wrong prose but documentation that had quietly drifted away from the code.
Seven documented constructor parameters raise TypeError when passed. A user following the docs got an error, and the error looked like their mistake:
GMM(verbose=0) # TypeError
LUNAR(n_neighbors=5) # TypeError - the real keyword is n_neighbours
RGraph(random_state=42) # TypeError
SUOD(cost_forecast_loc_fit=...) # TypeErrorThese entries are removed, or renamed to the real keyword where one exists. LUNAR's entry keeps a note about the British spelling so a search for n_neighbors still lands somewhere useful.
Roughly fourteen, including ABOD.n_neighbors (documented 10, actually 5), ALAD.epochs (500 / 200), ALAD.preprocessing (True / False), AnoGAN.learning_rate_query (0.001 / 0.01), RGraph.transition_steps (20 / 10), and DIF.hidden_neurons, documented as [64, 32] while the constructor substitutes [500, 100] for the None default.
Also corrected: labels_ was typed as int in BaseDetector and in every detector that copied the wording, when it is a numpy array of shape (n_samples,); and XGBOD.labels_ claimed threshold_ is applied to decision_scores_ when fit() never sets threshold_.
sphinx.ext.napoleon had never been enabled, so every numpydoc Parameters and Attributes heading was parsed as an RST section title rather than a field list. A full build went from 310 warnings and 242 class="problematic" spans to 41 and 5, and the :attr: links for decision_scores_ and labels_ — the two attributes every user touches after fit() — resolve for the first time.
Enabling the parser also exposed five docstrings it could not read, which had been inert text until now: AnoGAN emitted 1 of its 16 parameters, RGraph 5 of 16, DIF produced 30 fields for an 11-parameter constructor, XGBOD turned a commented-out block into four bogus parameter names, and the SO_GAAL in so_gaal_new.py had an entirely empty Parameters section. All five are repaired, and a sweep over all 62 detectors now parses every documented parameter with no bogus or missing entries.
Removed a dead pyod.models.auto_encoder_torch section (the module was deleted in 2024; a duplicated :exclude-members: made the directive raise DuplicateOptionError, which Sphinx stripped from the output, so the page silently rendered a heading with no body) and de-duplicated the pyod.models.base automodule.
clf.fit(X_train) without ever defining X_train, and used visualize without importing it. Pasting it raised NameError. This block is the GitHub landing page and the PyPI description.docs/install.rst documented a pytorch extra that does not exist. pip treats an unknown extra as a warning, so pip install pyod[pytorch] succeeded while installing none of the PyTorch stack, and the mistake surfaced later as an ImportError. The table now keys on the extras actually defined in pyproject.toml, adds the nine that were missing plus pip install pyod[all], corrects the MCP tool count from seven to ten, and drops the claim that pyod install skill supports Claude Desktop, which no code path targets.mad_example.py generated two features for a univariate-only detector, and qmcd_example.py appended ground-truth labels to the feature matrix before calling predict — which raised, and would have leaked test labels if it had not. Both run now. examples/data/mat_file_conversion.py byte-compiles after removal of mid-file Python 2 __future__ imports; end-to-end conversion still needs its optional dependencies and external source datasets.
Three findings need a runtime decision and are tracked separately: #713 (CBLOF.n_jobs accepted but unused — now disclosed in its docstring), #714 (DevNet has no class docstring and five parameters, including random_state, are never read, so runs are not reproducible), and #715 (pyod info infers "Claude Code detected" from a directory pyod install skill creates itself).
Full suite: 1532 passed. Reviewed via /implement-review with Codex.
pyod.dev website badge, brand assets, and a SECURITY.md vulnerability-reporting policy ( #705 ).
A maintenance release. The headline item is a DeepSVDD defect that produced silently meaningless results.
In 3.6.0 through 3.6.2, DeepSVDD did not train: loss.backward() was commented out, so no gradient ever reached the weights and scores came from the randomly initialized network. Restoring the backward pass (#704, thanks @DMZ22) then exposed three defects it had been masking, the most serious being that fit() set the hypersphere center to 0.0 while the initialized center was written somewhere the objective never read.
For a bias-free ReLU network the all-zero weights map every input to the origin, so a zero center is exactly the trivial solution of Deep SVDD (Ruff et al., ICML 2018, Proposition 1). Training converged to a collapsed hypersphere. On a 17-dataset ODDS benchmark the released behavior returned a single distinct score on 10 of 17 datasets while still clearing a ROC floor, because ordering can be induced by floating-point noise as small as 1e-24. The detector was useless and said nothing about it.
Fixed in this release:
c_ attribute that the objective and scorer actually read.l2_regularizer=0.1 as weight decay, five orders of magnitude above the reference implementation's 5e-7. That decay drives weights toward zero and compounds the collapse.Measured effect: mean ROC AUC across the 17 datasets rises from 0.601 to 0.748, with score collapse eliminated on all 17.
Calibration, stated plainly: 0.748 is level with the 0.746 obtained by the untrained network. This release restores DeepSVDD to its baseline rather than improving on it. Deep SVDD assumes a clean one-class training set while PyOD fits it unsupervised on contaminated data; in a controlled comparison, training on genuinely normal samples only reaches 0.879. The remaining gap largely reflects that assumption mismatch, and the limitation is now documented in the class docstring.
| Change | Impact |
|---|---|
l2_regularizer default 0.1 -> 5e-7 |
Matches the reference implementation. Changes behavior for every existing caller. |
Fitted center moved from c to c_ |
c is now configuration only and is no longer overwritten by fit(). Code reading clf.c for the fitted value should read clf.c_. |
c=0.0 now raises ValueError |
It is the trivial-solution condition. Pass c=None to initialize from data, or a non-zero center. |
New learning_rate parameter (default 1e-4) |
Additive; no action needed. |
c is also validated now: a scalar is expanded to the network output width, a vector must match that width, non-finite values are rejected, and the tensor is copied so a later mutation of your array cannot change the fitted estimator.
pyod[huggingface]-only install previously raised ImportError before the existing fallback could run.test_resolve_st_instance_no_download no longer breaks on sentence-transformers 5.6, which rejects the empty modules=[] construction the test relied on (#710).test_model_clone methods previously only checked that clone() did not raise.c/get_params/clone, refit re-initialization, all-zero rejection, and custom-center validation.SECURITY.md vulnerability-reporting policy (#705).Reviewed via /implement-review with Codex across five rounds.
PyOD 3.6.2: security release ( CVE-2026-15529 )
This release hardens model persistence against unsafe deserialization.
pyod.utils.persistence.load() and pyod.utils.persistence.compat_load() now require an explicit trusted=True before they will deserialize a pickle/joblib artifact. Previously both unpickled the file first, so the envelope, schema, and strict=True checks ran only after any embedded code had already executed. The trust guard now runs before joblib.load(), so those dependency checks are never mistaken for a safety boundary. (CVE-2026-15529; addresses #697 and PR #698 by @3em0.)
load() and compat_load() now raise ValueError unless called with trusted=True, including on artifacts you saved yourself with save(). Update existing round trips:
from pyod.utils.persistence import load
clf = load("model.pyod.joblib", trusted=True)The internal fall-through from load() to compat_load() forwards the acknowledgement automatically, so load(path, trusted=True) still recovers legacy dtype-mismatched artifacts in a single call.
trusted=True.Reviewed via /implement-review (Codex, two rounds).
Maintenance and contributor release since v3.6.0. No breaking API changes; buildable detector count unchanged at 61.
Maintenance and contributor release since v3.6.0. No breaking API changes; buildable detector count unchanged at 61.
pyod.models.thresholds wrappers and the BaseDetector threshold path now use the PyThresh v1 API (.fit() / .labels_ / .predict() instead of .eval()); the dependency pin moves to pythresh>=1.0.0.SentenceTransformer instance directly as the encoder, or a local filesystem path loaded with local_files_only=True (no Hub call) for offline use. Also fixes a resolver-order bug where a SentenceTransformer instance was wrapped as a CallableEncoder (calling model(X) instead of model.encode(X)).GMM, IForest, LOF, and OCSVM now run check_array inside decision_function, so scoring a pandas DataFrame after fitting no longer emits the scikit-learn feature-name UserWarning. The predict / predict_proba / predict_confidence paths route through decision_function, so the single fix covers them.AudioAE and the audio modality are now in the README and docs algorithm tables, with a new pyod.models.audio API page (v3.6.0 shipped AudioAE without a table row).SentenceTransformer(modules=[]).Full changelog: https://github.com/yzhao062/pyod/compare/v3.6.0...v3.6.1
Audio joins tabular, time-series, graph, text, and image as a first-class PyOD modality on the agentic and multimodal line. The additions are encoder-
Audio joins tabular, time-series, graph, text, and image as a first-class PyOD modality on the agentic and multimodal line. The additions are encoder-agnostic and additive, with no change to existing detectors.
AudioFeatureEncoder: each clip becomes a 74-dim handcrafted acoustic vector (20 MFCC, 12 chroma, 5 spectral descriptors, each as mean and standard deviation over frames, via librosa). Registered as the audio-mfcc encoder.EmbeddingOD.for_audio(quality=...): fast=IForest, balanced=KNN, best=LUNAR over the audio encoder, so any classical detector runs on audio (embed then detect).AudioAE: DCASE-style log-mel reconstruction autoencoder that reuses the PyOD AutoEncoder, scored by per-clip mean reconstruction error. Requires torch.for_audio as the default, AudioAE as the deep alternative); knowledge-base entries for AudioAE and audio support on EmbeddingOD and MultiModalOD.pip install pyod[audio]: new optional extra (librosa, soundfile).Buildable detector count rises from 60 to 61: 61 total (43 tabular, 7 time-series, 8 graph, 2 text, 2 image, 1 multimodal, 3 audio).
pip install --upgrade pyod # core
pip install "pyod[audio]" # audio encoder (librosa, soundfile)
pip install "pyod[torch,audio]" # AudioAE (deep)
References the public methods (the DCASE 2020 Task 2 log-mel autoencoder baseline, and MFCC, chroma, and spectral features via librosa). No breaking API changes.
Full changelog: https://github.com/yzhao062/pyod/compare/v3.5.4...v3.6.0
LLMCallable is a Protocol, not an inheritance-required base class. No breaking changes.
v3.5.4 bundles two things: the KB-tools API for agent-driven and LLM-driven detector routing (staged as v3.5.3 but never published to PyPI), and a claims-honesty remediation pass that aligns the v3 agentic-layer docs, skill, CLI, and examples with what an internal audit could verify. Both halves were reviewed across multiple implement-review rounds with Codex.
ADEngine.get_kb_for_routing(profile, top_k=3, constraints=None) returns a structured KB snapshot of every shipped detector (strengths, weaknesses, best_for, avoid_when, complexity, benchmark rank, modality match), filtered by constraints.exclude_detectors / constraints.data_type_strict and sorted by modality-specific benchmark rank.ADEngine.make_plan(detector_choices, justifications=None, params=None) validates a caller-chosen ordered detector list against the KB and returns a DetectionPlan consumable by build_detector / run.ADEngine.plan_detection(profile, *, llm_client=callable, top_k=3, llm_strict=None) accepts a user-supplied (prompt: str) -> str callable wrapping any LLM SDK. The engine builds the routing prompt, invokes the callable, parses the response, and returns the same DetectionPlan. On call or parse failure it falls back to rule routing with a RuntimeWarning; llm_strict=True (or PYOD3_LLM_STRICT=1) re-raises instead.pyod/utils/_llm.py: LLMCallable Protocol, RoutingParseError, build_routing_prompt, parse_routing_response.pyod info), skill prose, pyproject.toml, and docs, by excluding the one planned / non-buildable entry from buildable counts.separation quality metric reframed as a descriptive, label-free diagnostic computed from the run's own predicted labels. In ADEngine consensus this is circular (labels come from majority vote, scores are rank-averaged), so it is no longer presented as independent correctness evidence.random_state docstring states the verified guarantee.Every v3.5.2 caller pattern produces identical output. The new top_k, llm_client, and llm_strict parameters are keyword-only with backward-compatible defaults. LLMCallable is a Protocol, not an inheritance-required base class. No breaking changes.
53 new tests for the KB-tools surfaces (schema, filters, ordering, KB validation, top_k clamping, LLM stub and fallback paths, strict-mode precedence), plus count-pinning tests (test_pyod_info_excludes_planned_detectors, test_skill_count_prose_matches_kb). All existing ADEngine tests continue to pass.
pip install --upgrade pyodPyPI goes 3.5.2 to 3.5.4 directly; 3.5.3 was staged but never published.
Three reproducibility / kwargs-forwarding bug fixes from the PyOD 3 paper (KDD 2027 ADS Cycle 1) §5 evidence work, plus partial progress on a long-sta
Three reproducibility / kwargs-forwarding bug fixes from the PyOD 3 paper (KDD 2027 ADS Cycle 1) §5 evidence work, plus partial progress on a long-standing open issue. Reviewed via four rounds of implement-review with Codex (rounds 1 through 3 each surfaced real findings that were addressed before merging; round 4 cleared with no new findings).
ABOD / KNN / LUNAR / SOD over-forwarded **kwargs to sklearn's NearestNeighbors, crashing on any kwarg outside NearestNeighbors's signature (the sklearn-convention random_state, a typo like n_neighbours, etc.).ADEngine.investigate was non-deterministic on byte-identical input because no public API pinned random_state.LODA results were not reproducible because the constructor did not accept random_state and the inner np.random.* calls fell back to numpy's module-level state.random_state across pyod): ADEngine, LUNAR, LODA, and EmbeddingOD now accept random_state. Deep-learning detectors (DIF, AutoEncoder, DeepSVDD, ...) remain follow-up work tracked under #599.Removed **kwargs from each __init__ and stopped forwarding **self.kwargs / **kwargs to NearestNeighbors. The six named forwarding parameters added in b8f6c81 (algorithm, leaf_size, metric, p, metric_params, n_jobs) still cover the use case #654 originally asked for. Unknown kwargs on ABOD / KNN / SOD now raise a clean TypeError at construction that names the detector class and does NOT leak NearestNeighbors.
LUNAR is the one #685 detector that is actually stochastic. Instead of rejecting random_state, LUNAR.__init__ declares an explicit random_state parameter (accepts int or numpy.random.RandomState) that threads through:
torch.manual_seed (and torch.cuda.manual_seed_all when CUDA is available), before SCORE_MODEL / WEIGHT_MODEL construction and again in fit().RandomState returned by sklearn.utils.check_random_state.train_test_split(..., random_state=rng) for the validation split.generate_negative_samples(..., random_state=rng) for the synthetic anomaly generator (new signature).Added random_state to ADEngine.__init__. Plumbed through ADEngine.build_detector -> build_detector_from_plan -> build_from_preset. The factory injects random_state into plan['params'] only for detector classes whose __init__ declares an explicit random_state parameter (verified via inspect.signature); detectors that do not declare it are instantiated unchanged. Plan-level random_state in params wins over the engine default. The factory copies plan['params'] before injecting so the caller's plan dict is not mutated.
EmbeddingOD preset coverage is end-to-end: EmbeddingOD.__init__ accepts random_state, EmbeddingOD.fit forwards into resolve_detector(detector, contamination, random_state=...) which injects the seed into the inner shortcut detector (LUNAR by default), and EmbeddingOD._preprocess_fit passes the seed to PCA(n_components=self.reduce_dim, random_state=...) so a preset plan with reduce_dim is fully deterministic. The external encoder's own inference (sentence-transformers, DINOv2) is documented as NOT seeded.
Added random_state to LODA.__init__. Threaded through sklearn.utils.check_random_state and replaced the two np.random.* call sites (np.random.randn for the projection matrix and np.random.permutation for the per-cut feature subset) with rng.randn and rng.permutation. LODA(random_state=42) is now bit-stable across reruns, and ADEngine(random_state=42) propagates the seed through the existing factory path.
Soft API removal: the accidental arbitrary-**kwargs surface added to ABOD / KNN / LUNAR / SOD in commit b8f6c81 is gone. Code that relied on it (for example ABOD(some_unknown_kwarg=value)) now fails fast at the constructor instead of at the NearestNeighbors constructor inside fit. The six named forwarding parameters still work; this is the only meaningful behavior change.
ADEngine() without a seed retains v3.5.1 behavior (no determinism guarantee). Existing callers of LODA(), LUNAR(), EmbeddingOD() without random_state see no behavior change.
31 new regression tests across 6 test files. All pass locally. The 4 pre-existing TestFastABOD / TestKnnNearestNeighborsConfig / TestLUNARNearestNeighborsConfig / TestSODNearestNeighborsConfig failures on Windows are MKL DLL load errors that reproduce on a clean tree and are unrelated to this PR.
pip install --upgrade pyodor, with conda-forge (auto-released within a few hours):
conda install -c conda-forge pyod=3.5.2No breaking API changes. No deprecated APIs removed.
Patch release with bug fixes across LUNAR, DIF, SOS, SUOD, LOF, and the GAAL family, plus the v3.5.0 follow-on work and the NSF funding acknowledgment.
LUNAR.__init__ previously defaulted to a single shared MinMaxScaler() instance, so two LUNAR instances with different feature dimensions invalidated each other's predict path. Default is now scaler=None, materialized to a fresh MinMaxScaler per fit via _resolve_scaler(). User-supplied scalers are deep-copied. False disables scaling entirely. The fitted scaler lives on self.scaler_ so sklearn.base.clone() round-trips. Thanks to @jbbqqf for the fix.DIF.fit double-normalized: it min-max-scaled X, then called self.decision_function(X) on the already-scaled data, and decision_function re-scales internally. decision_scores_ and decision_function(X_train) now match. Thanks to @jbbqqf.suod package is absent; the actionable ImportError ("Install it with pip install suod") now fires only when SUOD() is constructed. Thanks to @jbbqqf.novelty=True as the PyOD default. PyOD's BaseDetector contract is fit-then-predict on unseen data, which scikit-learn's LocalOutlierFactor only allows in novelty mode; the code default has been True for years but the docstring claimed False. Regression test pins both the inspect.signature default and the docstring substring. Thanks to @jbbqqf.pyod/models/gaal_base.py print-then-crash optional-torch handling replaced with a guarded import and an actionable ImportError. Follow-up extends the same fix to pyod/models/mo_gaal.py, pyod/models/so_gaal.py, and pyod/models/so_gaal_new.py, so user-visible imports like from pyod.models.mo_gaal import MO_GAAL no longer print-then-crash when torch is missing. All four GAAL files now raise the unified message pointing at pip install pyod[torch] or pip install torch. Thanks to @tuanaiseo for the initial PR._get_perplexity inner-loop reductions use ndarray.sum() directly. Numerical equivalence test asserts bit-exact match against the previous np.sum form. Thanks to @jbbqqf.PyOD is now supported in part by the U.S. National Science Foundation under Award No. 2346158, "NSF POSE: Phase II: OpenAD: An Integrated Open-Source Ecosystem for Anomaly Detection." See the Acknowledgments section in the README for the full attribution.
6 new regression tests added (1 each in test_lof, test_dif, test_sos, test_suod; 2 in test_lunar).
No breaking API changes. No deprecated APIs removed.
External contributors this release: @jbbqqf (5 PRs) and @tuanaiseo (1 PR).
Sustainable cross-sklearn-version model persistence. Closes #519 .
Sustainable cross-sklearn-version model persistence. Closes #519.
pyod.utils.persistence is a new module with three additive helpers:
save(clf, path, metadata=None) writes a versioned envelope alongside the model: pyod / sklearn / numpy / scipy / joblib / python versions, a save timestamp, the model class, and an optional user metadata dict.load(path, strict=False, return_metadata=False) reads the envelope, compares the recorded dependency versions against the running environment, and emits a UserWarning on drift in sklearn, joblib, numpy, or scipy. strict=True escalates warn-severity drift to ValueError. Python-version drift is severity info and never raises on the normal envelope path. return_metadata=True returns (model, envelope_without_model_field).compat_load(path, mmap_mode=None) loads legacy artifacts whose sklearn Tree node dtype no longer matches the running sklearn (the recurring user pain in #519). It patches joblib's BUILD-opcode dispatch on a NumpyUnpickler subclass so saved Tree state is realigned to the running dtype before sklearn's own __setstate__ would raise.load() falls through to compat_load() automatically when joblib.load raises the documented dtype prefix; the original exception is preserved via raise ... from. A non-prefix ValueError from joblib.load propagates without invoking compat_load.
Dtype realignment is allowlist-driven:
_TREE_NODE_FIELD_DEFAULTS (currently {"missing_go_to_left": 0}, the pre-1.3 sklearn default) zero-fills documented missing fields._TREE_NODE_FIELD_RENAMES (empty in v3.5.0) maps known renames; rename targets are resolved before the missing-field default check, so a future rename does not also need a default entry.ValueError with a re-fit recommendation.Current dtype is discovered dynamically from sklearn.tree._tree.NODE_DTYPE; no hardcoded layout. A single UserWarning recommending re-fit fires when at least one Tree was realigned; non-tree artifacts (ECOD, COPOD, HBOS, LOF, ...) pass through silently.
joblib>=1.5 is now required because compat_load reuses joblib.numpy_pickle._validate_fileobject_and_memmap and the joblib 1.5 NumpyUnpickler(filename, file_handle, ensure_native_byte_order, mmap_mode=...) constructor; older joblib lacks both. The joblib internal imports are guarded with a clear ImportError recommending an upgrade.
31 new test cases plus 9 subtests in pyod/test/test_persistence.py covering Tree-dtype realignment (synthetic aged pickles via an _OldDtypeTree pickle-time shim), the committed sklearn 1.2.2 binary fixture under pyod/test/fixtures/iforest_sklearn_1_2_x.joblib (regenerable via regen_iforest_sklearn_1_2.py), envelope round-trip, drift warnings including the info-only python_version silent case, strict-mode rejection paths, schema-version validation including a future-version reject, the strict-after-compat no-drift case, exception chaining, the rename pattern without a paired default, and a monkey-patched joblib.load test that pins the exact-prefix fall-through gate.
New persistence-nightly job in testing-cron.yml installs pre-release sklearn / numpy / scipy / joblib (scientific-python nightly index) and runs only test_persistence.py; failure surfaces upstream dtype evolution before downstream users hit it. Not a release blocker.
docs/model_persistence.rst rewritten (16 → 218 lines) with quick-start, trust-boundary, why-versioning, legacy-load decision tree, cross-sklearn-version compatibility section, troubleshooting table keyed on error text, strict-mode notes, and envelope-metadata-reading guidance. docs/pyod.utils.rst cross-references the new module. examples/save_load_model_example.py leads with persistence.save / persistence.load and notes raw joblib as a secondary alternative.
No breaking API changes. Existing joblib.dump / joblib.load workflows continue to work. For new code, prefer from pyod.utils.persistence import save, load.
inspect_artifact(path) and pyod inspect <path> CLI (Phase 3, needs a .pyod zip container layout).Plan reviewed by Codex across four plan-review rounds; implementation reviewed by Codex across three execution-review rounds. All 6 findings raised over the loop were resolved before merge.
O3 detector failure recovery. ADEngine.run() now signals partial-detector failure via next_action.action='recover_detector_failure', listing the faile
ADEngine.run() now signals partial-detector failure via next_action.action='recover_detector_failure', listing the failed detectors and a planner-suggested replacement set. The new iterate(state, {'action': 'recover'}) action substitutes failed slots while preserving successful ones (no silent auto-substitution); pass {'detectors': [...]} to override the suggestion. The iterate() phase guard accepts both 'detected' and 'analyzed' for 'recover' so the agent can substitute immediately after run(). Other actions still require 'analyzed'.engine.contamination_diagnostics(state, threshold_sweep=...) reports the contamination value the run actually used, the consensus flagged rate, score percentiles (50/75/90/95/99), and an optional sweep showing what fraction would be flagged at each candidate contamination value. No state mutation; the agent uses these numbers to choose a value before iterating.engine.validate(state, y) returns label-based metrics (precision, recall, F1, ROC AUC, AP) for the consensus, every successful detector, and the analyzer-selected best detector, plus a consensus_helped flag and FP/FN row indices. Pure functional; ROC AUC and AP return None when y has only one class instead of raising.explain_findings accepts feature_names and threads it through to feature_contributions, which now returns enriched dicts with feature, name, value, mean, z_score, and direction (high/low). Backward compatible: existing feature and z_score keys are preserved.compare_detectors. When names is omitted, compare_detectors consults benchmark rankings instead of returning catalog-order slices: ADBench overall_top_5 for tabular, per-detector benchmark_rank for time series via TSB-AD. Modalities without a ranking fall back to catalog order.plan_detection now always exposes effective contamination in plan['params'] so the MCP plan_detection -> build_detector chain emits a code snippet that names the value the agent will run with.run_detection, analyze_results, explain_findings), bringing the registered tool count to ten and letting an agent close the plan -> run -> analyze -> explain loop without local glue. Round-tripping uses JSON; numpy arrays move as lists and are rebuilt for the engine call. Stateful investigate/iterate MCP tools remain deferred.workflow.md autonomous-loop step 4 documents the recovery branch; Trigger 4 separates "low separation" (try a different mix) from "low stability" (adjust contamination); Trigger 2 points the agent at contamination_diagnostics.No breaking API changes. New methods are additive (validate, contamination_diagnostics, the 'recover' iterate action). explain_findings and feature_contributions add fields without removing old ones. compare_detectors ordering changes when names is omitted (catalog order to benchmark rank), which is intended behavior for an agent-facing default.
80 new tests across test_recover.py, test_validate.py, test_contamination_diagnostics.py, test_ad_engine_compare.py, expanded test_ad_engine.py, and expanded test_mcp_server_import.py. Test infrastructure: test_readme_rst.py falls back to OptionParser on docutils < 0.19; test_thresholds.py skips the class when pythresh's resource loading is broken (Python 3.9 + pythresh 1.1.0 wheel lacks pythresh/models/__init__.py); test_linear_block checks output shape rather than exact equality with torch.zeros(2, 1).
The audit-cycle commits (37e8a6a..d4e10d0) landed directly on development as squash merges from local fix/* branches under the implement-review loop with Codex.
pip install --upgrade pyod
PyPI: https://pypi.org/project/pyod/3.4.0/
docs/superpowers/research/2026-05-09-agentic-hindsight-observations.mddocs/superpowers/research/2026-05-09-mcp-spark-test-notes.mdFixed: `quality['stability']` is now informative. The old formula computed the Jaccard index of nested top-k slices and collapsed to a constant ~0.817
quality['stability'] is now informative. The old formula computed the Jaccard index of nested top-k slices and collapsed to a constant ~0.817 for any reasonable k, hiding cutoff-sharpness signal from od-expert and downstream consumers. The new formula measures the standardized score gap at the rank-k boundary, clipped to [0, 1]. quality['overall'] and quality['verdict'] may shift on the same data because the constant no longer dominates the average; the od-expert skill's stability < 0.5 trigger threshold may need empirical recalibration. Closes #667 — thanks to @Quentin62 for reporting.pyod/utils/_quality_metrics.py, _kb_router.py, _detector_factory.py, _nl_feedback.py carry the metric, routing, factory, and feedback-parsing logic that previously lived inside ad_engine.py. The supported import path is unchanged: from pyod.utils.ad_engine import ADEngine still exposes exactly 20 public methods with the same signatures.iterate(feedback) now raises ValueError on malformed dicts (previously produced a confirm_with_user next-action silently). Per-detector exceptions in run() and analyze() now emit WARNING logs before swallowing. The natural-language feedback parser uses word-boundary regex matching instead of substring in, so a few previously incidental matches no longer fire (e.g., "withoutdoubt" no longer matches the exclude pattern).No public API changes. Same dict keys (quality['stability'], quality['overall'], quality['verdict']), same method signatures, same default behavior except where noted above. The stability numeric value changes for the same input data because the formula changed; the key name is preserved deliberately to avoid breaking v3.2.x users.
pip install --upgrade pyod
Point release fixing correctness regressions shipped in the v3.2.0 od-expert skill, with a redesigned interactive demo and a pytest safety net to prev
Point release fixing correctness regressions shipped in the v3.2.0 od-expert skill, with a redesigned interactive demo and a pytest safety net to prevent this class of regression going forward. No breaking API changes.
state.plan[...] → state.plans, state.scores → state.consensus['scores'], state.best_detector → state.analysis['best_detector'], and a phantom engine.start(X, y=labels) supervised path (there is no y parameter on ADEngine.start). Labelled data should use the classic XGBOD.fit(X, y) / predict(X) path; this is now what the skill and docs recommend.state.profile['estimated_contamination'] and state.profile['encoder'] were cited in v3.2.0 prose but do not exist on InvestigationState. The skill now tells the agent to observe state.analysis['consensus_analysis']['anomaly_ratio'] post-run instead.state.plans[:3] lists re-probed against a live ADEngine and corrected across references/tabular.md, references/time_series.md, references/graph.md, and references/text_image.md. The decision tables in those files are now explicitly labeled as expert heuristics, not predictions of engine.plan output; the agent is pointed at state.plans for the live selection.references/workflow.md now seeds np.random.seed(42), excludes the trailing label column (X = df.values[:, :-1]), and reports the numbers that one-pass code actually produces (172/1831 flagged at the default contamination of 0.1, validation precision 85/172 at recall 85/176).pyod/test/test_skill_api_refs.py — a pytest safety net that walks ADEngine + InvestigationState via live dry runs (tabular / time series / text) and validates every state.X / state.X['a']['b'] / engine.X(...) reference in the skill content. Catches invalid keyword arguments through inspect.signature. Ships a synthetic negative test that fabricates all five regression shapes (bad attr, bad nested key, bad kwarg, missing method, missing prose attr) and asserts the scanner flags them.examples/agentic_demo.html — now uses a diabetes screening dataset (examples/data/pima.csv, 768 patients, 8 features) with dark "od-expert decisions" callouts alongside the agent's turns showing modality triage, top-10 pitfall checks, the 11 adaptive escalation triggers, and the resulting plan. Two-column CSS grid with sticky callouts and overflow guards for narrow viewports. (Previously Pima Indians Diabetes; renamed to diabetes screening in user-visible text.)scripts/render_agentic_demo.py — Playwright headless-Chromium script that regenerates docs/figs/agentic-demo.png from the HTML demo source. Re-runnable any time the HTML changes so the readthedocs figure stays in sync.docs/examples/agentic.rst with a new "What the skill encodes" section documenting the master decision tree, top-10 pitfalls, 11 escalation triggers, on-demand reference files, KB-derived detector list, and CI safety nets./implement-review with Codex on this batch; 9 findings total (3 High + 4 Medium + 2 Low), all resolved.pip install --upgrade pyod
pyod install skill # refresh ~/.claude/skills/od-expert/ with the fixed content
pyod info
v3.0.0 / v3.1.0 / v3.2.0 user code keeps working unchanged.
No breaking changes. v3.0.0 / v3.1.0 user code keeps working unchanged.
Minor release that transforms the bundled od-expert skill from a 78-line API documentation file into a real expert distillation (~1000 lines) that drives PyOD's ADEngine autonomously for non-expert users.
od-expert skill (~1000 lines across SKILL.md + 6 reference files).
SKILL.md: activation rules, master decision tree, top-10 critical pitfalls, 11 adaptive escalation triggersreferences/workflow.md: autonomous loop pattern, escalation phrasings, cardio canonical worked example, result interpretation patternsreferences/pitfalls.md: 23 additional pitfalls organized by phase (preprocessing / detection / analysis / reporting / iteration), severity-taggedreferences/{tabular,time_series,graph,text_image}.md: per-modality decision tables, KB-derived detector lists, worked snippets, modality-specific pitfallsdocs/skill_maintenance.rst documenting the hybrid hand-written + KB-derived pattern, manual + automatic update workflows, and the recipe for adding new skills.scripts/regen_skill.py refreshes KB-derived sections in skill files from pyod.utils.knowledge.pyod/test/test_skill_kb_consistency.py asserts every backtick-wrapped detector name in the skill matches the live KB; drift fails the build loudly.pyod install skill now copies the entire skill directory tree (including references/), not just SKILL.md.SUOD and FeatureBagging so engine.explain_detector() now correctly surfaces their suod and combo extras as install hints.docs/superpowers/research/2026-04-13-od-ad-state-of-art.md.docs/v3.3-backlog.md for future releases.pip install --upgrade pyod
pyod install skill
pyod info
No breaking changes. v3.0.0 / v3.1.0 user code keeps working unchanged.
…to Codex, and tightening the packaging layer. No breaking changes.
Minor release focused on making the Claude Code od-expert skill install flow self-discoverable, extending agent support to Codex, and tightening the packaging layer. No breaking changes.
pyod CLIA new top-level command with three subcommands:
pyod install skill # Claude Code / Claude Desktop
pyod install skill --project # Codex (project-local)
pyod info # self-diagnostic
pyod mcp serve # alias for `python -m pyod.mcp_server`
The legacy pyod-install-skill console script from v3.0.0 still works as an alias and now shares a single code path with pyod install skill.
pyod info self-diagnosticPyOD version: 3.1.0
Detectors (ADEngine): 61 total (44 tabular, 7 time-series, 8 graph, 3 text, 2 image, 1 multimodal)
Classic API: OK
ADEngine (Layer 2): OK
MCP extra: NOT INSTALLED (install: pip install pyod[mcp])
od-expert skill: INSTALLED (user-global) at /Users/you/.claude/skills/od-expert/SKILL.md
Detected agents: Claude Code, Codex
Detector counts come directly from pyod.utils.knowledge.algorithms (no hardcoded modality list). Agent stack detection checks both ~/.claude/ (Claude Code) and ~/.codex/ (Codex) and prints actionable install commands if the skill is missing.
Codex does not have a user-global skill directory like Claude Code. Instead, it reads shared skills from ./skills/<name>/ per project. pyod install skill --project writes exactly there, so a single command enables od-expert for Codex in any project. pyod info reports both Claude Code and Codex when both are detected, with modality-aware install recommendations.
pyod.mcp_server is now safe to importIn v3.0.0, import pyod.mcp_server called sys.exit(1) at import time if the optional mcp extra was missing — this killed any parent process that tried to probe MCP availability. v3.1.0 refactors the module to defer the FastMCP check into a new main() entry point. import pyod.mcp_server is now safe in every install, and pyod info uses this to report MCP availability reliably.
The full installation guide is now in docs/install.rst (core install, conda, source, agentic activation paths for Claude Code + Codex + MCP, verification via pyod info). README.rst has a lean quickstart block that links to the full guide instead of duplicating content.
packaging-smoke-test job now verifies the unified pyod CLI end-to-end: pyod --help, pyod info, pyod install skill --help/--list/--target/--skill od_expert (with canonical-name assertion that underscore input → hyphen output), and a regression guard that import pyod.mcp_server does not exit in a core install without mcp./implement-review) on the development branch before merge. All findings addressed.pip install --upgrade pyod
pyod install skill # Claude Code / Claude Desktop: enable the od-expert skill
pyod info # verify everything is wired up
For Codex users:
pip install --upgrade pyod
pyod install skill --project # writes to ./skills/od-expert/ for project-local pickup
pyod info # should show "Detected agents: Codex"
For MCP-compatible agents:
pip install --upgrade pyod[mcp]
pyod mcp serve
See CHANGES.txt for the full v3.1.0 entry.
PyOD 3 repositions the library around a three-layer architecture and adds multi-modal detector coverage while keeping the classic fit/predict API full
PyOD 3 repositions the library around a three-layer architecture and adds multi-modal detector coverage while keeping the classic fit/predict API fully backward-compatible.
BaseDetector interface.investigate(X) call.start, plan, run, analyze, iterate, report) so any AI agent can drive an expert-level investigation through natural conversation. Ships with an od-expert skill for Claude Code and an MCP server for any MCP-compatible LLM.Detector modalities
pip install pyod[graph]): 8 PyG-based detectors (DOMINANT, CoLA, CONAD, AnomalyDAE, GUIDE, Radar, ANOMALOUS, SCAN) routed via the BOND benchmark (NeurIPS 2022).EmbeddingOD adds multi-modal anomaly detection via foundation model embeddings (sentence-transformers, OpenAI, HuggingFace). Routed via NLP-ADBench.Intelligence layer
ADEngine with a JSON-backed knowledge base of 58 detector metadata entries (benchmark rankings, complexity, strengths, weaknesses, preprocessing modes).od-expert skill for Claude Code and MCP server for any MCP-compatible LLM.Packaging modernization
setup.py to pyproject.toml (PEP 621) with SPDX license metadata, dynamic version and dependencies from requirements.txt, and modern extras (pyod[torch], [suod], [xgboost], [combo], [pythresh], [embedding], [openai], [huggingface], [graph], [mcp], [all]).>=3.9; CI tests on 3.9 through 3.13.pyod-install-skill console script that copies the bundled Claude Code skill into ~/.claude/skills/od-expert/ after pip install.Documentation redesign
docs/examples/ directory with 9 walkthroughs (agentic, ADEngine, tabular, time series, graph, embedding, combination, thresholding, index).pyod.models.tabular, pyod.models.timeseries, pyod.models.graph, pyod.models.embedding, pyod.ad_engine, pyod.utils.docs/impact.rst page documenting PyOD's reach: ESA OPS-SAT (Nature Scientific Data, 2025), Walmart, Databricks, IQVIA, Ericsson, 3+ dedicated books, 2 major podcasts, 60+ third-party media references.Backwards compatibility
BaseDetector subclasses and fit/predict calls continue to work unchanged.pip install --upgrade pyod
pyod-install-skill # optional: install the od-expert skill for Claude Code
python -m pyod.mcp_server # optional: start the MCP server for any MCP-compatible LLM
from pyod.models.iforest import IForest
clf = IForest()
clf.fit(X_train)
y_train_scores = clf.decision_scores_
y_test_scores = clf.decision_function(X_test)
If you use PyOD in research, please cite:
@inproceedings{chen2025pyod,
title={PyOD 2: A Python Library for Outlier Detection with LLM-powered Model Selection},
author={Chen, Sihan and Qian, Zhuangzhuang and Siu, Wingchun and Hu, Xingcan and Li, Jiaqi and Li, Shawn and Qin, Yuehan and Yang, Tiankai and Xiao, Zhuo and Ye, Wanghao and others},
booktitle={Companion Proceedings of the ACM on Web Conference 2025},
pages={2807--2810},
year={2025}
}
The original 2019 JMLR paper remains the canonical library reference:
@article{zhao2019pyod,
author = {Zhao, Yue and Nasrullah, Zain and Li, Zheng},
title = {PyOD: A Python Toolbox for Scalable Outlier Detection},
journal = {Journal of Machine Learning Research},
year = {2019},
volume = {20},
number = {96},
pages = {1-7},
url = {http://jmlr.org/papers/v20/19-011.html}
}
PyOD v2.1.0: Multi-Modal Anomaly Detection via Foundation Model Embeddings
PyOD v2.1.0: Multi-Modal Anomaly Detection via Foundation Model Embeddings
EmbeddingOD: Chain any embedding encoder (sentence-transformers, OpenAI, HuggingFace, or custom callable) with any of PyOD's 50+ detectors for text and image anomaly detection. Implements the two-step approach validated by NLP-ADBench (EMNLP 2025).
Benchmark-informed presets: EmbeddingOD.for_text() and EmbeddingOD.for_image() with quality tiers (fast/balanced/best) based on NLP-ADBench and AnomalyDINO results.
MultiModalEncoder (early fusion): Encode multiple modalities (text + image + tabular) and concatenate embeddings. Supports per-sample missing data via mean imputation from training.
MultiModalOD (score fusion): Run a separate detector per modality, standardize scores with training-time scalers, and combine via average/maximization/median. Missing modalities at test time are imputed with the training mean score.
Documentation cleanup: README and ReadTheDocs updated with EmbeddingOD examples, compacted resource links, shortened API reference (removed inherited members from 40+ model pages), and full EmbeddingOD walkthrough in docs/example.rst.
pip install pyod --upgrade
# For text anomaly detection:
pip install pyod sentence-transformers
# For image anomaly detection:
pip install pyod transformers torch
from pyod.models.embedding import EmbeddingOD
# Text anomaly detection in 3 lines
clf = EmbeddingOD(encoder='all-MiniLM-L6-v2', detector='KNN')
clf.fit(train_texts)
labels = clf.predict(test_texts)
# Or use a preset
clf = EmbeddingOD.for_text(quality='fast')
from pyod.models.embedding import EmbeddingOD, MultiModalOD
from pyod.models.knn import KNN
clf = MultiModalOD(modalities={
'text': EmbeddingOD(encoder='all-MiniLM-L6-v2', detector='KNN'),
'tabular': KNN(),
}, combination='average')
clf.fit({'text': train_texts, 'tabular': X_train})
scores = clf.decision_function({'text': test_texts, 'tabular': X_test})
This release focuses on compatibility fixes and consistency improvements across core detectors and packaging.
This release focuses on compatibility fixes and consistency improvements across core detectors and packaging.
Improved NearestNeighbors consistency/performance in:
KNNABODSODLUNARUpdated VAE defaults:
identityidentity activation support and testsPackaging/distribution fix:
package_data / MANIFEST configurationDeep learning base behavior fix:
BaseDeepLearningDetector, y is now explicitly ignored during unsupervised fit2.0.7v<2.0.6>, <09/04/2025> -- Finally, add the auto model selector (#616). v<2.0.6>, <12/01/2025> -- Pre-caution for new sklearn break change(#649).
v<2.0.6>, <09/04/2025> -- Finally, add the auto model selector (#616). v<2.0.6>, <12/01/2025> -- Pre-caution for new sklearn break change(#649).
This long-overdue PR merges the auto model selector by LLMs as well as a new fix for the incoming sklearn break change (no changes on the user end)
Nothing published for this version
Nothing published for this version
v<2.0.3>, <09/06/2024> -- Add Reject Option in Unsupervised Anomaly Detection (#605). v<2.0.3>, <12/20/2024> -- Massive documentation polish.
v<2.0.3>, <09/06/2024> -- Add Reject Option in Unsupervised Anomaly Detection (#605). v<2.0.3>, <12/20/2024> -- Massive documentation polish.
v<2.0.2>, <07/01/2024> -- Add AE1SVM. v<2.0.2>, <07/04/2024> -- Moving from TF to Torch -- reimplement ALAD. v<2.0.2>, <07/04/2024> -- Moving from TF
v<2.0.2>, <07/01/2024> -- Add AE1SVM. v<2.0.2>, <07/04/2024> -- Moving from TF to Torch -- reimplement ALAD. v<2.0.2>, <07/04/2024> -- Moving from TF to Torch -- reimplement anogan. v<2.0.2>, <07/06/2024> -- Complete of removing all Tensorflow and Keras code. v<2.0.2>, <07/21/2024> -- Add DevNet.
v<2.0.0>, <05/21/2024> -- Moving from TF to Torch -- reimplement SO_GAAL. v<2.0.0>, <05/21/2024> -- Moving from TF to Torch -- implement dl base with
v<2.0.0>, <05/21/2024> -- Moving from TF to Torch -- reimplement SO_GAAL. v<2.0.0>, <05/21/2024> -- Moving from TF to Torch -- implement dl base with more utilities. v<2.0.1>, <06/16/2024> -- Moving from TF to Torch -- reimplement DeepSVDD. v<2.0.1>, <06/17/2024> -- Moving from TF to Torch -- reimplement dl_base. v<2.0.1>, <06/21/2024> -- Moving from TF to Torch -- reimplement MO_GAAL. v<2.0.1>, <06/21/2024> -- Moving from TF to Torch -- reimplement AE and VAE.
primarily driven by @yqin43 @RaymondY @zhuox5 @Yeechin-is-here in random order :)
Nothing published for this version
v<1.1.3>, <02/07/2024> -- Minor fix for SUOD changes.
v<1.1.3>, <02/07/2024> -- Minor fix for SUOD changes.
v<1.1.2>, <11/17/2023> -- Massive documentation optimization. v<1.1.2>, <11/17/2023> -- Fix the issue of contamination. v<1.1.2>, <11/17/2023> -- KPCA
v<1.1.2>, <11/17/2023> -- Massive documentation optimization. v<1.1.2>, <11/17/2023> -- Fix the issue of contamination. v<1.1.2>, <11/17/2023> -- KPCA bug fix (#494).
v<1.1.1>, <07/03/2023> -- Bump up sklearn requirement and some hot fixes. v<1.1.1>, <10/24/2023> -- Add deep isolation forest
v<1.1.1>, <07/03/2023> -- Bump up sklearn requirement and some hot fixes. v<1.1.1>, <10/24/2023> -- Add deep isolation forest (#506)
v<1.0.9>, <03/19/2023> -- Hot fix for errors in ECOD and COPOD due to the issue of scipy. v<1.1.0>, <06/19/2023> -- Further integration of PyThresh.
v<1.0.9>, <03/19/2023> -- Hot fix for errors in ECOD and COPOD due to the issue of scipy. v<1.1.0>, <06/19/2023> -- Further integration of PyThresh.
Nothing published for this version
v<1.0.8>, <03/08/2023> -- Improve clone compatibility (#471). v<1.0.8>, <03/08/2023> -- Add QMCD detector (#452). v<1.0.8>, <03/08/2023> -- Optimized
v<1.0.8>, <03/08/2023> -- Improve clone compatibility (#471). v<1.0.8>, <03/08/2023> -- Add QMCD detector (#452). v<1.0.8>, <03/08/2023> -- Optimized ECDF and drop Statsmodels dependency (#467).
v<1.0.7>, <12/14/2022> -- Enable automatic thresholding by pythresh (#454).
v<1.0.7>, <12/14/2022> -- Enable automatic thresholding by pythresh (#454).
v<1.0.6>, <09/23/2022> -- Update ADBench benchmark for NeruIPS 2022. v<1.0.6>, <10/23/2022> -- ADD KPCA.
v<1.0.6>, <09/23/2022> -- Update ADBench benchmark for NeruIPS 2022. v<1.0.6>, <10/23/2022> -- ADD KPCA.
v<1.0.5>, <07/29/2022> -- Import optimization. v<1.0.5>, <08/27/2022> -- Code optimization. v<1.0.5>, <09/14/2022> -- Add ALAD.
v<1.0.5>, <07/29/2022> -- Import optimization. v<1.0.5>, <08/27/2022> -- Code optimization. v<1.0.5>, <09/14/2022> -- Add ALAD.
AnoGAN is too slow to run. Consider a removal or refactoring.
v<1.0.4>, <07/29/2022> -- General improvement of code quality and test coverage. v<1.0.4>, <07/29/2022> -- Add LUNAR (#413). v<1.0.4>, <07/29/2022> --
v<1.0.4>, <07/29/2022> -- General improvement of code quality and test coverage. v<1.0.4>, <07/29/2022> -- Add LUNAR (#413). v<1.0.4>, <07/29/2022> -- Add LUNAR (#415).
v<1.0.3>, <06/27/2022> -- Change default generation to new behaviors (#409). v<1.0.3>, <07/04/2022> -- Add AnoGAN (#412).
v<1.0.3>, <06/27/2022> -- Change default generation to new behaviors (#409). v<1.0.3>, <07/04/2022> -- Add AnoGAN (#412).
v<1.0.2>, <06/21/2022> -- Add GMM detector (#402). v<1.0.2>, <06/23/2022> -- Add ADBench Benchmark.
v<1.0.2>, <06/21/2022> -- Add GMM detector (#402). v<1.0.2>, <06/23/2022> -- Add ADBench Benchmark.
v<1.0.1>, <04/27/2022> -- Add INNE (#396). v<1.0.1>, <05/13/2022> -- Urgent fix for iForest (#406).
v<1.0.1>, <04/27/2022> -- Add INNE (#396). v<1.0.1>, <05/13/2022> -- Urgent fix for iForest (#406).
Urgent fix for
File "lib/python3.10/site-packages/pyod/models/iforest.py", line 13, in <module> from sklearn.utils.fixes import _joblib_parallel_args ImportError: cannot import name '_joblib_parallel_args' from 'sklearn.utils.fixes' (/lib/python3.10/site-packages/sklearn/utils/fixes.py)
v<1.0.0>, <04/04/2022> -- Add KDE detector (#382). v<1.0.0>, <04/06/2022> -- Disable the bias term in DeepSVDD (#385). v<1.0.0>, <04/21/2022> -- Fix a
v<1.0.0>, <04/04/2022> -- Add KDE detector (#382). v<1.0.0>, <04/06/2022> -- Disable the bias term in DeepSVDD (#385). v<1.0.0>, <04/21/2022> -- Fix a set of issues of autoencoders (#313, #390, #391). v<1.0.0>, <04/23/2022> -- Add sampling based detector (#384).
v<0.9.9>, <03/20/2022> -- Renovate documentation. v<0.9.9>, <03/23/2022> -- Add example for COPOD interpretability. v<0.9.9>, <03/23/2022> -- Add outl
v<0.9.9>, <03/20/2022> -- Renovate documentation. v<0.9.9>, <03/23/2022> -- Add example for COPOD interpretability. v<0.9.9>, <03/23/2022> -- Add outlier detection by Cook’s distances. v<0.9.9>, <04/04/2022> -- Various community fix.
v<0.9.8>, <02/23/2022> -- Add Feature Importance for iForest. v<0.9.8>, <03/05/2022> -- Update ECOD (TKDE 2022).
v<0.9.8>, <02/23/2022> -- Add Feature Importance for iForest. v<0.9.8>, <03/05/2022> -- Update ECOD (TKDE 2022).
See the usage of feature importance of iforest in https://github.com/yzhao062/pyod/blob/master/examples/iforest_example.py See the new ECOD detector in https://github.com/yzhao062/pyod/blob/master/examples/ecod_example.py
We add a new detection algorithm called ECOD. See example here: https://github.com/yzhao062/pyod/blob/master/examples/ecod_example.py
We add a new detection algorithm called ECOD. See example here: https://github.com/yzhao062/pyod/blob/master/examples/ecod_example.py
v<0.9.6>, <11/05/2021> -- Minor bug fix for COPOD. v<0.9.6>, <12/24/2021> -- Bug fix for MAD (#358). v<0.9.6>, <12/24/2021> -- Bug fix for COPOD plott
Happy holiday!
v<0.9.6>, <11/05/2021> -- Minor bug fix for COPOD. v<0.9.6>, <12/24/2021> -- Bug fix for MAD (#358). v<0.9.6>, <12/24/2021> -- Bug fix for COPOD plotting (#337). v<0.9.6>, <12/24/2021> -- Model persistence doc improvement.
In this important update, we introduce multiple important features:
In this important update, we introduce multiple important features:
v<0.9.5>, <09/10/2021> -- Update to GitHub Action for autotest! v<0.9.5>, <09/10/2021> -- Various documentation fix. v<0.9.5>, <10/26/2021> -- MAD fix #318. v<0.9.5>, <10/26/2021> -- Automatic histogram size selection for HBOS and LODA #321. v<0.9.5>, <10/27/2021> -- Add prediction confidence #349.
Urgent fix for breaking changes in scikit-learn 1.0.
Urgent fix for breaking changes in scikit-learn 1.0.
v<0.9.3>, <08/19/2021> -- Expand test to Python 3.8 and 3.9. v<0.9.3>, <08/29/2021> -- Add SUOD.
v<0.9.3>, <08/19/2021> -- Expand test to Python 3.8 and 3.9. v<0.9.3>, <08/29/2021> -- Add SUOD.
In this version, SUOD is integrated into PyOD, and fast training/prediction is therefore possible. See https://github.com/yzhao062/pyod/blob/master/examples/suod_example.py for more information.
This release mainly features a new deep model, DeepSVDD, in PyOD.
This release mainly features a new deep model, DeepSVDD, in PyOD.
v<0.9.2>, <08/15/2021> -- Fix ROD. v<0.9.2>, <08/15/2021> -- Add DeepSVDD (implemented by Rafał Bodziony).
This release incorporates a few bug fixes and enhancement.
This release incorporates a few bug fixes and enhancement.
v<0.9.1>, <07/12/2021> -- Improve COPOD by dropping pandas dependency. v<0.9.1>, <07/19/2021> -- Add memory efficienct COF. v<0.9.1>, <08/01/2021> -- Fix Pytorch Dataset issue. v<0.9.1>, <08/14/2021> -- Synchronize scikit-learn LOF parameters.
v<0.9.0>, <06/20/2021> -- Add clone test for models. v<0.9.0>, <07/03/2021> -- ROD hot fix (#316). v<0.9.0>, <07/04/2021> -- Improve COPOD plot with c
v<0.9.0>, <06/20/2021> -- Add clone test for models. v<0.9.0>, <07/03/2021> -- ROD hot fix (#316). v<0.9.0>, <07/04/2021> -- Improve COPOD plot with colunms parameter.
v<0.8.9>, <05/17/2021> -- Turn on test for Python 3.5-3.8. v<0.8.9>, <06/10/2021> -- Add PyTorch AutoEncoder v<0.8.9>, <06/11/2021> -- Fix LMDD parame
v<0.8.9>, <05/17/2021> -- Turn on test for Python 3.5-3.8. v<0.8.9>, <06/10/2021> -- Add PyTorch AutoEncoder v<0.8.9>, <06/11/2021> -- Fix LMDD parameter (#307)
v<0.8.7>, <01/16/2021> -- Add ROD. v<0.8.7>, <02/18/2021> -- Dependency optimization. v<0.8.8>, <04/08/2021> -- COPOD optimization. v<0.8.8>, <04/08/2
v<0.8.7>, <01/16/2021> -- Add ROD. v<0.8.7>, <02/18/2021> -- Dependency optimization. v<0.8.8>, <04/08/2021> -- COPOD optimization. v<0.8.8>, <04/08/2021> -- Add parallelization for COPOD. v<0.8.8>, <04/26/2021> -- fix XGBOD issue with xgboost 1.4.
Nothing published for this version
Most the changes are bug-fix and performance enhancement.
Most the changes are bug-fix and performance enhancement.
v<0.8.5>, <12/22/2020> -- Refactor test from sklearn to numpy v<0.8.5>, <12/22/2020> -- Refactor COPOD for consistency v<0.8.5>, <12/22/2020> -- Refactor due to sklearn 0.24 (issue #265) v<0.8.6>, <01/09/2021> -- Improve COF speed (PR #159) v<0.8.6>, <01/10/2021> -- Fix LMDD parameter inconsistenct. v<0.8.6>, <01/12/2021> -- Add option to specify feature names in copod explanation plot (PR #261).
Nothing published for this version
v<0.8.4>, <10/13/2020> -- Fix COPOD code inconsistency (issue #239). v<0.8.4>, <10/24/2020> -- Fix LSCP minor bug (issue #180). v<0.8.4>, <11/02/2020>
v<0.8.4>, <10/13/2020> -- Fix COPOD code inconsistency (issue #239). v<0.8.4>, <10/24/2020> -- Fix LSCP minor bug (issue #180). v<0.8.4>, <11/02/2020> -- Add support for Tensorflow 2. v<0.8.4>, <11/12/2020> -- Merge PR #!02 for categortical data generation.
v<0.8.2>, <07/04/2020> -- Add a set of utility functions. v<0.8.2>, <08/30/2020> -- Add COPOD and MAD algorithm. v<0.8.3>, <09/01/2020> -- Make decisi
v<0.8.2>, <07/04/2020> -- Add a set of utility functions. v<0.8.2>, <08/30/2020> -- Add COPOD and MAD algorithm. v<0.8.3>, <09/01/2020> -- Make decision score consistent. v<0.8.3>, <09/19/2020> -- Add model persistence documentation (save and load).
Short summary, we add two new algorithms COPOD and MAD. Moreover, we now provide a short example regrading model save and load.
Nothing published for this version
This is a stable release. Python 2 support will be dropped in the next version.
This is a stable release. Python 2 support will be dropped in the next version.
v<0.8.0>, <05/18/2020> -- Update test frameworks by reflecting sklearn change. v<0.8.1>, <07/11/2020> -- Bug fix and documentation update
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →