一、简介
K-Nearest-Neighbor 算法是一种常用的监督学习算法,它没有显式的训练过程,是‘懒惰学习’的显著代表,此类学习算法仅在训练阶段将训练集保存起来,训练时间开销为0,待收到测试样本后在进行处理
k近邻模型的三要素: K值选择、距离度量、分类评价规则
二、工作机制
给定测试样本,基于某种距离度量找出训练集中与其最靠近的k个训练样本,然后基于这k个‘邻居’的信息来进行预测。
在分类任务中,可使用“投票法”,即选择这k个样本中出现类别最多的标记作为预测结果;评价分类问题可以使用准确率 score
在回归任务中使用“平均法”,将这k个样本的实值输出标记的平均值作为预测结果;评价回归问题可以使用MSE(均方误差)、MAE(平均绝对值误差),需要注意,语法上y值必须是可以计算的数值类型。
最佳拟合:经验误差和泛化误差相近,泛化误差尽可能小
还可以基于距离远近进行加权平均或加权投票,距离越近,权重越大
距离度量方式:
其中p=2,就是欧氏距离
p=1,就是曼哈顿距离
三、算法实现
K近邻算法的实现最简单的方法是线性扫描,该方法要计算待预测样本与每一个训练实例的距离,当训练集很大时,计算非常耗时,显然这种方法不太可行。故引入kd树
如果实例点是随机分布的,kd树更适用于训练样本数远大于空间维数时的k近邻搜索。当空间维数接近训练实例数时。它的效率会迅速下降,几乎接近线性扫描。
3.1 KD树
Kd-树是K-dimension tree的缩写,是对数据点在k维空间(如二维(x,y),三维(x,y,z),k维(x1,y,z…))中划分的一种数据结构,主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索)。本质上说,Kd-树就是一种平衡二叉树。
构造KD树相当于不断用垂直于坐标轴的超平面将K维空间进行切分,构成一系列的K维超矩形区域,直至子区域没有节点。KD树中的每一个节点对应于一个k维超矩形区域。
通常选择训练实例点再选定坐标轴上的中位数为切分点,这样得到平衡KD树,但平衡KD树不一定就是搜索效率最优的。
3.2 KD树搜索过程
①、在kd树中找出包含目标点的x的叶结点:从根结点出发,递归地向下访问kd树。若目标点x当前维的坐标小于切分点的坐标,则移动到左子结点,否则移动到右子结点。直到子结点为叶结点为止。
②、以此叶结点为“当前最近点”。
③、递归地向上回退,在每个结点进行以下操作:
(a)如果该结点保存的实例点比当前最近点距离目标点更近,则以该实例点为“当前最近点”。
(b)当前最近点一定存在于该节点的一个子结点对应的区域。检查该子结点的父结点的另一子结点对应的区域是否有更近的点。具体地,检查另一子结点对应的区域是否与以目标点为球心、以目标点与“当前最近点的距离为半径的超球体相交。如果相交,可能在另一个子结点对应的区域内存在距离目标点更近的点,移动到另一个子结点。接着,递归地进行最近邻搜索;如果不相交,向上回退。
④、当回退到根结点是,搜索结束,最后的“当前最近点”即为x的最近邻点。
四、简单应用
一般用于小样本集的数据模型,K不能为样本集的容量,K值不能为偶数。K的(经验)取值上限为sqrt(样本容量)
3.1 自定义数据集进行KNN预测(分类)
film:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
# 导入我们自己构建的伪数据集
film = pd.read_excel('C:/Users/Administrator/Desktop/films.xlsx')
# 获取特征向量集合,和标签集合
y = film['类别'].copy()
X = film[['动作镜头','爱情镜头']].copy()
# 生成一组待预测样本
X_test = np.array([[11,6],[5,17]])
# 取X中的数值
X.values
# 绘制样本集在特征空间中的分布状况
plt.figure(figsize=(8,5))
plt.scatter(X['动作镜头'],X['爱情镜头'],s=100,c=y.map({
'动作':0,
'爱情':1
}),cmap=plt.cm.winter)
plt.legend([])
# 显示中文
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 给空间样本点添加图例描述,因为散点图不支持在绘图时添加图例
action = X.loc[y=='动作']
love = X.loc[y=='爱情']
s = 100
plt.scatter(action['动作镜头'],action['