[TOC] 更新、更全的《机器学习》的更新网站,更有python、go、数据结构与算法、爬虫、人工智能教学等着你:http://www.javashuo.com/article/p-vozphyqp-cm.htmlhtml
k近邻算法(k-nearest neighbors,KNN)是一种基本的分类和回归方法,本文只探讨分类问题中的k近邻算法,回归问题一般是得出最近的$k$个实例的标记值,而后取这$k$实例标记值的平均数或中位数。python
k近邻算法常常被人们应用于生活当中,好比傅玄曾说过“近朱者赤近墨者黑”,还有人曾说过“若是要判断一我的的品性,只须要看看他身边朋友的品性便可”,这些都是用了k近邻算法的思想。算法
本文主要介绍k近邻算法的基本理论以及k近邻的扩展——限定半径最近邻算法和最近质心算法,以后会使用k近邻算法对鸢尾花数据进行分类,并讲解scikit-learn库中k近邻算法各个参数的使用。为了解决k近邻算法须要大量计算的问题在这以后会讲解kd树(KDTree)。数据结构
不知道同窗们在看电影的时候有没有思考过你是如何判断一部电影是爱情片仍是动做片的,你能够停下来想一想这个问题再往下看看个人想法。机器学习
我说说我是如何判断一部电影是爱情片仍是动做片的,首先绝对不是靠那些预告片,毕竟预告片过短了,爱情片的预告多是动做片,动做片的预告多是爱情片也说不定。学习
相比较预告片我用了一个很愚蠢很繁琐但颇有效的方法。首先我用一部电影的接吻镜头的次数做为$x$轴,打斗的场景次数做为$y$轴生成了一个二维空间,即平面图,以下图所示。(注:如下电影的接吻镜头次数和打斗场景次数都是假设的)测试
# k近邻算法引入图例 import matplotlib.pyplot as plt from matplotlib.font_manager import FontProperties %matplotlib inline font = FontProperties(fname='/Library/Fonts/Heiti.ttc') # 动做片 plt.scatter(2, 10, marker='o', c='r', s=50) plt.text(2, 9, s='《战狼2》(2,10)', fontproperties=font, ha='center') plt.scatter(4, 12, marker='o', c='r', s=50) plt.text(4, 11, s='《复仇者联盟2》(4,12)', fontproperties=font, ha='center') plt.scatter(2, 15, marker='o', c='r', s=50) plt.text(2, 14, s='《猩球崛起》(2,15)', fontproperties=font, ha='center') # 爱情片 plt.scatter(10, 4, marker='x', c='g', s=50) plt.text(10, 3, s='《泰坦尼克号》(10,4)', fontproperties=font, ha='center') plt.scatter(12, 2, marker='x', c='g', s=50) plt.text(12, 1, s='《致咱们终将逝去的青春》(12,2)', fontproperties=font, ha='center') plt.scatter(15, 5, marker='x', c='g', s=50) plt.text(15, 4, s='《谁的青春不迷茫》(15,5)', fontproperties=font, ha='center') # 测试点 plt.scatter(5, 6, marker='s', c='k', s=50) plt.text(5, 5, s='《未知类型的电影》(5,6)', fontproperties=font, ha='center') plt.xlim(0, 18) plt.ylim(0, 18) plt.xlabel('接吻镜头(次)', fontproperties=font) plt.ylabel('打斗场景(次)', fontproperties=font) plt.title('k近邻算法引入图例', fontproperties=font, fontsize=20) plt.show()
网站
经过上图咱们能够发现动做片《战狼2》的打斗场景次数明显多于接吻镜头,而爱情片《泰坦尼克号》的接吻镜头明显多于打斗场景,而且其余的动做片和爱情片都有这样的规律,所以我作了一个总结:爱情片的接吻镜头次数会明显比打斗的场景次数多,而动做片反之。人工智能
经过上述的总结,若是我再去看一部新电影的时候,我会在内心默数这部电影的接吻镜头的次数和打斗场景,而后再去判断。这种方法看起来无懈可击,可是若是碰到了上述黑点《未知类型的电影》所在的位置,即当接吻镜头次数和打斗场景次数差很少的时候,每每很难判断它是爱情片仍是动做片。spa
这个时候咱们的主角k近邻算法就应该出场了,由于使用k近邻算法能够很好的解决《未知类型的电影》这种尴尬的情形。
上述整个过程其实就是k近邻算法实现的一个过程,接下来将从理论层面抽象的讲解k近邻算法。
k近邻算法简而言之就是给定一个有$m$个实例的数据集$T={(x_1,y_1),(x_2,y_2),\cdots,(x_m,y_m)}$,计算出将来新样本到每一个实例的距离,而后找到与将来新数据最近的$k$个实例,这$k$个实例哪一个类别的实例多,则将来新样本属于哪一个类别,基于这个解释能够给出k近邻算法的三个基本要素。
k近邻算法的三个基本要素分别是$k$值的选择、距离度量的方式和分类决策的规则,只要这三点肯定了,则k近邻算法也就肯定了。
k近邻算法对于$k$值的选择,通常没有一个固定的选择,对于不一样的问题一般可能有不一样的$k$值。可是须要注意的是若是$k$值取的越大,则离将来新样本的实例会愈来愈多,即较远的实例也会对结果形成影响,从而使得模型欠拟合,可是模型会变得简单;反之只有较少的实例会对结果形成影响,模型会变得复杂,同时会使得模型容易发生过拟合现象。而且须要注意的是$k$值通常小于20。
例如当$k$值取$m$的时候,模型会简单到不管将来新样本输入什么,预测结果都是训练集中实例最多的类。
当$k=1$的时候,称为最近邻算法,即对于将来新样本,最近邻算法将训练集中与将来新样本最邻近点的类别做为将来新样本的类别。
k近邻算法对于距离度量的方式,有不少种方法能够选择,通常选择咱们电影分类例子中讲到的欧几里得距离,也称做欧氏距离。同时还可能会使用曼哈顿距离或闵可夫斯基距离,这里统一给出它们的公式。
假设$n$维空间中有两个点$x_i$和$x_j$,其中$x_i = (x_i^{(1)},x_i^{(2)},\cdots,x_i^{(n)})$,\(x_j = (x_j^{(1)},x_j^{(2)},\cdots,x_j^{(n)})\)。
欧氏距离为
曼哈顿距离为
闵可夫斯基距离为
其中曼哈顿距离是闵可夫斯基距离$p=2$时的特例,而欧氏距离是闵可夫斯基距离$p=1$时的特例。
k近邻算法对于分类决策规则,通常选择电影分类例子中讲到的多数表决法,即$k$个实例中拥有最多实例的类别即为将来新样本的类别。例如假设获得距离《未知类型的电影》最近的$10$部电影中,有$3$部属于$c_1$类;有$3$部属于$c_2$类;有$4$部是$c_3$类,则能够判断《未知类型的电影》属于$c_3$类。
值得注意的是使用k近邻算法解决回归问题时,分类决策的规则一般是对$k$个实例的标记值取平均值或中位数。例如距离将来新样本的最近的$3$个实例的标记值分别为${2.3,2.7,1.0}\(,则能够获得将来新样本的标记值为\){\frac{2.3+2.7+1.0}{3}}=2$。
维数诅咒的意思是:当训练集特征维度愈来愈大的时候,特征空间愈来愈稀疏,经过距离度量的方式能够发现即便是最近的邻居在高维空间的距离也很远,以致于很难估计样本之间的距离。
通常状况下可使用特征选择和降维等方法避免维数诅咒。
限定半径k近邻算法顾名思义就是限定一个距离范围搜索$k$个近邻,经过限定距离范围能够解决数据集中实例太少甚至少于$k$的问题,这样就不会把距离目标点较远的实例也划入$k$个实例当中。
最近质心算法是将全部实例按照类别归类,归类后对$c_k$类的全部实例的$n$维特征的每一维特征求平均值,而后由每一维特征的平均值造成一个质心点,对于样本中的全部类别都会对应得到一个质心点。
每当将来新样本被输入时,则计算将来新样本到每个类别对应质心点的距离,距离最近的则为该将来新样本的类别。
有$m$个实例$n$维特征的数据集
其中$x_i$是实例的特征向量即$({(1)},{(2)},\cdots,^{(n)})$,$y_i$是实例的类别,数据集有${c_1,c_2,\cdots,c_j}$共$j$个类别。
将来新样本$(x_i,y_i), \quad (i=1,2,\cdots,m)$的类别$c_l, \quad (l=1,2,\cdots,j)$。
除了咱们讲的第一个古老的机器学习算法感知机,k近邻算法应该是目前工业上还会使用最为简单的算法,而且使用起来也很简单、方便,可是有个前提是数据量不能过大,更不能使用有维数诅咒的数据集。
k近邻遇到数据量大的数据集计算量是一个很难解决的问题,那么有没有什么好的方法能稍微减轻这个问题呢?有是必定有的,即下一篇——kd树。