Skip to content

Fix fast ABOD counting each training point as its own neighbor - #774

Open
raashish1601 wants to merge 2 commits into
yzhao062:developmentfrom
raashish1601:fix/abod-fast-self-neighbor
Open

raashish1601 wants to merge 2 commits into
yzhao062:developmentfrom
raashish1601:fix/abod-fast-self-neighbor

Conversation

@raashish1601

@raashish1601 raashish1601 commented Oct 7, 2026 •

Copy link
Copy Markdown

All Submissions Basics:

All Submissions Cores:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you successfully ran tests with your changes locally?
  • Does your submission pass tests, including CircleCI, Travis CI, and AppVeyor? (CI will run on this PR.)
  • Does your submission have appropriate code coverage? The cutoff threshold is 95% by Coversall.

In fast ABOD, _fit_fast finds the neighbors of the training points with self.neigh_.kneighbors(self.X_train_, ...). Querying with the training data returns each point as its own nearest neighbor, and _calculate_wocs then skips every pair that contains the point itself, so a training score is computed from only n_neighbors - 1 real neighbors. decision_function uses n_neighbors neighbors for new points, so decision_scores_ (and threshold_ / labels_, which come from them) are on a different basis than the test scores. As a consequence, fast ABOD with n_neighbors = n_train - 1 also does not match the default (all points) method.

The fix calls kneighbors(n_neighbors=..., return_distance=False) without X, which in scikit-learn excludes each training point from its own neighbors (the same approach KNN uses). Only fast ABOD training scores change; decision_function and the default method are unchanged.

Tests in pyod/test/test_abod.py:

  • test_fast_mode_train_scores_use_k_other_points: each training score equals -_calculate_wocs over its n_neighbors nearest other training points.
  • test_fast_mode_with_all_neighbors_matches_default: with n_neighbors = n - 1, fast and default give the same training scores.

Both fail on the current code and pass with the change. _numpy_abod_scores, the reference added by #766 for the dtype tests, queried the training points with the training data too (it followed the current convention), so it now also leaves each training point out of its own neighbors. pyod/test/test_abod.py passes locally (58 tests).

@raashish1601
raashish1601 force-pushed the fix/abod-fast-self-neighbor branch from 92234d5 to b05f083 Compare October 7, 2026 23:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant