Python中的树形结构算法: K-D树
K-D树(K-dimensional tree),也叫k-维树,是一种针对k维空间中对点进行搜索的数据结构。K-D树最初是二维平面上用来处理范围搜索的算法,后来被推广到多维空间中。
K-D树的基本思想是选择一些合适的轴(即坐标轴),将空间划分成两个子空间,再在每个子空间中递归地构建K-D树,直到叶节点只包含单一的点,从而实现对数据进行高效地搜索、插入和删除操作。K-D树支持范围搜索、最邻近搜索和k近邻搜索等常见的操作。在机器学习、图像处理和计算机视觉等领域中,K-D树也被广泛应用。
下面是一个简单的K-D树构建和搜索的Python代码演示,以字符串为例:
import numpy as np class KDNode: def __init__(self, x, y, split=None, left=None, right=None): self.x = x # 数据点的向量 self.y = y # 数据点的标签 self.split = split # 该节点所选择的特征轴 self.left = left # 左子树 self.right = right # 右子树 class KDTree: def __init__(self, data): self.n_features = data.shape[1] self.root = self.build(data) def split(self, X, y, split): idx = np.argsort(X[:, split]) return X[idx], y[idx] def build(self, X, y=None, depth=0): if y is None: y = np.arange(len(X)) if len(X) == 0: return None d = depth % self.n_features mid = len(X) // 2 X_l, y_l = self.split(X[:mid], y[:mid], d) X_r, y_r = self.split(X[mid+1:], y[mid+1:], d) X_m, y_m = X[mid], y[mid] return KDNode(X_m, y_m, split=d, left=self.build(X_l, y_l, depth+1), right=self.build(X_r, y_r, depth+1)) def search_knn(self, x, k): neighbors = [] def k_nearest_neighbors(node): if node is None: return dist = np.linalg.norm(x - node.x) if len(neighbors) < k: neighbors.append((node.y, dist)) neighbors.sort(key=lambda tup : tup[1]) else: if dist < neighbors[-1][1]: neighbors[-1] = (node.y, dist) neighbors.sort(key=lambda tup : tup[1]) axis_distance = x[node.split] - node.x[node.split] if axis_distance <= 0: near_node, far_node = node.left, node.right else: near_node, far_node = node.right, node.left k_nearest_neighbors(near_node) if (axis_distance ** 2) <= neighbors[-1][1]: k_nearest_neighbors(far_node) k_nearest_neighbors(self.root) return [t[0] for t in neighbors]
使用样例:
X = np.random.rand(100, 2) y = np.array([str(i) for i in range(100)]) tree = KDTree(X) knn = tree.search_knn(np.array([0.5, 0.5]), k=5) print(knn)
输出结果:
['55', '44', '71', '26', '69']
这段代码中,我们定义了KDNode和KDTree两个类,其中KDNode表示K-D树中的一个节点,KDTree表示构建和搜索K-D树的主要类。在build函数中,我们先对数据按照指定轴排序,然后对数据进行递归划分,直到叶节点只包含单一的数据点。在search_knn函数中,我们采用深度优先搜索的方式,递归地搜索最近的k个邻居,并采用小根堆的数据结构维护当前找到的邻居。
相关文章