KNN中KD树的查询操作

简介: KNN中KD树的查询操作


1.简介

KD树(K-Dimensional Tree)是一种二叉树,用于在k维空间中对数据进行分割和组织。它具有以下特点:

2.基本知识点:

  1. KD树是一种二叉树,每个节点代表一个k维向量。
  2. 每个节点的左子树和右子树分别表示比当前节点小和大的数据。
  3. KD树的构建过程是通过递归的方式进行的,每次选择一个维度作为切分维度,以该维度的中值作为节点,将数据集切分成两部分。
  4. 在查询时,通过比较目标向量和节点的切分维度的值,可以确定搜索路径。

3.与平衡二叉树的不同之处:

  1. 平衡二叉树(如AVL树、红黑树)的主要目的是保持树的左右子树的高度差不超过1,从而提供快速的插入、删除和搜索操作。
  2. KD树并不一定是平衡的,因为它的构建过程是基于数据集的切分,而不是固定的旋转操作。
  3. KD树的构建过程是通过选择切分维度和切分值来进行的,因此它可能会导致树的不平衡。
  4. 不平衡的KD树可能导致搜索操作的效率下降,因为搜索路径可能会非常长。

4.基于上篇博客编写:

需要将上篇博客中的函数进行导入(作者命名为了KDtree.py):

KD树构建链接

5.代码:

这里随机了10000个1到1000的随机整数,输入的点需要自己手动调整(这里设置的是(44, 46),在代码中可以看到)

代码实现了使用KD树进行最近邻搜索的功能。首先,通过随机生成一组坐标点作为输入数据。然后,给定一个预测点predict,代码使用普通方法和KD树两种方式分别找到距离预测点最近的点,并计算出最近距离。

具体流程如下:

  1. 创建了一个KD树,将输入的数据作为构建KD树的节点。
  2. 使用普通方法,通过计算每个点到预测点的欧几里得距离,对输入数据进行排序,找到距离最近的点。
  3. 使用KD树方法,通过建立的KD树结构,从根节点开始,按照预测点的坐标与节点的划分维度进行比较,逐步向下搜索,直到找到最近的叶子节点。
  4. 在搜索过程中,通过维护一个栈来记录搜索路径,以便在回溯时处理另一侧的节点。
  5. 最后,输出普通方法和KD树方法分别找到的最近点及其距离,并输出两种方法的执行时间。
from KDtree import *
import math
import random
import time
def append_stack(node, predict, stack):
    loop_num = 0
    stack.append(node.data + (0,))
    while node.rchild != None or node.lchild != None:
        tup = None
        if predict[loop_num % 2] < node.data[loop_num % 2]:
            if node.lchild == None:
                break
            node = node.lchild
            tup = (-1,)
        else:
            if node.rchild == None:
                break
            node = node.rchild
            tup = (1,)
        stack.append(node.data + tup)
        loop_num += 1
def search(root, predict, stack):
    min_distance = 1000
    min_node = None
    while True:
        up_node = root
        distance = math.sqrt(pow((stack[-1][0] - predict[0]), 2) + pow((stack[-1][1] - predict[1]), 2))
        if distance < min_distance:
            min_distance = distance
            min_node = stack[-1]
        # 移除这个点
        last = stack[-1][2]
        stack.pop()
        if stack == []:
            break
        # 下一个点用来比较是否相交,以确定要不要给另一侧的点考虑进去
        if min_distance > abs(predict[(len(stack) - 1) % 2] - stack[-1][(len(stack) - 1) % 2]):
            # 得到最后一个点的位置
            for _, _, k in stack[1:]:
                if k == -1:
                    up_node = up_node.lchild
                if k == 1:
                    up_node = up_node.rchild
            if last == -1 and up_node.rchild != None:
                append_stack(up_node.rchild, predict, stack)
            if last == 1 and up_node.lchild != None:
                append_stack(up_node.lchild, predict, stack)
    return min_node
if __name__ == "__main__":
    list_data = [(random.randint(1, 1000), random.randint(1, 1000)) for _ in range(10000)]   # 输入数据
    predict = (44, 46)
    # ----------普通办法-----------
    time_start = time.time()  # 记录开始时间
    # ++++核心代码++++
    list_data1 = sorted(list_data, key=lambda x: math.sqrt(pow((predict[0] - x[0]), 2) + pow((predict[1] - x[1]), 2)))
    # ++++核心代码++++
    print(list_data1[0])
    print(math.sqrt(pow((list_data1[0][0] - predict[0]), 2) + pow((list_data1[0][1] - predict[1]), 2)))
    time_end = time.time()  # 记录结束时间
    time_sum = time_end - time_start  # 计算的时间差为程序的执行时间,单位为秒/s
    print('time_sum1: ', time_sum)
    # ----------------------------
    print('**************************************')
    # ----------KD树办法-----------
    time_start = time.time()  # 记录开始时间
    # ++++核心代码++++
    root = create(list_data)    #创建KD树
    # ++++核心代码++++
    time_end = time.time()  # 记录结束时间
    time_sum = time_end - time_start  # 计算的时间差为程序的执行时间,单位为秒/s
    print('time_sum2.1: ', time_sum)
    time_start = time.time()  # 记录开始时间
    # ++++核心代码++++
    stack = []
    append_stack(root, predict, stack)
    list_data2 = search(root, predict, stack)
    # ++++核心代码++++
    print(list_data2)
    print(math.sqrt(pow((list_data2[0] - predict[0]), 2) + pow((list_data2[1] - predict[1]), 2)))
    time_end = time.time()  # 记录结束时间
    time_sum = time_end - time_start  # 计算的时间差为程序的执行时间,单位为秒/s
    print('time_sum2.2: ', time_sum)
    # ----------------------------

6.效果:

  1. time_sum1代表通过排序得到最邻近点需要的时间
  2. time_sum2.1代表构建KD树需要的时间
  3. time_sum2.1代表通过KD树查询得到最邻近点需要的时间

确实,构造KD树会比较浪费时间,但是通过KD树查询需要的时间几乎为0

小结:

关注我给大家分享更多有趣的知识,以下是个人公众号,提供 ||代码兼职|| ||代码问题求解||

由于本号流量还不足以发表推广,搜我的公众号即可:

目录
相关文章
|
3月前
|
存储 算法 C语言
"揭秘C语言中的王者之树——红黑树:一场数据结构与算法的华丽舞蹈,让你的程序效率飙升,直击性能巅峰!"
【8月更文挑战第20天】红黑树是自平衡二叉查找树,通过旋转和重着色保持平衡,确保高效执行插入、删除和查找操作,时间复杂度为O(log n)。本文介绍红黑树的基本属性、存储结构及其C语言实现。红黑树遵循五项基本规则以保持平衡状态。在C语言中,节点包含数据、颜色、父节点和子节点指针。文章提供了一个示例代码框架,用于创建节点、插入节点并执行必要的修复操作以维护红黑树的特性。
99 1
|
27天前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
16 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
1月前
|
机器学习/深度学习 算法
机器学习入门(三):K近邻算法原理 | KNN算法原理
机器学习入门(三):K近邻算法原理 | KNN算法原理
|
1月前
|
机器学习/深度学习 算法 API
机器学习入门(五):KNN概述 | K 近邻算法 API,K值选择问题
机器学习入门(五):KNN概述 | K 近邻算法 API,K值选择问题
|
2月前
|
大数据 UED 开发者
实战演练:利用Python的Trie树优化搜索算法,性能飙升不是梦!
在数据密集型应用中,高效搜索算法至关重要。Trie树(前缀树/字典树)通过优化字符串处理和搜索效率成为理想选择。本文通过Python实战演示Trie树构建与应用,显著提升搜索性能。Trie树利用公共前缀减少查询时间,支持快速插入、删除和搜索。以下为简单示例代码,展示如何构建及使用Trie树进行搜索与前缀匹配,适用于自动补全、拼写检查等场景,助力提升应用性能与用户体验。
50 2
|
27天前
|
存储 算法
数据结构与算法学习十六:树的知识、二叉树、二叉树的遍历(前序、中序、后序、层次)、二叉树的查找(前序、中序、后序、层次)、二叉树的删除
这篇文章主要介绍了树和二叉树的基础知识,包括树的存储方式、二叉树的定义、遍历方法(前序、中序、后序、层次遍历),以及二叉树的查找和删除操作。
22 0
|
2月前
|
算法 Python
KNN
【9月更文挑战第11天】
48 13
|
1月前
|
存储 算法 Java
数据结构和算法--分段树
数据结构和算法--分段树
12 0
|
2月前
|
算法 大数据
K-最近邻(KNN)
K-最近邻(KNN)