分类方法:KNN算法的全面解析

分类方法:KNN算法的全面解析

原文链接:http://kakazai.cn/index.php/Kaka/Jqxx/query/id/8

一、孟母三迁与KNN

“昔孟母,择邻处”----《三字经》

孟母三迁是为了给孩子更好的成长环境,因为她明白居住地的环境会深深地影响着孩子的成长。无独有偶,KNN算法也认为,一个样本点的类别是由多个离它最近的样本点的类别所投票决定的。

我们可以用KNN算法描述孟母是否搬迁。假设在一个居住地中有10个小朋友跟孟母的儿子玩耍,关系最亲近。如果其中有8个是淘气的,只有2个懂礼貌,那么孟母的儿子极容易受到淘气孩子的影响,也变得淘气,所以要搬迁。反过来,如果只有2个是淘气的,剩余8个都是懂礼貌的,那么孟母的儿子很可能也会变得更有礼貌,可以留下来。

近朱者赤,近墨者黑,一个人最亲近环境中最主要的力量就塑造了这个人。这也是KNN想告诉我们的。

二、别名

K-近邻算法

k-nearest neighbor classification

三、历史

KNN最早是由Cover和Hart在1968年提出最初的邻近算法。

四、算法

(1)核心思想

给定数据集,其中所有样本点都已被标注类别。新来一个样本点,为了预测它的类别,找出离它最近的k个点,统计这k个点的类别,若类别a包含样本点数目最多,那么预测新样本点的类别是a。

KNN属于有监督算法,因为它的数据集有标签。它也是一种分类(classification)方法,能预测未知样本点的类别。它还属于懒惰学习(lazy learning),因为它不预先对训练集进行任何处理,只在预测未知样本点的时候才进行归类。

(2)算法描述

S1	算距离
	给定未知样本点A,计算它与训练集中的每个样本点的距离
S2	找邻居
	将S1计算好的距离升序排列,取前k个最近的样本点作为A的邻居
S3	确定分类
	这k个邻居中,包含邻居数最多的类别作为A的类别

1)k的选择

k太小的话,会被噪音点所影响。而k太大的话,会让邻居中包含许多别的类别的样本点。选择合适的k对算法的性能影响很大。

2)距离

距离的度量要能衡量样本点的相似性。对文本分类来说,余弦距离比欧几里得距离更能衡量样本的相似性。而当维度很高时,欧几里得距离的计算会成为问题。

(3)时间复杂度分析

假设数据集的样本点个数是n,每个样本点的维度是d,距离度量采用欧几里得距离。也可以采取其他距离度量方式。

第一步:要计算A与n个样本点的距离,其复杂度是O(nd)。

第二步:要将计算好的距离排序,其复杂度至少是O(nlogn)。

第三步:统计k个邻居的类别,并找出最大的类别,其复杂度至少是O(k)。

总的时间复杂度是O(nd)+O(nlogn)+O(k)。而k和n相比可能非常小,可以忽略不计。

所以,判断一个样本点的类别的时间复杂度是O(nlogn)。

以上的分析是已经假设了用暴力搜索brute-force法找出k个邻居。在小型数据集上,brute-force很有竞争力,然而随着样本数的增长,brute-force变得不可行。

为了解决brute-force方法计算效率低下,发明了各种基于树的数据结构,如BallTree,KDTree。这些结构通过有效编码汇总样本距离信息,来减少所需的距离计算量。其基本思想是,如果A远离B,而C接近B,那么A远离C,不用明确计算。

(1)Brute force 时间复杂度 O(nd)

(2)BallTree 时间复杂度 O(dlogn)

(3)当d<20时,KDTree的时间复杂度是 O(dlogn);当d>=20时,时间复杂度是 O(dn)

在样本数小于30的情况下,Brute force比BallTree和KDTree高效。

(4)算法的优缺点分析

优点:(1)对异常值和噪音有较高的容忍度。因为某个样本点的类别是由k个邻居共同决定的,即使有其中一个邻居是噪音或者异常值,可能也不会影响该样本点的类别。

缺点:(1)计算量大,对内存需求大。因为预测每个样本点,都需要算出它跟其他所有样本点的距离。

五、算法的变种

KNN有一些变种,主要集中在K个邻居上。

(1)增加邻居的权重

默认情况下,k个邻居都是同样的权重,即都同样重要。但有些情况中,距离越近的邻居明显影响越大,因此可以给邻居们赋予距离权重,距离越近,影响越大,权重越大。也可以根据实际情况,自行指定每一个邻居的权重。

(2)用一定半径范围内的点取代k个邻居

有些情况中,对某个样本点A的影响不一定是最近的k个邻居,而是方圆xx里的邻居都会影响A。因此,以A为中心,设定半径r,在该半径范围内的所有的点都是A的邻居。

也有些情况中,样本点的分布不均匀。有的样本点周围很密集,它的k个邻居都离它很近。而有的样本点周围很稀疏,邻居们离它很远。如果还假设距离近才会有影响,那么就不应该再设定样本点被k个邻居影响,而应该是样本点被一定范围内的邻居影响。

这个算法已经在scikit-learn中RadiusNeighborsClassifier中实现。

六、KNN在sklearn中的实现

核心函数KNeighborsClassifier()

sklearn中已经实现了KNN算法,其模型函数是KNeighborsClassifier()


#函数中的参数值皆为默认值
sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, weights=’uniform’, algorithm=’auto’, leaf_size=30,p=2, metric=’minkowski’, metric_params=None, n_jobs=1, **kwargs)

参数说明

(1)n_neighbors			int型参数;knn算法中指定以最近的几个最近邻样本具有投票权。
(2)weights				str参数;即每个拥有投票权的样本是按什么比重投票,'uniform'表示等比重投
                         票,'distance'表示按距离反比投票,[callable]表示自己定义的一个函数,这个函数接收一
                         个距离数组,返回一个权值数组。
                         
(3)algorithm='auto'     str参数;即内部采用什么算法实现,['auto', 'ball_tree', 'kd_tree', 'brute']。
                         'brute':暴力搜索;默认'auto':自动根据数据选择合适的算法。一般低维数据用kd_tree速度
                         快,用ball_tree相对较慢。超过20维的高维数据用kd_tree效果不佳,而ball_tree效果好。
                         
(4)leaf_size            int参数;基于以上介绍的算法,此参数给出了kd_tree或者ball_tree叶节点规模,叶节点的
                         不同规模会影响数的构造和搜索速度,同样会影响储树的内存的大小。     
                         
(5)matric				str参数或者距离度量对象;即怎样度量距离。默认是闵氏距离minkowski。
(6)p					int参数;就是以上闵氏距离各种不同的距离参数,默认为2,即欧氏距离。p=1代表曼哈顿距离等
(7)metric_params        距离度量函数的额外关键字参数,一般不用管,默认为None。
(8)n_jobs				int参数;指并行计算的线程数量,默认为1表示一个线程,为-1的话表示为CPU的内核数,也可指定为其他数量的线程。                                

找出最邻近的邻居:kneighbors()

#找出样本点A的最近邻居
kneighbors(X=None,n_neighbors=None,return_distance=True)        

返回值说明

返回邻居们在训练集中的序号

参数说明

X					样本点A
n_neighbors			A的最近邻居数目
return_distance		是否返回具体的距离值,True=返回,False=不返回

七、代码案例

简单应用

#生成数据集
from sklearn.datasets.samples_generator import make_blobs
import numpy as np
c = np.array([[-2,2],[2,2],[0,4]])   #生成3个中心点,类型为array
#共生成60个样本点,每个样本点2个特征,共3个类别,各个类别的标准差是0.6;返回样本点及其对应的类别
x, y = make_blobs(n_samples=60, n_features=2,centers = c, random_state=0, cluster_std=0.60)

#可视化该数据集
import matplotlib.pyplot as plt
plt.scatter(x[:,0],x[:,1],c=y)  #x的第0列绘制在横坐标,x的第1列绘制在纵坐标,每个样本点的颜色跟类别有关,类别不同颜色不同
plt.scatter(c[:,0],c[:,1],marker='^',c='red')    #绘制中心点,形状是三角形,颜色是红色
plt.show()  #显示该图

#训练模型
from sklearn.neighbors import KNeighborsClassifier
k=5
model = KNeighborsClassifier(n_neighbors=k) #设置最近5个点具有投票权
model.fit(x,y)  #用数据集(x,y)训练模型

#进行预测
x_sample = np.array([[0,2]])    #待预测的样本点集[[0,2]],要转化为array类型
y_sample = model.predict(x_sample)  #预测结果
neighbors = model.kneighbors(x_sample, return_distance=False)   #返回x_sample的最近邻k个邻居的序号,不返回它们到x_sample的距离

#把待预测样本和它最近的k个点标记出来
plt.scatter(x[:,0],x[:,1],c=y,s=100)  #样本,每个样本点的像素是100
plt.scatter(c[:,0],c[:,1],marker='^',c='red',s=100)    #中心点
plt.scatter(x_sample[:,0],x_sample[:,1],marker='x',c=y_sample)    #待预测点

#画出预测点与它的k个邻居
for i in neighbors[0]:
    plt.plot([x[i][0],x_sample[0][0]],[x[i][1],x_sample[0][1]],'k--',linewidth=0.6)
plt.show()

八、应用领域

(1)分类问题

比如将 20 万张猫的图片和 20 万张狗的图片,输入到计算机让它学习,每一张都不要重复。 训练成功后,你就可以随意选一张图片,让它识别,它就会在它储存 40 万张照片中,判断与它储存的形状最接近的一个。

(2)回归问题

KNN 算法还可以回归。 通过找出待预测样本点的几个近邻,求出这些近邻的平均值,将这个平均值赋给待预测样本点,就可以知道这个待预测样本点的属性值。

参考

https://www.cnblogs.com/xiaotan-code/p/6680438.html 基于scikit-learn包实现机器学习之KNN(K近邻)-完整示例

https://blog.csdn.net/loveliuzz/article/details/77943054 机器学习——最邻近规则分类(K Nearest Neighbor)KNN算法

https://blog.csdn.net/lovego123/article/details/67638789 最近邻检索(Nearest Neighbor Search)的简单综述

https://blog.csdn.net/qq_36330643/article/details/77532161 KNN(k-nearest neighbor的缩写)最近邻算法原理详解

https://blog.csdn.net/skyline0623/article/details/8154911 【机器学习】K-means聚类算法初探

https://www.jianshu.com/p/778d39132d66 scikit-learn–Nearest Neighbors(最近邻)

KNN 算法综述 窦小凡(吉林高新区万信培训学校,吉林省 吉林市 132000)

https://blog.csdn.net/u010986080/article/details/78670378

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值