KNN
k近邻法(k-nearest neighbor,k-NN) 是一种基本分类与回归方法。其算法如下:
K近邻模型
k近邻算法中,当训练集、距离度量、k值及分类决策规则确定之后,对于任何一个新的输入的实例,它所属的类唯一地确定。这相当于根据上述将特征空间划分为一些子空间,确定子空间的每个点所属的类。特征空间中,对每个训练实例点
KNN三要素
距离的度量
设特征空间
当
p=1 时,称为曼哈顿距离(Manhattan distance)当
p=2 时,称为欧式距离(Euclidean distance)当
p=∞ 时,就是去各个坐标的最大值,即:
用图表示如下:
k值的选择
k值较小意味着整体模型变得复杂,容易发生过拟合
k值较大相当于用较大邻域中的训练实例进行预测,较远的实例也会对预测起作用,容易使预测发生错误
分类决策规则
分类的损失函数为 0-1损失函数
误分类率为:
要使误分类率最小即经验最小,就要是的分类准确率最大即
kd-tree算法
输入: k维空间数据集
输出:kd-tree
- 构造根节点,根节点对应于包含
T 的k 维空间的超矩形区域. 选择x(1) 为坐标轴,以T 中所有实例的x(1) 坐标的中位数为切分点,将根节点对应的超矩形区域切分为两个子区域。切分由通过切分点与坐标轴x(1) 垂直的超平面实现,则左子节点对应坐标x(1) 小于切分点的子区域,右节点对应的坐标则大于切分点的子区域 - 递归的继续划分区域,直到两个子区域没有实例则停止
代码如下:
import os
class node(object):
def __init__(self,point):
self.point = point
self.left = None
self.right = None
pass
def median(data):
m = len(data)/2
return data[m], m
def build_kd_tree(data,flag):
data = sorted(data,key = lambda x: x[flag])
print(data)
p,m = median(data)
tree = node(p)
del data[m]
if (m > 0):
tree.left = build_kd_tree(data[:m],not flag)
if (len(data) > 1):
tree.right = build_kd_tree(data[m:],not flag)
return tree
if __name__ == '__main__':
T = [[2,3],[5,4],[9,6],[4,7],[8,1],[7,2]]
kd_tree = build_kd_tree(T,0)
print(kd_tree)
代码参考http://www.hankcs.com/ml/k-nearest-neighbor-method.html
搜索kd-tree
给定一个目标点,搜索其最近邻。首先找到包含目标点的叶节点;然后从该叶节点出发,一次回退到父节点;不断查找与目标节点最近邻的节点,当确定不可能存在更近的节点时终止,这样搜索就被限制在空间的局部区域上,效率大为提高。
搜索跟二叉树一样来,是一个递归的过程。先找到目标点的插入位置,然后往上走,逐步用自己到目标点的距离画个超球体,用超球体圈住的点来更新最近邻(或k最近邻)
import os
class node(object):
def __init__(self,point):
self.point = point
self.left = None
self.right = None
self.parent = None
def set_left(self,left):
if left == None:
pass
left.parent = self
self.left = left
def set_right(self,right):
if right == None:
pass
right.parent = self
self.right = right
def median(data):
m = len(data) / 2
return data[m],m
def build_kd_tree(data,flag):
data = sorted(data,key = lambda x: x[flag])
p,m = median(data)
tree = node(p)
del data[m]
if m > 0:
tree.set_left(build_kd_tree(data[:m],not flag))
if (len(data) > 1):
tree.set_right(build_kd_tree(data[m:],not flag))
return tree
def distance(x,y):
return ((x[0]-y[0]) ** 2 + (x[1] - y[1]) ** 2) **0.5
def search_kd_tree(tree,d,target):
if target[d] < tree.point[d]:
if tree.left != None:
return search_kd_tree(tree.left,not d,target)
else:
if tree.right != None:
return search_kd_tree(tree.right,not d,target)
def update_best(t,best):
if t == None:
return
t = t.point
d = distance(t,target)
if (d < best[1]):
best[1] = d
best[0] = t
best = [tree.point,100000.0]
while(tree.parent != None):
update_best(tree.parent.left,best)
update_best(tree.parent.right,best)
tree = tree.parent
return best[0]
if __name__ == '__main__':
T = [[2, 3], [5, 4], [9, 6], [4, 7], [8, 1], [7, 2]]
tree = build_kd_tree(T,0)
print(search_kd_tree(tree,0,[5,6]))
##查找[5,6]的最近邻输出结果为[4,7]