KD-Tree Nearest Neighbor Search.
Classes
KD-Tree for nearest neighbor search in low-dimensional spaces.
A KD-Tree is a binary tree that recursively partitions the search space along axis-aligned splits. It is highly efficient for k-nearest neighbor queries in low to moderate dimensions (typically d < 20), but performance degrades toward brute-force speed as dimensionality increases.
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 KD-Tree is constructed and queried as follows:
- Choose the splitting dimension with the largest spread.
- Find the median of the data along that dimension.
- Partition the data: points \leq median go left, others go
- Recursively build subtrees until the number of points in a node is
leaf_size.
- During a query, traverse the tree starting from the closer subtree
Theory
The pruning criterion for a query point q at an internal node splitting on dimension j with value v is:
where d_k is the squared distance to the current k-th nearest neighbor. If this holds, the far subtree cannot contain a closer point and is skipped entirely.
The distance metric 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 dimensions)
- Space: O(n) for the tree structure
- Low-dimensional data (d < 20)
- Repeated nearest-neighbor queries on a fixed dataset
- When axis-aligned splits naturally separate the data
- When construction time can be amortized over many queries
References
See Also
Build a KD-Tree and query for the nearest neighbor:
>>> from tuiml.algorithms.neighbors.search import KDTree
>>> import numpy as np
>>> X = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
>>> tree = KDTree(leaf_size=2)
>>> tree.build(X)
KDTree(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