嗯~,scipy.spatial.cKDTree是个很有用的工具,可以这样来介绍它:
在探索多维空间数据的海洋中,有效地检索和操作点集是至关重要的。Python的科学计算宝库SciPy为我们提供了一个强大的航标——scipy.spatial.cKDTree。这是一种利用k维树(k-d tree)数据结构的优化算法,用于高效处理多维空间的查询问题。无论是最邻近搜索、范围查询还是加速点集间的复杂操作,cKDTree的引入都能显著提升性能,尤其在处理大规模数据集时。它的实现是用C语言编写的,因此在执行速度上远超纯Python实现的基础版本KDTree。简而言之,如果你的数据拥有多个维度,并且你需要一个既快速又可靠的数据结构来进行各种空间检索,那么cKDTree无疑是你的理想选择。

查询最近邻

query(x, k=1, eps=0, p=2, distance_upper_bound=inf)

其中,k为查询的最近邻的个数;eps是查询的近似参数,如果愿意牺牲一定精度而提高查询效率,cKDTree会返回距离真实最近邻至多(1 + eps)倍的点;p决定了距离的计算方式,如p=1代表曼哈顿距离,p=2代表欧氏距离等;distance_upper_bound代表最远的邻居距离。

Python
import pandas as pd
from scipy.spatial import cKDTree 

'''
用例1
node_dict是一个dict = {(int, str): (float, float)}类型的对象
center_loc是一个tuple = (float, float)类型的对象
'''

node_dict = {(int(row['node_id']), str(row['node_name'])): (float(row['loc_x']), float(row['loc_y'])) for index, row in df_node.iterrows()}
node_key = list(node_dict.keys())
node_loc_mat = list(node_dict.values())
node_tree = cKDTree(node_loc_mat)

center_loc = (1.01, 0.99)
distance, indexes = node_tree.query(center_loc, k=2)

查询圆形区域

query_ball_point(x, r, p=2, eps=0)

其中,r为所查询圆形区域的半径,p和eps的意义同上。

Python
import numpy as np

ANGLE_THRESHOLD = 120

'''
用例2
相关对象同用例1,这次我们增大一点难度,查询圆形区域后,筛选出中心点和另一点连线为对称轴的某个扇形区域内的点
'''

node_tree = cKDTree(node_loc_mat)

center_loc = (1.01, 0.99)
stick_loc = (2.25, 0.5)

def calc_angle(aim_node, source_node, target_node):
    point, A, B = np.array([aim_node[0], aim_node[1]]), np.array([source_node[0], source_node[1]]), np.array([target_node[0], target_node[1]])
    AB = B - A
    AP = point - A
    AB_length = np.linalg.norm(AB)
    AP_length = np.linalg.norm(AP)
    cos_angle = np.dot(AB, AP) / (AB_length * AP_length)
    angle = np.arccos(np.clip(cos_angle, -1.0, 1.0))
    return angle

candidates_idx = node_tree.query_ball_point(center_loc, r=10)

angle_maximum = np.deg2rad(ANGLE_THRESHOLD)
in_range_node_idx = []
for idx in candidates_idx:
    node_coord = node_loc_mat[idx]
    angle = calc_angle(node_coord, center_loc, stick_loc)
    if angle < angle_maximum:
        in_range_node_idx.append(idx)

其他方法

query_ball_tree(other, r, p=2, eps=0)

查找与另一个cKDTree中的点的距离在半径r内的所有点对。

query_pairs(r, p=2, eps=0)

找出树内所有点对的距离在半径r内的点对。

count_neighbors(other, r, p=2)

计算与另一个cKDTree中的每个点在距离r内有多少邻居。

sparse_distance_matrix(other, max_distance, p=2)

创建一个稀疏距离矩阵,矩阵中记录的是自身与另一个cKDTree所有距离在max_distance以内的点对的距离。