You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SciPy或同类Python库是否支持矩形范围KDTree查询方法

大规模二维点集的KDTree矩形范围查询实现

问题说明

现有形状为[m, 2]的大规模二维点数组(m数值极大),需要构造边长为n(n为奇数)的轴对齐矩形查询框:以目标查询点为框中心,返回框内包含的所有点。
基于SciPy构建KDTree后,自带的query_ball_point方法仅支持圆形半径范围的最近邻查询,无法直接返回矩形范围内的点。
以n=3、查询中心点为[1,2]的场景为例,期望返回的矩形内点集如下:

[[0,1],
 [0,2],
 [0,3],
 [1,1],
 [1,2],
 [1,3],
 [2,1],
 [2,2],
 [2,3]]

实现方案

优先使用scipy.spatial.cKDTree而非纯Python实现的KDTree,前者为C语言优化实现,针对百万级以上大规模点集的查询速度比后者高1~2个数量级,完全适配大m的使用场景。

方法1:原生矩形查询(推荐,效率最高)

SciPy 1.1及以上版本的cKDTree自带query_ball_box方法,专门用于轴对齐矩形范围查询,无需额外过滤:

  1. 计算矩形边界:设中心点坐标为(cx, cy),矩形半长half = (n - 1) // 2,则矩形各轴的下界为[cx-half, cy-half],上界为[cx+half, cy+half]
  2. 调用query_ball_box传入上下界,直接返回矩形内所有点的索引,索引原数组即可得到对应坐标

示例代码:

import numpy as np
from scipy.spatial import cKDTree

# 构建测试点集
points = np.array([
    [0,0], [0,1], [0,2], [0,3],
    [1,0], [1,1], [1,2], [1,3],
    [2,0], [2,1], [2,2], [2,3],
    [3,0], [3,1], [3,2], [3,3]
])
tree = cKDTree(points)

# 查询参数
center = np.array([1, 2])
n = 3
half = (n - 1) // 2
lower_bound = center - half
upper_bound = center + half

# 矩形查询
point_idx = tree.query_ball_box(lower_bound, upper_bound)
result = points[point_idx]

运行后result即为期望的矩形内点集。

方法2:低版本兼容方案

如果使用的SciPy版本低于1.1、没有query_ball_box方法,可以通过「外接圆粗筛+边界过滤」的方式实现,额外开销极低:

  1. 计算矩形的外接圆半径r = half * np.sqrt(2),用query_ball_point查询圆形范围内的候选点,这一步会过滤掉绝大多数无关点
  2. 对候选点做简单的数值比较,过滤掉落在圆形范围内、但在矩形范围外的点即可

示例代码:

radius = half * np.sqrt(2)
candidate_idx = tree.query_ball_point(center, r=radius)
candidates = points[candidate_idx]
# 边界过滤
mask = (
    (candidates[:, 0] >= lower_bound[0]) & (candidates[:, 0] <= upper_bound[0]) &
    (candidates[:, 1] >= lower_bound[1]) & (candidates[:, 1] <= upper_bound[1])
)
result = candidates[mask]

优化提示

  • 批量查询多个中心点的矩形范围时,可以直接给query_ball_box传入多组上下界数组,批量返回结果,比循环单查效率高3~10倍
  • 如果点集坐标是整数格点,可以提前把坐标转成整型存储,进一步加快查询和过滤速度

内容的提问来源于stack exchange,提问作者Nate Frisch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 22:27:35