通过上文可知k近邻算法的基本原理,以及算法的具体流程,kd树的生成和搜索算法原理。本文实现了kd树的生成和搜索算法,通过对算法的具体实现,我们可以对算法原理有进一步的了解。具体代码可以在我的github上查看。

代码

#!/usr/bin/python3
# -*- coding:utf-8 -*- import sys
import numpy as np class Kdtree(object):
'''
类名: Kdtree
用于存储kd树的数据
成员:
__value: 训练数据,保存数据点的坐标
__type: 保存点对应的类型
__dim: 保存当前kd树节点的切分平面维度
left: 左子树
right: 右子树
'''
def __init__(self, node = None, node_type = -1, dim = 0, left = None, right = None):
self.__value = node
self.__type = node_type
self.__dim = dim
self.left = left
self.right = right @property
def type(self):
return self.__type @property
def value(self):
return self.__value @property
def dim(self):
return self.__dim def distance(self, node):
'''
计算当前节点与传入节点之间的距离
参数:
node: 需要计算距离的节点
'''
if node == None:
return sys.maxsize dis = 0
for i in range(len(self.__value)):
dis = dis + (self.__value[i] - node.__value[i]) ** 2
return dis def build_tree(self, nodes, dim = 0):
'''
利用训练数据建立一棵kd树
参数: nodes: 训练数据集
dim: 树的切分平面维度
return: a kd-tree
'''
if len(nodes) == 0:
return None
elif len(nodes) == 1:
self.__dim = dim
self.__value = nodes[0][:-1]
self.__type = nodes[0][-1]
return self #将数据集按照第dim维度的值的大小进行排序
sortNodes = sorted(nodes, key = lambda x:x[dim], reverse = False) #排序后,中间的点为当前节点值
midNode = sortNodes[len(sortNodes) // 2]
sortNodes.remove(midNode)
self.__value = midNode[:-1]
self.__type = midNode[-1]
self.__dim = dim leftNodes = list(filter(lambda x: x[dim] < midNode[dim], sortNodes))
rightNodes = list(filter(lambda x: x[dim] >= midNode[dim], sortNodes))
nextDim = (dim + 1) % (len(midNode) - 1) self.left = Kdtree().build_tree(leftNodes, nextDim)
self.right = Kdtree().build_tree(rightNodes, nextDim) return self def find_type(self, fnode):
'''
在kd树内查找传入点的最近邻点和对应的类型
参数: fnode: 需要判断类型的点
return: fnode的最近邻点和其类型
'''
if fnode == None:
return self, -1 fNode = Kdtree(fnode) #首先搜索整棵树到达叶子节点
path = []
currentNode = self
while currentNode != None:
path.append(currentNode) dim = currentNode.__dim
if fNode.value[dim] < currentNode.value[dim]:
currentNode = currentNode.left
else:
currentNode = currentNode.right #path的最后一个节点即为叶子节点
nearestNode = path[-1]
nearestDist = fNode.distance(nearestNode)
path = path[:-1] #向上进行回溯
while path != None and len(path) > 0:
currentNode = path[-1]
path = path[:-1]
dim = currentNode.__dim #判断当前点是否比最近点更近
if fNode.distance(currentNode) < nearestDist:
nearestNode = currentNode
nearestDist = fNode.distance(currentNode) #当前最近点一定存在于当前点的一棵子树上,那么找到它的兄弟子树的节点
brotherNode = currentNode.left
if fNode.value[dim] < currentNode.value[dim]:
brotherNode = currentNode.right if brotherNode == None:
continue #若兄弟子树的节点对应的区域与以fnode为圆心,以nearestDist为半径的圆相交,则进入兄弟子树,进行递归查找
bdim = brotherNode.__dim
if np.abs(fnode[bdim] - brotherNode.__value[bdim]) < nearestDist:
cNode, _ = brotherNode.find_type(fnode)
if fNode.distance(cNode) < nearestDist:
nearestDist = fNode.distance(cNode)
nearestNode = cNode return nearestNode, nearestNode.type if __name__ == "__main__": #训练数据集
trainArray = [[1.0, 1.0, 'a'], [1.1, 1.1, 'a'], [1.5, 1.5, 'a'], \
[5.0, 5.0, 'b'], [5.2, 5.2, 'b'], [5.5, 5.5, 'b'], \
[3.0, 2.5, 'c'], [3.1, 2.8, 'c'], [3.2, 2.4, 'c']] kdtree = Kdtree().build_tree(trainArray) #test1
testNode = [1.6, 1.5]
_, testType = kdtree.find_type(testNode)
print("the type of ", testNode, "is ", testType) #test2
testNode = [3.5, 2.7]
_, testType = kdtree.find_type(testNode)
print("the type of ", testNode, "is ", testType) #test3
testNode = [4.3, 5.1]
_, testType = kdtree.find_type(testNode)
print("the type of ", testNode, "is ", testType)

测试结果

通过测试结果可知,kd树可以有效地对输入数据进行类型的识别。

讨论

虽然通过测试结果正确,但代码依然存在许多需要改进的地方,如kd树的选择,可以通过改进为红黑平衡树,来提高搜索速度。以及对于树的每层切分平面的维度选择,可以选择各维度中方差最大的维度,这样在此维度下的点分布更加分散,使后续的查找难度更小等等。

统计学习三:2.K近邻法代码实现(以最近邻法为例)的更多相关文章

  1. 统计学习方法三:K近邻

    一.什么是K近邻? K近邻是一种基本的分类和回归方法. 在分类时,对新的实例,根据其K个最近邻的训练实例的类别,通过多数表决权等方式预测其类别. 通俗的讲,找K个和其关系最近的邻居,哪个类别的邻居多, ...

  2. 统计学习笔记之k近邻法

    1.kNN算法的思想:给定一个训练数据集,对新的输入实例,在训练集中找到与该实例最近邻的k个实例,这k个实例的多数属于某类,就把输入实例分为这个类. 2.算法 (1)根据给定的距离度量,在训练集T中找 ...

  3. 4.机器学习——统计学习三要素与最大似然估计、最大后验概率估计及L1、L2正则化

    1.前言 之前我一直对于“最大似然估计”犯迷糊,今天在看了陶轻松.忆臻.nebulaf91等人的博客以及李航老师的<统计学习方法>后,豁然开朗,于是在此记下一些心得体会. “最大似然估计” ...

  4. kd树 求k近邻 python 代码

      之前两篇随笔介绍了kd树的原理,并用python实现了kd树的构建和搜索,具体可以参考 kd树的原理 python kd树 搜索 代码 kd树常与knn算法联系在一起,knn算法通常要搜索k近邻, ...

  5. 统计学习三:1.k近邻法

    全文引用自<统计学习方法>(李航) K近邻算法(k-nearest neighbor, KNN) 是一种非常简单直观的基本分类和回归方法,于1968年由Cover和Hart提出.在本文中, ...

  6. 统计学习方法(三)——K近邻法

    /*先把标题给写了.这样就能经常提醒自己*/ 1. k近邻算法 k临近算法的过程,即对一个新的样本,找到特征空间中与其最近的k个样本,这k个样本多数属于某个类,就把这个新的样本也归为这个类. 算法  ...

  7. 第三章 K近邻法(k-nearest neighbor)

    书中存在的一些疑问 kd树的实现过程中,为何选择的切分坐标轴要不断变换?公式如:x(l)=j(modk)+1.有什么好处呢?优点在哪?还有的实现是通过选取方差最大的维度作为划分坐标轴,有何区别? 第一 ...

  8. kNN(k近邻)算法代码实现

    目标:预测未知数据(或测试数据)X的分类y 批量kNN算法 1.输入一个待预测的X(一维或多维)给训练数据集,计算出训练集X_train中的每一个样本与其的距离 2.找到前k个距离该数据最近的样本-- ...

  9. 机器学习 —— 基础整理(三)生成式模型的非参数方法: Parzen窗估计、k近邻估计;k近邻分类器

    本文简述了以下内容: (一)生成式模型的非参数方法 (二)Parzen窗估计 (三)k近邻估计 (四)k近邻分类器(k-nearest neighbor,kNN) (一)非参数方法(Non-param ...

随机推荐

  1. 奇(qi)谋(ji)巧(yin)计(qiao)

    一.打表法 0.http://oeis.org/ 1.差分序列:https://blog.csdn.net/wu_tongtong/article/details/79115921 对于一个多项式产生 ...

  2. 洛谷P3812 【模板】线性基

    题目背景 这是一道模板题. 题目描述 给定n个整数(数字可能重复),求在这些数中选取任意个,使得他们的异或和最大. 输入输出格式 输入格式: 第一行一个数n,表示元素个数 接下来一行n个数 输出格式: ...

  3. excel批量转换为CSV格式,xls批量导出csv格式

    工具/原料   excel 2013 地址链接:http://pan.baidu.com/s/1c1ZABlu 密码:d3rc 方法/步骤     首选我们把需要导出为CVS的Excel文件整理集中到 ...

  4. JDBC中执行sql语句的 增 , 删 , 改 , 查 的方法

    executeQuery()  : 执行 SELECT 语句,它几乎是使用最多的 SQL 语句 executeUpdate() :   执行 INSERT.UPDATE 或 DELETE 语句以及 S ...

  5. .Net Core如何在程序的任意位置使用和注入服务

    最近有人问我:我该如何在Startup类之外的地方注入我的服务呢,都写在startup里看着好乱:我该如何在程序的其他地方获取我注入的服务呢: 故我写了这篇博客,文中有不对的地方欢迎指正. 一.如何在 ...

  6. 微信小程序 —— 仿制豆瓣(一)

    先预览一下效果 欢迎扫码查看 码云地址:https://gitee.com/mk_23/little_chen_xu.git 预览完成,首先进入app.json文件中配置参数,主要就是配置我们要用的页 ...

  7. 树莓派3B+学习笔记:2、更改显示分辨率

    1.打开终端,输入 sudo raspi-config 选择第7行: 2.选择第5行: 3.选择一个自己习惯的分辨率(我选择1024X768),确定后重启,VNC会自动连接: 4.更改分辨率完成,方便 ...

  8. services 系统服务的启动、停止、卸载

    MySQL服务的启动.停止与卸载 在 Windows 命令提示符下运行: 启动: net start MySQL 停止: net stop MySQL 卸载: sc delete MySQL Sc d ...

  9. QImage对一般图像的处理

    QImage对一般图像的处理 Qt中QImage类封装了对于一般图像像素级的操作,图像显示则使用QPixmap. 本文说说对一般图像(常见格式,图像不大)的处理,比如将彩色图像处理为灰度图像.首先要获 ...

  10. 解决CentOS下可以ping通ip ping不通域名

    现象:1. ping不通域名,比如 www.qq.com 2. 可以ping通ip,比如 61.135.157.156 分析:1. 查看DNS配置文件 /etc/resolve.conf, 里面的服务 ...