Ball Tree Nearest Neighbor Search.
Classes
Ball Tree for nearest neighbor search in high-dimensional spaces.
A Ball Tree is a binary tree where each node defines a D-dimensional hypersphere (ball) containing a subset of the data points. Compared to KD-trees, Ball Trees tend to be more efficient when the dimensionality is moderate to high because they use ball-shaped (spherical) partitions instead of axis-aligned splits.
This implementation delegates tree construction and querying to an optimized C++ backend with optional OpenMP parallelism, providing orders-of-magnitude speedup over pure-Python recursive traversal.
__init__( self, leaf_size: int = 10, )
Overview
The Ball Tree is constructed and queried as follows:
- Compute the centroid and radius of the bounding ball for all
-
If the number of points is at or below
leaf_size, create a leaf
- Otherwise, find the dimension with the greatest spread and split the
- Recursively build left and right child subtrees.
- During a query, prune subtrees whose bounding ball cannot contain
Theory
The pruning criterion for a query point q and a ball node with center c and radius r is:
where d_k is the distance to the current k-th nearest neighbor. If the inequality holds, the entire subtree is skipped because no point inside the ball can be closer than d_k.
The distance metric used is Euclidean distance:
Parameters
leaf_size
Attributes
X_
n_samples_
n_features_
Notes
Complexity:
- Construction: O(n \log n) where n = number of data points
- Query (average case): O(\log n) per query point
- Query (worst case): O(n) per query point (high-dimensional or adversarial data)
- Space: O(n) for the tree structure
- Moderate to high-dimensional data where KD-trees degrade
- When the data has intrinsic low-dimensional structure (e.g., manifolds)
- Repeated nearest-neighbor queries against a fixed dataset
- When non-axis-aligned clusters are present in the data
References
See Also
Build a Ball Tree and query for the nearest neighbor:
>>> from tuiml.algorithms.neighbors.search import BallTree
>>> import numpy as np
>>> X = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
>>> tree = BallTree(leaf_size=2)
>>> tree.build(X)
BallTree(n_samples=4, leaf_size=2)
>>> dists, indices = tree.query([3.1, 4.1], k=1)
Methods
query
(self, x: np.ndarray, k: int=1) -> Tuple[np.ndarray, np.ndarray]
query
(self, x: np.ndarray, k: int=1) -> Tuple[np.ndarray, np.ndarray]
Find the k nearest neighbors for a query point.
Parameters
x
k
Returns
distances
indices
query_batch
(self, X: np.ndarray, k: int=1) -> Tuple[np.ndarray, np.ndarray]
query_batch
(self, X: np.ndarray, k: int=1) -> Tuple[np.ndarray, np.ndarray]
Find the k nearest neighbors for multiple query points.
Parameters
X
k
Returns
distances
indices
query_radius
(self, x: np.ndarray, radius: float) -> Tuple[np.ndarray, np.ndarray]
query_radius
(self, x: np.ndarray, radius: float) -> Tuple[np.ndarray, np.ndarray]
Find all neighbors within a specified radius.
Parameters
x
radius
Returns
distances
indices