k近邻算法的介绍

k近邻算法是一种基本的分类和回归方法,这里只实现分类的k近邻算法。

k近邻算法的输入为实例的特征向量,对应特征空间的点;输出为实例的类别,可以取多类。

k近邻算法不具有显式的学习过程,实际上k近邻算法是利用训练数据集对特征向量空间进行划分。将划分的空间模型作为其分类模型。

k近邻算法的三要素

k值的选择:即分类决策时选择k个最近邻实例;

距离度量:即预测实例点和训练实例点间的距离,一般使用L2距离即欧氏距离;

分类决策规则。

下面对三要素进行一下说明:

1.欧氏距离即欧几里得距离,高中数学中用来计算点和点间的距离公式;

2.k值选择:k值选择会对k近邻法结果产生重大影响,如果选择较小的k值,相当于在较小的邻域中训练实例进行预测,这样有点是“近似误差”会减小,即只与输入实例较近(相似)的训练实例才会起作用,缺点是“估计误差”会增大,即对近邻的实例点很敏感。而k值过大则相反。实际中取较小的k值通过交叉验证的方法取最优k值。

3.k近邻法的分类决策规则往往采用多数表决的方式,这等价于“经验风险最小化”。

k近邻算法的实现:kd树

实现k近邻法是要考虑的主要问题是如何退训练数据进行快速的k近邻搜索,当训练实例数很大是显然通过一般的线性搜索方式效率低下,因此为了提高搜索效率,需要构造特殊的数据结构对训练实例进行存储。kd树就是一种不错的数据结构,可以大大提高搜索效率。

本质商kd树是对k维空间的一个划分,构造kd树相当与使用垂直于坐标轴的超平面将k维空间进行切分,构造一系列的超矩形,kd树的每一个结点对应一个这样的超矩形。

kd树本质上是一棵二叉树,当通过一定规则构造是他是平衡的。

下面是过早kd树的算法:

开始:构造根结点,根节点对应包含所有训练实例的k为空间。 选择第1维为坐标轴,以所有训练实例的第一维数据的中位数为切分点,将根结点对应的超矩形切分为两个子区域。由根结点生成深度为1的左右子结点,左结点对应第一维坐标小于切分点的子区域,右子结点对应第一位坐标大于切分点的子区域。

重复:对深度为j的结点选择第l维为切分坐标轴,l=j(modk)+1,以该区域中所有训练实例的第l维的中位数为切分点,重复第一步。

直到两个子区域没有实例存在时停止。形成kd树。

以下是kd树的python实现

准备工作

#读取数据准备

def file2matrix(filename):

fr = open(filename)

returnMat = [] #样本数据矩阵

for line in fr.readlines():

line = line.strip().split('\t')

returnMat.append([float(line[0]),float(line[1]),float(line[2]),float(line[3])])

return returnMat

#将数据归一化,避免数据各维度间的差异过大

def autoNorm(data):

#将data数据和类别拆分

data,label = np.split(data,[3],axis=1)

minVals = data.min(0) #data各列的最大值

maxVals = data.max(0) #data各列的最小值

ranges = maxVals - minVals

normDataSet = np.zeros(np.shape(data))

m = data.shape[0]

#tile函数将变量内容复制成输入矩阵同样大小的矩阵

normDataSet = data - np.tile(minVals,(m,1))

normDataSet = normDataSet/np.tile(ranges,(m,1))

#拼接

normDataSet = np.hstack((normDataSet,label))

return normDataSet

//数据实例

40920 8.326976 0.953952 3

14488 7.153469 1.673904 2

26052 1.441871 0.805124 1

75136 13.147394 0.428964 1

38344 1.669788 0.134296 1

72993 10.141740 1.032955 1

35948 6.830792 1.213192 3

42666 13.276369 0.543880 3

67497 8.631577 0.749278 1

35483 12.273169 1.508053 3

//每一行是一个数据实例,前三维是数据值,第四维是类别标记

树结构定义

#构建kdTree将特征空间划分

class kd_tree:

"""

定义结点

value:节点值

dimension:当前划分的维数

left:左子树

right:右子树

"""

def __init__(self, value):

self.value = value

self.dimension = None #记录划分的维数

self.left = None

self.right = None

def setValue(self, value):

self.value = value

#类似Java的toString()方法

def __str__(self):

return str(self.value)

kd树构造

def creat_kdTree(dataIn, k, root, deep):

"""

data:要划分的特征空间(即数据集)

k:表示要选择k个近邻

root:树的根结点

deep:结点的深度

"""

#选择x(l)(即为第l个特征)为坐标轴进行划分,找到x(l)的中位数进行划分

# x_L = data[:,deep%k] #这里选取第L个特征的所有数据组成一个列表

#获取特征值中位数,这里是难点如果numpy没有提供的话

if(dataIn.shape[0]>0): #如果该区域还有实例数据就继续

dataIn = dataIn[dataIn[:,int(deep%k)].argsort()] #numpy的array按照某列进行排序

data1 = None; data2 = None

#拿取根据xL排序的中位数的数据作为该子树根结点的value

if(dataIn.shape[0]%2 == 0): #该数据集有偶数个数据

mid = int(dataIn.shape[0]/2)

root = kd_tree(dataIn[mid,:])

root.dimension = deep%k

dataIn = np.delete(dataIn,mid, axis = 0)

data1,data2 = np.split(dataIn,[mid], axis=0)

#mid行元素分到data2中,删除放到根结点中

elif(dataIn.shape[0]%2 == 1):

mid = int((dataIn.shape[0]+1)/2 - 1) #这里出现递归溢出,当shape为(1,4)时出现,原因是np.delete时没有赋值给dataIn

root = kd_tree(dataIn[mid,:])

root.dimension = deep%k

dataIn = np.delete(dataIn,mid, axis = 0)

data1,data2 = np.split(dataIn,[mid], axis=0) #mid行元素分到data1中,删除放到根结点中

#深度加一

deep+=1

#递归构造子树

#这里犯了严重错误,递归调用是将root传递进去,造成程序混乱,应该给None

root.left = creat_kdTree(data1, k, None, deep)

root.right = creat_kdTree(data2, k, None, deep)

return root

前序遍历测试

#前序遍历kd树

def preorder(kd_tree,i):

print(str(kd_tree.value)+" :"+str(kd_tree.dimension)+":"+str(i))

if kd_tree.left != None:

preorder(kd_tree.left,i+1)

if kd_tree.right != None:

preorder(kd_tree.right,i+1)

kd树的最近邻搜索

最近邻搜索算法,k近邻搜索在此基础上实现

原理:首先找到包含目标点的叶节点;然后从该也结点出发,一次退回到父节点,不断查找与目标点最近的结点,当确定不可能存在更近的结点是停止。

def findClosest(kdNode,closestPoint,x,minDis,i=0):

"""

这里存在一个问题,当传递普通的不可变对象minDis时,递归退回第一次找到

最端距离前,minDis改变,最后结果混乱,这里传递一个可变对象进来。

kdNode:是构造好的kd树。

closestPoint:是存储最近点的可变对象,这里是array

x:是要预测的实例

minDis:是当前最近距离。

"""

if kdNode == None:

return

#计算欧氏距离

curDis = (sum((kdNode.value[0:3]-x[0:3])**2))**0.5

if minDis[0] < 0 or curDis < minDis[0] :

i+=1

minDis[0] = curDis

closestPoint[0] = kdNode.value[0]

closestPoint[1] = kdNode.value[1]

closestPoint[2] = kdNode.value[2]

closestPoint[3] = kdNode.value[3]

print(str(closestPoint)+" : "+str(i)+" : "+str(minDis))

#递归查找叶节点

if kdNode.value[kdNode.dimension] >= x[kdNode.dimension]:

findClosest(kdNode.left,closestPoint,x,minDis,i)

else:

findClosest(kdNode.right, closestPoint, x, minDis,i)

#计算测试点和分隔超平面的距离,如果相交进入另一个叶节点重复

rang = abs(x[kdNode.dimension] - kdNode.value[kdNode.dimension])

if rang > minDis[0] :

return

if kdNode.value[kdNode.dimension] >= x[kdNode.dimension]:

findClosest(kdNode.right,closestPoint,x,minDis,i)

else:

findClosest(kdNode.left, closestPoint, x, minDis,i)

测试:

data = file2matrix("datingTestSet2.txt")

data = np.array(data)

normDataSet = autoNorm(data)

sys.setrecursionlimit(10000) #设置递归深度为10000

trainSet,testSet = np.split(normDataSet,[900],axis=0)

kdTree = creat_kdTree(trainSet, 3, None, 0)

newData = testSet[1,0:3]

closestPoint = np.zeros(4)

minDis = np.array([-1.0])

findClosest(kdTree, closestPoint, newData, minDis)

print(closestPoint)

print(testSet[1,:])

print(minDis)

测试结果

[0.35118819 0.43961918 0.67110669 3. ] : 1 : [0.40348346]

[0.11482037 0.13448927 0.48293309 2. ] : 2 : [0.30404792]

[0.12227055 0.07902201 0.57826697 2. ] : 3 : [0.22272422]

[0.0645755 0.10845299 0.83274698 2. ] : 4 : [0.07066192]

[0.10020488 0.15196271 0.76225551 2. ] : 5 : [0.02546591]

[0.10020488 0.15196271 0.76225551 2. ]

[0.08959933 0.15442555 0.78527657 2. ]

[0.02546591]

k近邻搜索实现

在最近邻的基础上进行改进得到:

这里的closestPoint和minDis合并,一同处理

#k近邻搜索

def findKNode(kdNode, closestPoints, x, k):

"""

k近邻搜索,kdNode是要搜索的kd树

closestPoints:是要搜索的k近邻点集合,将minDis放入closestPoints最后一列合并

x:预测实例

minDis:是最近距离

k:是选择k个近邻

"""

if kdNode == None:

return

#计算欧式距离

curDis = (sum((kdNode.value[0:3]-x[0:3])**2))**0.5

#将closestPoints按照minDis列排序,这里存在一个问题,排序后返回一个新对象

#不能将其直接赋值给closestPoints

tempPoints = closestPoints[closestPoints[:,4].argsort()]

for i in range(k):

closestPoints[i] = tempPoints[i]

#每次取最后一行元素操作

if closestPoints[k-1][4] >=10000 or closestPoints[k-1][4] > curDis:

closestPoints[k-1][4] = curDis

closestPoints[k-1,0:4] = kdNode.value

#递归搜索叶结点

if kdNode.value[kdNode.dimension] >= x[kdNode.dimension]:

findKNode(kdNode.left, closestPoints, x, k)

else:

findKNode(kdNode.right, closestPoints, x, k)

#计算测试点和分隔超平面的距离,如果相交进入另一个叶节点重复

rang = abs(x[kdNode.dimension] - kdNode.value[kdNode.dimension])

if rang > closestPoints[k-1][4]:

return

if kdNode.value[kdNode.dimension] >= x[kdNode.dimension]:

findKNode(kdNode.right, closestPoints, x, k)

else:

findKNode(kdNode.left, closestPoints, x, k)

测试

data = file2matrix("datingTestSet2.txt")

data = np.array(data)

normDataSet = autoNorm(data)

sys.setrecursionlimit(10000) #设置递归深度为10000

trainSet,testSet = np.split(normDataSet,[900],axis=0)

kdTree = creat_kdTree(trainSet, 3, None, 0)

newData = testSet[1,0:3]

print("预测实例点:"+str(newData))

closestPoints = np.zeros((3,5)) #初始化参数

closestPoints[:,4] = 10000.0 #给minDis列赋值

findKNode(kdTree, closestPoints, newData, 3)

print("k近邻结果:"+str(closestPoints))

测试结果

预测实例点:[0.08959933 0.15442555 0.78527657]

k近邻结果:[[0.10020488 0.15196271 0.76225551 2. 0.02546591]

[0.10664709 0.13172159 0.83777837 2. 0.05968697]

[0.09616206 0.20475001 0.75047289 2. 0.06153793]]

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

kd树 python实现_python K近邻算法的kd树实现相关推荐

  1. K近邻算法的kd树实现

    k近邻算法的介绍 k近邻算法是一种基本的分类和回归方法,这里只实现分类的k近邻算法. k近邻算法的输入为实例的特征向量,对应特征空间的点:输出为实例的类别,可以取多类. k近邻算法不具有显式的学习过程 ...

  2. python机器学习---1. K近邻算法

    机器学习的方法是基于数据产生的"模型" (model) 的算法,也称"学习算法" (learning algorithm).包括有监督学习(supervised ...

  3. 基于KD树的K近邻算法(KNN)算法

    文章目录 KNN 简介 KNN 三要素 距离度量 k值的选择 分类决策规则 KNN 实现 1,构造kd树 2,搜索最近邻 3,预测 用kd树完成最近邻搜索 K近邻算法(KNN)算法,是一种基本的分类与 ...

  4. K近邻算法讲解与python实现(附源码demo下载链接)

    k近邻算法概述 对应demo源码及数据:传送门 K近邻(k-Nearest Neighbor,简称kNN)算法,是一种应用很广泛的监督学习算法.它非常有效且易于掌握,其工作机制也很简单:给定测试样本, ...

  5. 机器学习第七章之K近邻算法

    K近邻算法(了解) 7.1 K近邻算法 7.1.1 K近邻算法的原理介绍 7.1.2 K近邻算法的计算步骤及代码实现 7.2 数据预处理之数据归一化 7.2.1 min-max标准化 7.2.2 Z- ...

  6. K近邻算法你掌握了吗?来测试一下就知道了

    https://www.toutiao.com/a6703706053311201795/ 2019-06-18 11:23:15 简介 如果你要问我两个机器学习中最直观明了且通俗易懂的算法--那必然 ...

  7. 基于kd树的k近邻算法——KNN

    1.简介 k近邻算法是机器学习中一种基本的分类与回归算法,对你没听错k近邻算法不仅可以用来做分类,还可以用于回归,英文全称为k-Nearest Neighbor简称k-NN.k近邻算法属于一种有监督学 ...

  8. 从K近邻算法、距离度量谈到KD树、SIFT+BBF算法

    原文出自:http://blog.csdn.net/v_JULY_v/article/details/8203674 前言 前两日,在微博上说:"到今天为止,我至少亏欠了3篇文章待写:1.K ...

  9. 【转】从K近邻算法、距离度量谈到KD树、SIFT+BBF算法

    最近在看<统计学习方法>,发现这么一篇好文章,与大家分享 转自:http://blog.csdn.net/v_july_v/article/details/8203674?reload 前 ...

  10. python k近邻算法_python中的k最近邻居算法示例

    python k近邻算法 K最近邻居(KNN) (K-Nearest Neighbors (KNN)) KNN is a supervised machine learning algorithm t ...

最新文章

  1. Activiti工作流之流程变量
  2. JAVA的三种常量池
  3. TeamCity+Rancher+Docker实现.Net Core项目DevOps
  4. vi编辑器服务器维护,vi编辑器有哪几种工作模式及如何转换_网站服务器运行维护,vi编辑器,工作模式...
  5. 幂的末尾(信息学奥赛一本通-T1084)
  6. 三极管的经典模型——两个二极管连接和三极管人(transistor man)
  7. 蛮力法求最大字段和时间复杂度_中文分词算法之--最大匹配法
  8. 手把手教你一个321MB的视频,如何压缩到300MB以内?
  9. 这些APP专注于大众的生活,致远互联专注于他们的管理
  10. jsp统计页面访问量和刷访问量的简单使用
  11. 各种门锁的内部结构图_有没有这种执手门锁的内部结构图?
  12. 滴滴美团58携程,那些发生在大并购谈判桌背后的故事
  13. Python 玩转数据 19 - 数据操作 正则表达式 Regular Expressions 搜索模式匹配
  14. 千年服务器GM命令及使用详解
  15. twitter、facebook、pinterest、linkedin 分享代码
  16. 三国演义人物出场次数
  17. 巧用电池小工具 电量问题全掌握
  18. 特运tong app sign签名破解
  19. 记录chrome 浏览器 本地ip 地址报 CORS 错误
  20. STEM教育-制作纸飞机游戏

热门文章

  1. Python正则表达式快速入门
  2. 「堡垒之夜」母公司Epic元宇宙蓝图:颠覆Facebook的社交媒体,拆除苹果的高墙花园...
  3. win10怎么获得计算机权限,Win10如何获取TrustedInstaller超级权限?
  4. 异或(另类斐波那契数列题)
  5. Javascript传奇
  6. 电容屏物体识别_浅谈多点电容屏物体识别,实物识别技术
  7. 2018年湘潭大学程序设计竞赛 - 题解
  8. 百度地图开放平台web api 获取上海市所有小区信息
  9. 《创业维艰》详细的思维导图
  10. 鲁大师最新笔记本排行榜,微星 Raider GE76性能最强