机器学习基础篇(六)——KNN
一、简介
K-Nearest Neighbors(KNN) 是机器学习中的一个基础分类算法。
1.工作原理
- 首先我们需要一个训练样本集,并且样本集中每个数据都存在标签。存在标签就代表我们知道样本集中每一个数据与所属分类对应的关系。
- 输入没有标签的数据后,将新数据中的每个特征与样本集中数据对应的特征进行比较。
- 提取出样本集中特征最相似数据(最近邻)的分类标签,作为该数据的标签。
- 一般情况下,我们只选择样本集中前K个最相似的数据,作为新数据分类的参考。K一般是一个小于20的整数,我们会选择这K个数据中出现次数最多的分类标签作为新输入数据的标签。
可以发现,KNN算法实质是一种“懒惰算法”,不需要对训练集进行训练,只需要将新数据与原始数据做出对比即可。
2.举例
K值的不同会对结果有什么影响呢?
- 绿色的正方形和蓝色的的六边形是我们的训练数据点,而红色的星星则是我们需要分类的数据。
- 那么我们应该把红色的星星分到哪一类呢?
- 假如我们让K = 3, 那么我们会发现,在离红色星星最近的三个数据点中:有两个蓝色的六边形,一个绿色的正方形。
- 所以按照KNN算法,我们应该把红星分到蓝色这一组。
- 假如我们让K = 5, 那么我们会发现,在离红色星星最近的五个数据点中:有两个蓝色的六边形,三个绿色的正方形。
- 所以按照KNN算法,我们应该把红星分到绿这一组。
显然我们可以发现,KNN算法中,K的值对于最终的结果十分重要。
二、具体方法
1.穷举法(force method)
既然要根据预测数据点的最近邻居点做预测,那么我们只要计算预测数据点与训练集中所有样本的欧氏距离。然后计算出最小的K个距离,再对这K个数据集的标签进行多数表决即可。 这个方法简单而又直接,在样本量少,样本特征少的时候很有效。
欧式距离(Euclidean distance):连接两个点的线段的长度。对两个N维的向量X、Y,欧式距离定义如下:
但是,当样本量很多,样本特征也很多的时候,此方法需要的时间很多。在这种情况下,穷举法的性能很低,效率也成问题。
针对这种情况,我们可以考虑另外一种方法:KD树法。☟
2.K-D tree method(K-D树法)
KD树是一个二叉树,表示对K维空间的一个划分,可以进行快速检索(这样在KNN中就不需要对全样本进行距离的计算了)
以下是KD树的算法原理详解,有兴趣的同学可以研读一下,不过不了解原理也不影响KNN算法的使用,在sklearn中都已经封装好了。大家可以自行阅读或跳过,跳过不影响后续知识点的学习
我们以二维平面的数据集为例,来看下KD树算法的实现逻辑。
- 首先,在二维平面中有以下几个测试点(2,3),(5,4),(9,6),(4,7),(8,1),(7,2),预测点为(2,4.5)。
- 我们想要知道这六个点离预测点最近的那个点是什么,有两种方法。
- 穷举法
- KD树算法 - 我们需要建立一个KD树。
- 因为我们的维度只有两个,首先我们按照X轴分割数据,点集合在x维从小到大排序为(2,3),(4,7),(5,4),(7,2),(8,1),(9,6)。
- 所以我们按照(7,2)分割数据,(2,3),(4,7),(5,4)挂在(7,2)节点的左子树,(8,1),(9,6)挂在(7,2)节点的右子树。
- 然后我们按照Y轴去分割数据。
- (2,3),(4,7),(5,4)这三个点集在Y轴排序为(2,3),(5,4),(4,7)。
- 所以我们按照(5,4)来分割数据,左子树是(2,3),右子树为(4,7)。
- (8,1),(9,6)这两个点集在Y轴排序就是(8,1),(9,6)。
- 所以我们按照(9,6)来分割数据,左子树为(8,1),无右子树。
- 再然后我们按照X轴去分割数据,无法继续分割。
- 最终得到KD树图如下:
- 分别按照我们的分割点,划分整个数据集,结果如下:
- 那么给定一个预测点(2,4.5),我们如何才能知道它离哪个点的距离最近呢?
- 根据分枝树,我们可以找到离(2,4.5)最近的节点为(4,7)。
- 计算出预测点和最近节点的距离为3.202。
- 此时,需要进行一次回溯,即回溯预测点与上一个节点的距离是否更小
- 从(4,7)回溯到(5,4),计算预测点与其的距离为3.041,小于3.202。
- 所以“当前最近邻点”变成(5,4)。
- 以目标点(2,4.5)为圆心,以目标点(2,4.5)到最近节点(5,4)的距离(即3.041)为半径作圆,如上图所示。
- 可见该圆和y = 4超相交,所以需要进入(5,4)左子树进行查找。
- 回溯至(2,3)叶子节点(2,3)距离(2,4.5)的距离为1.5<3.041
- 所以最近节点更新为(2,3),最近距离更新为1.5,回溯至(7,2)。
- 以(2,4.5)为圆心1.5为半径作圆,并不和x = 7相交如下图所示。
- 至此,搜索路径回溯完。
- 返回最近节点(2,3),最近距离1.5。
三、K的选择
K的选择通常取决于数据集的实际情况。
k太小 分类结果易受噪声点影响,模型过于复杂会发生过拟合,忽略数据的真实分布;
k太大 模型将过于简单,会忽略训练数据实例中的大量有用信息。
k值通常是采用交叉检验来确定(以k=1为基准)
经验规则:k一般低于训练样本数的平方根
四、代码实现
# KNN
import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_breast_cancer
#导入乳腺癌数据集
dataCancer=load_breast_cancer()
# data是乳腺癌数据集的特征,这里选择的是前两列特征,一共有三十列特征,可以任意选择
data=dataCancer.data[:,0:2]
target=dataCancer.target
# 创建模型
# k值就是n_neighbors的值,可以随意选择合适的值,改变n_neighbors的值将获得不同的边界线;可以选择的建模方法{auto,ball_tree,kd_tree,brute}
model=KNeighborsClassifier(n_neighbors=3,algorithm='auto')
# 使用模型去训练数据
model.fit(data,target)
# 将训练数据绘制成散点图
plt.scatter(data[:,0],data[:,1],c=target,s=30,cmap=plt.cm.prism)
axis=plt.gca()
x_limit=axis.get_xlim()
y_limit=axis.get_xlim()
# 绘制边界线的图
x=np.linspace(x_limit[0],x_limit[1])
y=np.linspace(y_limit[0],y_limit[1])
X,Y=np.meshgrid(x,y)
xy=np.c_[X.ravel(),Y.ravel()]
# 用模型进行分类器的预测
boundary=model.predict(xy)
boundary=boundary.reshape(X.shape)
# 绘制边界线
axis.contour(X,Y,boundary,colors='k')
plt.show()
运行结果
五、小结
- KNN的不同的方法值影响模型的性能,并不影响最终结果
- 穷举法适用于数据集量比较小的情况
- KD树算法更适用于数量级比较大的情况
- sklearn可以根据数据的量级来自由的选择不同的算法建模
- K值的不同决定了最终结果差别很大,所以K值的选择很重要
- 尽可能的选择一个较小的K值**
自学自用,希望可以和大家积极沟通交流,小伙伴们加油鸭,如有错误还请指正,不喜勿喷,喜欢的小伙伴帮忙点个赞支持,蟹蟹呀