KD树 球树

KD树


  1.KD树建树采用的是从m个样本的n维特征中,分别计算n个特征的取值的方差,用方差最大的第k维特征 nk来作为根节点。选择特征 nk的取值的中位数 nkv对应的样本作为划分点,对于所有第k维特征的取值小于 nkv的样本,划入左子树,对于第k维特征的取值大于等于 nkv的样本,划入右子树,对于左子树和右子树,采用和刚才同样的办法来找方差最大的特征来做更节点,递归的生成KD树。
        2.流程图


    3.二维样本6个,{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},构建kd树的具体步骤为:
  1)找到划分的特征。6个数据点在x,y维度上的数据方差分别为6.97,5.37,所以在x轴上方差更大,用第1维特征建树。
  2)确定划分点(7,2)。根据x维上的值将数据排序,6个数据的中值(所谓中值,即中间大小的值)为7,所以划分点的数据是(7,2)。这样,该节点的分割超平面就是通过(7,2)并垂直于:划分点维度的直线x=7;
  3)确定左子空间和右子空间。 分割超平面x=7将整个空间分为两部分:x<=7的部分为左子空间,包含3个节点={(2,3),(5,4),(4,7)};另一部分为右子空间,包含2个节点={(9,6),(8,1)}
  4)用同样的办法划分左子树的节点{(2,3),(5,4),(4,7)}和右子树的节点{(9,6),(8,1)}。最终得到KD树
 4.最后得到的KD树如下:


 3. KD树搜索最近邻:
  首先在KD树里面找到包含目标点的叶子节点。以目标点为圆心,以目标点到叶子节点样本实例的距离为半径,得到一个超球体,最近邻的点一定在这个超球体内部。然后返回叶子节点的父节点,检查另一个子节点包含的超矩形体是否和超球体相交,如果相交就到这个子节点寻找是否有更加近的近邻,有的话就更新最近邻。如果不相交那就简单了,直接返回父节点的父节点,在另一个子树继续搜索最近邻。当回溯到根节点时,算法结束,此时保存的最近邻节点就是最终的最近邻
 

 球树


  KD树算法虽然提高了KNN搜索的效率,但是在某些时候效率并不高,比如当处理不均匀分布的数据集时,不管是近似方形,还是矩形,甚至正方形,都不是最好的使用形状,因为他们都有角。一个例子如下图:


  球树,顾名思义,就是每个分割块都是超球体,而不是KD树里面的超矩形体。


  建树流程
 1) 先构建一个超球体,这个超球体是可以包含所有样本的最小球体。
 2) 从球中选择一个离球的中心最远的点,然后选择第二个点离第一个点最远,将球中所有的点分配到离这两个聚类中心最近的一个上,然后计算每个聚类的中心,以及聚类能够包含它所有数据点所需的最小半径。这样我们得到了两个子超球体,和KD树里面的左右子树对应。
 3)对于这两个子超球体,递归执行步骤2)最终得到了一个球树。
 使用球树找出给定目标点的最近邻方法是首先自上而下贯穿整棵树找出包含目标点所在的叶子,并在这个球里找出与目标点最邻近的点,这将确定出目标点距离它的最近邻点的一个上限值,然后跟KD树查找一样,检查兄弟结点,如果目标点到兄弟结点中心的距离超过兄弟结点的半径与当前的上限值之和,那么兄弟结点里不可能存在一个更近的点;否则的话,必须进一步检查位于兄弟结点以下的子树。检查完兄弟节点后,我们向父节点回溯,继续搜索最小邻近值。当回溯到根节点时,此时的最小邻近值就是最终的搜索结果。

sklearn_example

print(__doc__)

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn import neighbors, datasets

n_neighbors = 15

# import some data to play with
iris = datasets.load_iris()

# we only take the first two features. We could avoid this ugly
# slicing by using a two-dim dataset
X = iris.data[:, :2]
y = iris.target

h = .02  # step size in the mesh

# Create color maps
cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA', '#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000', '#00FF00', '#0000FF'])

for weights in ['uniform', 'distance']:
    # we create an instance of Neighbours Classifier and fit the data.
    clf = neighbors.KNeighborsClassifier(n_neighbors, weights=weights)
    clf.fit(X, y)

    # Plot the decision boundary. For that, we will assign a color to each
    # point in the mesh [x_min, x_max]x[y_min, y_max].
    x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                         np.arange(y_min, y_max, h))
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])

    # Put the result into a color plot
    Z = Z.reshape(xx.shape)
    plt.figure()
    plt.pcolormesh(xx, yy, Z, cmap=cmap_light)

    # Plot also the training points
    plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold,
                edgecolor='k', s=20)
    plt.xlim(xx.min(), xx.max())
    plt.ylim(yy.min(), yy.max())
    plt.title("3-Class classification (k = %i, weights = '%s')"
              % (n_neighbors, weights))

plt.show()

 

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在处理大型数据集时,KNN算法和RadiusNeighbors算法需要计算每个测试样本与训练样本之间的距离,这样的计算需要耗费大量的计算资源。为了解决这个问题,我们可以使用一些加速计算的方法,例如基于树的KNN算法和基于球树的RadiusNeighbors算法。 下面,我们将基于树的KNN算法和基于球树的RadiusNeighbors算法来优化KNN算法和RadiusNeighbors算法,并比较改进前后的运行时间。 1. 基于树的KNN算法 基于树的KNN算法可以通过构建一棵KD树或Ball树来实现快速的邻近搜索。KD树和Ball树都是一种二叉树结构,能够将高维空间中的数据点分割成不同的区域,从而实现快速的搜索。在训练阶段,我们可以通过构建KD树或Ball树来存储训练集中的数据点,从而避免在预测阶段对所有训练样本进行距离计算。在预测阶段,我们只需要搜索最近的k个邻居即可。 下面是基于树的KNN算法的代码实现: ```python from sklearn.neighbors import KNeighborsClassifier from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split import time # 生成样本数据 X, y = make_classification(n_samples=10000, n_features=20, n_informative=10, n_classes=2, random_state=42) # 数据集划分 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 基于树的KNN算法 start_time = time.time() clf_tree = KNeighborsClassifier(n_neighbors=5, algorithm='kd_tree') clf_tree.fit(X_train, y_train) y_pred_tree = clf_tree.predict(X_test) end_time = time.time() print("基于树的KNN算法运行时间为:", end_time - start_time) ``` 2. 基于球树的RadiusNeighbors算法 基于球树的RadiusNeighbors算法可以通过构建一棵球树来实现快速的邻近搜索。球树是一种多叉树结构,能够将高维空间中的数据点划分成不同半径的球形区域,从而实现快速的搜索。在训练阶段,我们可以通过构建球树来存储训练集中的数据点。在预测阶段,我们只需要搜索半径r内的所有邻居即可。 下面是基于球树的RadiusNeighbors算法的代码实现: ```python from sklearn.neighbors import RadiusNeighborsClassifier from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split import time # 生成样本数据 X, y = make_classification(n_samples=10000, n_features=20, n_informative=10, n_classes=2, random_state=42) # 数据集划分 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 基于球树的RadiusNeighbors算法 start_time = time.time() clf_ball = RadiusNeighborsClassifier(radius=0.5, algorithm='ball_tree') clf_ball.fit(X_train, y_train) y_pred_ball = clf_ball.predict(X_test) end_time = time.time() print("基于球树的RadiusNeighbors算法运行时间为:", end_time - start_time) ``` 通过比较基于树的KNN算法和基于球树的RadiusNeighbors算法与原始KNN算法和RadiusNeighbors算法的运行时间,我们可以看出,基于树的KNN算法和基于球树的RadiusNeighbors算法能够显著地提高算法的运行效率。但是,由于构建树结构需要一定的时间和空间开销,如果数据集较小或者k值或半径r较小,可能会导致基于树的KNN算法和基于球树的RadiusNeighbors算法的性能不如原始算法。因此,在实际应用中,需要根据具体情况选择合适的算法和参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值