机器学习笔记之KNN

KNN

k近邻法(k-nearest neighbor,k-NN) 是一种基本分类与回归方法。其算法如下:

这里写图片描述

K近邻模型

k近邻算法中,当训练集、距离度量、k值及分类决策规则确定之后,对于任何一个新的输入的实例,它所属的类唯一地确定。这相当于根据上述将特征空间划分为一些子空间,确定子空间的每个点所属的类。特征空间中,对每个训练实例点 xi , 距离该点比其他点更近的所有点组成一个区域,叫做单元。每个训练实例点拥有一个单元,所有训练实例点的单元构成特征空间的一个划分。最近邻法(k=1时)将实例 xi 的类 yi 作为七单元中所有点的类标记。这样每个单元实例点的类别都是确定的。
这里写图片描述

KNN三要素

距离的度量

设特征空间 是n维实数向量空间 Rn , xi,xj,xi=(x1i,,xni),xj=(x1j,,xnj) , xi,xj Lp 距离定义为:

Lp(xi,xj)=(l=1nxlixljp)1p

  • p=1 时,称为曼哈顿距离(Manhattan distance)

  • p=2 时,称为欧式距离(Euclidean distance)

  • p= 时,就是去各个坐标的最大值,即:

L(xi,xj)=maxxlixlj

用图表示如下:
这里写图片描述

k值的选择

k值较小意味着整体模型变得复杂,容易发生过拟合
k值较大相当于用较大邻域中的训练实例进行预测,较远的实例也会对预测起作用,容易使预测发生错误

分类决策规则

分类的损失函数为 0-1损失函数

误分类率为:

1kxiNk(x)I(yicj)=11kxiNk(x)I(yi=cj)

要使误分类率最小即经验最小,就要是的分类准确率最大即 1kxiNk(x)I(yi=cj) 最大,所以多数表决规则等价于经验风险最小化

kd-tree算法

输入: k维空间数据集 T
输出:kd-tree

  1. 构造根节点,根节点对应于包含 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]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值