Custom neighbor transformers with varying neighbor count and respect `knn`
Allows neighbor counts < k in sc.pp.neighbors by adding masking to _ind_dist_slow, enabling adaptive neighbor transformers. Draft for now, as I could not run tests locally or on CI (following the exact installation instructions and not touching the GitHub actions, so it seems like the workflow is broken). I would also appreciate help in making the tests more idiomatic to scanpy and getting some feedback on if this could break any other part that might rely on connectivities having a certain shape.
To make it work, I also had to take on #3014 (more discussion in that issue). Adding a binary connectivity method like in this PR would be backwards compatible and unlock many different use cases. In my opinion, the current implementation is however quite confusing for end users and some documentation clarity, simplification and warning about unexpected behavior when using knn with method="umap" would be helpful. Since some of this could result in breaking changes, this PR can hopefully also serve as a place for discussion on how to implement this.
The second part has also been discussed in:
- #2587
- #1984
#3021 might also be related to the overall complex structure with multiple distance calculations and changes to the connectivities in neighbors, though I have not been able to confirm it yet.
Use cases of these changes:
-
Full comparability with use of transformers outside of scanpy
-
SNN transformers
-
Distance adaptive algorithms
-
Less duplication when implemeting methods like
bbknn, etc. -
[X] Closes #3806 and closes #3014
-
[X] Tests included: Needs additional tests to verify
n_neighborsin distances and connectivities for different methods and different n_obs (this test might have prevented #3809)
- [ ] Release notes not necessary - included
Codecov Report
:x: Patch coverage is 84.37500% with 5 lines in your changes missing coverage. Please review.
:white_check_mark: Project coverage is 76.85%. Comparing base (f75ac11) to head (fe1ba5e).
:white_check_mark: All tests successful. No failed tests found.
| Files with missing lines | Patch % | Lines |
|---|---|---|
| src/scanpy/neighbors/_common.py | 80.00% | 5 Missing :warning: |
Additional details and impacted files
@@ Coverage Diff @@
## main #3807 +/- ##
==========================================
+ Coverage 76.72% 76.85% +0.13%
==========================================
Files 116 116
Lines 12398 12413 +15
==========================================
+ Hits 9512 9540 +28
+ Misses 2886 2873 -13
| Flag | Coverage Δ | |
|---|---|---|
| hatch-test.pre | 76.85% <84.37%> (+0.13%) |
:arrow_up: |
Flags with carried forward coverage won't be shown. Click here to find out more.
| Files with missing lines | Coverage Δ | |
|---|---|---|
| src/scanpy/neighbors/__init__.py | 80.26% <100.00%> (+0.20%) |
:arrow_up: |
| src/scanpy/neighbors/_types.py | 100.00% <100.00%> (ø) |
|
| src/scanpy/neighbors/_common.py | 89.70% <80.00%> (+24.79%) |
:arrow_up: |