kd树的搜索方式
至下而上的搜索
kd树的基本逻辑是,建立k-d树:
def findtree(树,当前维度 = 1,点):
if 当前树只有一个节点:
return 该节点,搜索路径
if 点[当前维度]<树的当前节点[当前维度]:
findtree(树,当前维度>>1,点)
更新搜索路径
else:
findtree(树,当前维度>>1,点)
更新搜索路径
def down_tree(树,输入点,最优点=0,原递归节点表=0,判断条件=0):
#其实可以通过树是否存在,来判断是否计算
if 树 == None or 判断条件 == 0:
当前最近点,原递归节点表 = findtree(树,树的根节点的维度,输入点)
递归节点表1 = 递归节点表.copy()
#判断条件用于判断是否执行搜索最近点
递归节点 = 原递归节点表.最后一个点
#递归节点表备份,用于存储操作
#最近点仅第一次更新即可
最近点距离 = 欧氏距离(输入点-当前最近点)
#每次迭代都要更新,递归节点距离
递归节点的距离 = 欧氏距离(输入点-原递归节点表.最后一个点)
#递归节点算法
///#判断链表是否到头,到头则返回最近点和递归链表
if 原递归节点表 is None
return 当前最近点,递归节点表1
if 递归节点的距离 < 最近点的距离:
当前最近点 = 递归节点
最近点的距离 = 递归节点的距离
#实际上,如果递归点是当前最小点,只有当切分维度距离超平面距离刚刚相等时
#才不用在递归节点的另一个里寻找,这种情况在统计学上概率为0.所以我们还是要判断。
if 最近点的距离 > 超平面的距离:
#说明了与另一个区域相交,则在该节点,此时节点为递归节点(父节点),在另一个子树里面寻找最优点。
子树 = 当前最近点.另一个子树
# 考虑没有子树的情况,则当前点为最优点
if 子树 = None
#则说明当前点为最优点,递归向上
原递归节点表 -> 1
#使用输入条件,来使递归跳过第一步
down_tree(None,输入点,当前最近点,原递归节点表,判断条件=1):
#跳转到(2)
else
最优点,递归节点表 = down_tree(子树,输入点,当前最近点,原递归节点表,判断条件=0)
最优距离 = 欧式距离(最优点-输入点)
if 最优距离 < 最近点的距离
#说明该区域内没有最优点,最优点依然为当前点,不操作,递归
原递归节点表 -> 1
down_tree(None,输入点,最优点,原递归节点表,判断条件=1):
#跳转到(2)
else
#说明有最优点,更新最优点,更新递归结点链表
当前最近点 = 最优点
最近点的距离 = 最优距离
原递归节点表 = 原递归节点表 + 递归节点表
递归节点表备份更新 = 递归节点表1 + 递归节点表
#更新了链表和最近点,进行从新递归
down_tree(None,输入点,当前最近点,递归节点表备份更新,判断条件=1):
else 最近点的距离 < 超平面距离
#说明了没有与另一个区域相交,这种概率理论上为0
原递归节点表 -> 1
down_tree(None,输入点,最优点,原递归节点表,判断条件=1):
#跳转到(2)
#递归节点的距离 < 最近点的距离,不用更新节点,依然判断超平面,方法与上面一样,
#说明上面的情况独立于是否跟新点。
#观察跳转到(2)的情况,一般返回,最优点,最优距离通过最优点计算,以及链表。添加判断是否执行第一步即可
///#如果做Knn则新建一个长度为k的链表,如果有点比之前点小,则插入其中,最后返回K个点
???输入点可以优化为 constant ,或者放到最后定义为常量,不清楚该程序的震荡性质如何。可能有部分地方可以优化
至上而下的搜索方式
该搜索方式如图所示
从上到下的搜索方式算法相同:
(1)初始化根节点当成当前最近点(有输入则不初始化)
计算距离,判断输入点在节点的哪一侧,
左侧:
if 左子树为空:
if 右子树不为空,且与超平面有交集:
搜索(右子树节点为最近点)
跳转->(1)
else:
return 点
else
搜索(左子树节点为最近点)
跳转->(1)
右侧:
if 右子树为空:
if 左子树不为空,且与超平面有交集
搜索(左子树节点为最近点)
跳转->(1)
else:
return 点
else:
搜索(右子树节点为最近点)
跳转->(1)
从上往下往往会执行跟多的步骤,后向前回溯更好。
KNN一般算法
采用python书写的代码,用pandas数据操作,matplot绘图。
实在没啥时间的我就不写成中文了。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
#打开文件
def field_open(list='D:\suanfa\Knn\datingTestSet.txt'):
folines = pd.read_csv(list, header=None, sep='\t')
print(folines.shape)
return folines
#绘制图像
def plot_fig(a):
Colors = []
for m in a.iloc[:, -1]:
if m == 'didntLike':
Colors.append('black')
if m == 'smallDoses':
Colors.append('orange')
if m == 'largeDoses':
Colors.append('red')
# 绘制图片,
fig = plt.figure()
ax = fig.add_subplot(221)
ax.scatter(a.iloc[:, 0], a.iloc[:, 1], c=Colors)
ax1 = fig.add_subplot(222)
ax1.scatter(a.iloc[:, 0], a.iloc[:, 2], c=Colors)
ax2 = fig.add_subplot(223)
ax2.scatter(a.iloc[:, 1], a.iloc[:, 2], c=Colors)
plt.show()
#数据的归一化
def normal(a):
amax = a.iloc[:, 0:3].max()
amin = a.iloc[:, 0:3].min()
anor = amax - amin
agui = (a.iloc[:, 0:3] - amin)/anor
agui1 = pd.concat([agui.iloc[:, :3], a.iloc[:, 3]], axis=1)
return agui1
#欧氏空间距离计算
def cal_dis(Xtrain, Xtest,k):
dista = list((((Xtrain.iloc[:, :-1] - Xtest)**2).sum())**0.5)
distal = pd.DataFrame({'dist': dista, 'labels': (Xtrain.iloc[:, 3])})
dr = distal.sort_values(by='dist')[: k]
re = dr.value_counts('labels')
return re.index[0]
#随机生成函数
def sui_ji(Xdata,rata=0.9):
a = int(Xdata.shape[0]*rata)
Xtrain = Xdata.iloc[:a, :]
Xtest = Xdata.iloc[a:, :]
#重置序号
Xtest.index = range(Xtest.shape[0])
return Xtrain, Xtest
#KNN计算
def data_chat(k):
oridata = field_open()
nordata = normal(oridata)
train, test = sui_ji(nordata)
print(train)
n = train.shape[1] - 1
m = test.shape[0]
result = []
#计算所有值并取前K个
for i in range(m):
dist = list((((train.iloc[:, :n] - test.iloc[i, :n]) ** 2).sum(1)) ** 5)
dist_l = pd.DataFrame({'dist': dist, 'labels': (train.iloc[:, n])})
dr = dist_l.sort_values(by='dist')[: k]
re = dr.loc[:, 'labels'].value_counts()
result.append(re.index[0])
result = pd.Series(result)
test['predict'] = result
acc = (test.iloc[:, -1] == test.iloc[:, -2]).mean()
print(f'模型预测准确率为{acc}')
return test