In Balltree, filter out/mask specific points in query

### Describe the workflow you want to enable

I would like to be able to query nearest points within a Balltree but excluding some of them.
E.g. I create a Balltree on 60k points. I want to find the k nearest neighbour points but within a subset of the 60k points. 
Example case: I have N clusters of points. I build a Balltree with all the points of the N clusters (e.g. 60k points). Then I want to find for each of the points of a given cluster the closest point from the other clusters (i.e. excluding itself).

### Describe your proposed solution

 I would like to pass an extra mask argument (e.g. array of 60k elements) to the query with True for the points in the other clusters and False for the points in the specific cluster.

### Describe alternatives you've considered, if relevant

_No response_

### Additional context

_No response_

COMMENT:
Yes but I have a lot of groups (~5000) and lot of points (300k) and
building for each group a balltree with all the points from the other
groups doesn't scale well.

I was thinking that in the internal loop to find the k closest points,
there could be a test on the mask that would skip the point if it is masked
and therefore continue to look for the next closest points.

On Wed, 16 Jul 2025, 16:33 Jérémie du Boisberranger, <
***@***.***> wrote:

> *jeremiedbb* left a comment (scikit-learn/scikit-learn#31754)
> <https://github.com/scikit-learn/scikit-learn/issues/31754#issuecomment-3078882096>
>
> Thanks for the details. What you're asking doesn't fit very well with the
> tree design. To be efficient a new tree with the excluded points should be
> created. Otherwise it would be equivalent to querying all points and then
> mask yourself the query result afterwards.
>
> Here's a simple solution (if I got it right this time):
>
> import numpy as npfrom sklearn.neighbors import BallTree
> N_groups = 10N_points_per_group = 5D = 3groups = np.arange(N_groups)
> # create N_groups centersX = np.random.RandomState(0).random_sample((N_groups, D))
> # create per group, N_points_per_group points around each center by adding a small random perturbationX = X[:,np.newaxis,:] + np.random.RandomState(0).random_sample((N_groups,N_points_per_group, D))*.05
> # create a BallTree from all the points of all the groupstree = BallTree(X.reshape((-1,D)))  # this is not needed anymore
> # for each group, I want to find the closest point in the BallTree that is not in the group itself# in the case here, I need to query k=2 to get it because the first one is always the point itselffor i in range(N_groups):
>     print(f"Group {i}:")
>     new_tree = BallTree(X[groups != i].reshape(-1, D))
>     dist, ind = tree.query(X[i], k=2)
>     print(ind[:,[1]])  # only the 2nd column
>     break
> Group 0:
> [[3]
>  [0]
>  [0]
>  [0]
>  [3]]
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/scikit-learn/scikit-learn/issues/31754#issuecomment-3078882096>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AAJ6S5VRLTUMFGRJVF4E5W33IZPFNAVCNFSM6AAAAACBNNLSY2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTANZYHA4DEMBZGY>
> .
> You are receiving this because you were mentioned.Message ID:
> ***@***.***>
>

Labels: New Feature