入门小菜鸟,希望像做笔记记录自己学的东西,也希望能帮助到同样入门的人,更希望大佬们帮忙纠错啦~侵权立删。
目录
一、算法思想
1、具体过程
给定测试样本,基于某种距离度量找到训练集中与其最靠近的k个训练样本,然后基于这k个“邻居”的信息来进行预测。
在分类任务中可使用“投票法”(即选择这k个样本中出现最多的类别标记作为预测结果);在回归任务中可使用“平均法”(即将这k个样本的实际输出标记的平均值作为预测结果);还可以基于距离远近进行平均加权或加权投票,距离越近的样本权重越大。
2、k值的选择
(1)较小的k值
“学习”的近似误差减少(即只有与输入实例较近的训练实例才会对预测结果起作用);
“学习”的估计误差增大(即预测结果会对近邻的实例点非常敏感,比如噪点,容易过拟合)
(2)较大的k值
减少“学习”的估计误差,但会增大“学习”的近似误差,k值的增大意味着整体模型变得简单。
二、算法优缺点
1、优点
- 简单易用
- 模型训练时间快(惰性算法)
- 对异常值不敏感
2、缺点
- 对内存要求较高(因为该算法存储了所有训练数据)
- 预测阶段可能很慢
- 对不相关的功能和数据规模敏感
三、k近邻法的实现——kd树
1、kd树引入原因
上述实现k近邻法的算法过程看似非常简单,但是有个比较头疼的问题:如何对训练数据进行快速k近邻搜索,尤其是在特征空间维数大和训练数据容量大的情况下。
最简单的k近邻实现方法是线性扫描(即直接计算输入实例与每个训练样本的距离),计算量大且耗时,pass。
为了提高k近邻搜索的效率,可以考虑特殊的结构存储训练数据,以减少计算距离的次数,kd树就是其中的一种。
2、构造kd树
kd树是二叉树,构造kd树相当于不断地用垂直于坐标轴的超平面将K维空间切分,构成一系列的k维超矩形区域。kd树的每个结点对应于一个k维超矩形区域。利用kd树可以省去对大部分数据点的搜索,从而减少搜索的计算量(思路有点像二分查找)。
比如说只有2维,先分成x>0和x<0,然后再分别在这两项里再细分y>0和y<0:
Note:通常选择训练实例点在选定坐标轴上的中位数为切分点,这样得到的kd树是平衡的。但平衡的kd树搜索时的效率未必是最优的。
3、搜索kd树
顺着“搜索路径”找到目标点x的最近邻的近似点(叶结点),回溯搜索路径,并判断搜索路径上的结点的其他子结点空间中是否可能有距离查询点更近的数据点,如果有可能,则需要跳到其他子结点空间中去搜索,重复这个过程直到搜索路径为空。
Note:kd树适用于训练样本数目远大于空间维数时的k近邻搜索。
四、python实现k近邻
from sklearn import datasets
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
import numpy as np
import seaborn as sns
from sklearn.neighbors import KNeighborsClassifier
iris = datasets.load_iris()# 导入鸢尾花数据集
data = iris.data[:, :2]
target = iris.target
#分出训练集和测试集
train_x,test_x,train_y,test_y = train_test_split(data, target,test_size=0.4,random_state=0)
# 训练并预测,其中选取k=15
clf = KNeighborsClassifier(15, 'distance')
clf.fit(train_x, train_y)
Z = clf.predict(test_x)
print('准确率:' ,clf.score(test_x, test_y))
colormap = dict(zip(np.unique(target), sns.color_palette()[:3]))
plt.scatter(train_x[:,0], train_x[:,1], edgecolors=[colormap[x] for x in train_y],c='', s=40, label='train_data')
plt.scatter(test_x[:,0], test_x[:,1], marker='*', color=[colormap[x] for x in Z], s=10, label='pre_data')
plt.legend()
plt.show()
result:
欢迎大家在评论区批评指正,谢谢~