sinanmu · 2020年04月22日

[易懂机器学习]KNN,k-Nearest Neighbor (k近邻算法)[分类算法]

首发:https://zhuanlan.zhihu.com/p/66360783
作者:司南牧

k- Nearest Neighbor (k个最接近的邻居)算法

任何机器学习都是假定一种数学模型可以用于当前这个数据解决问题 。而任何数学模型都有参数,其中不同数据参数的取值是不一样的。那么我们学习任何机器学习第一件事。那就是要确定它使用的是数学模型是什么。第二件事就是看这个数学模型有哪些参数需要根据数据来确定。

kNN算法到底是什么?它未知参数k到底是什么?

kNN很简单。那就是“人以类聚,物以群分”。假设,现在有一个人你不知道她什么性格。然后,为了分类出她是什么性格。你首先找她身边和她最相似的k个朋友。如果她的最相似的k个朋友,大部分都很文艺范。那么,你可以把目标对象分类为文艺青年。这就是kNN的原理。 从名字就看得出来。遍历训练集带标签的已知数据。计算所有带标签数据和新数据之间的相似度。找到前k个相似度最大的数据,看他们的分类标签出现的次数。假如这k个数据出现的分类标签次数最多的是A类,那么算法就认为新数据它是属于A类。

由于我们要找k个最相似的已知带标签的样本。那么我们怎么知道已知标签的样本和未知标签的样本之间是否相似呢?

问题来了,如何用数学量化两个样本之间的相似度?

有很多数学指标可以量化两个样本之间的相似度。最简单的,两个点他们距离越接近不就越相似嘛(两点间距离公式 )。 然后还有,两个向量他们之间夹角越小不就这两个向量方向越接近么(求两个向量之间夹角的cos函数。 )?

现在我们知道怎么量化相似度。剩下就是遇到一个新数据我想对它进行分类,那就遍历训练集带标签的已知数据。计算所有带标签数据和新数据之间的相似度。找到前k个相似度最大的数据,看他们的分类标签出现的次数。假如这k个数据出现的分类标签次数最多的是A类,那么算法就认为新数据它是属于A类。

编程实践:

from numpy import *
# 弄带标签的数据
data = array([[1.0, 1.1],[1.0, 1.0],[0,0],[0, 0.1]])
labels = ['A','A','B','B']# data各元素的类别标签

newdata = array([1.0, 0.9])
'''
:newdata 来了一个新样本数据,
现在问题是要knn根据已有的数据data和标签lables判断它属于哪个类.
'''
# 设定knn的参数。
# 只根据k个最相似的样本,统计他们的标签哪个分类出现次数最多就认为新数据属于这个类。
k = 3 

# 1. 计算已知的所有样本与新数据的相似度
    # 相似度:用两点间的距离来量化样本间的相似度.(距离越大越不相似))
    # sum()中参数axis=1,表示按行把每行所有列累加起来
distance = sqrt(sum((data-newdata)**2, axis=1))
print('各样本与新数据之间的距离为:',distance)
各样本与新数据之间的距离为: [0.2 0.1 1.3453624 1.28062485]
# 2. 找到相似度较大的前k个已知样本的下标序号

# 2.1 先把距离从小到到排序(),
#     并取出对应样本的序号(方便取他们的标签)
sorted_index = distance.argsort()
print('距离低到高对应已知样本data中的下标为:',sorted_index)

# 2.2 找对应下标的标签,并统计各标签出现次数
label_frequence = {}
for i in range(k):# 只统计前k个最相似的样本它们标签出现的次数
    tmp_index = sorted_index[i]
    tmp_label = labels[tmp_index]
    # 当前这个标签出现次数+1。
    # .get(tmp_label,0)后面那个0指的是假设当前字典{}没有这个索引就返回0
    label_frequence[tmp_label] = label_frequence.get(tmp_label,0) + 1

print('距离前k=%d小的样本对应标签出现频率:'% k,label_frequence)
距离低到高对应已知样本data中的下标为: [1 0 3 2]
距离前k=3小的样本对应标签出现频率: {'A': 2, 'B': 1}
# 3. 算法把出现频率最高的那个标签认为是新数据的所属分类
label_frequence_list = label_frequence.items() #把字典变为list
print('label_frequence变成列表后为:',label_frequence_list)
# 从高到低排序,按照label_frequence_list元素中的第2个值排序
label_frequence_sorted =sorted(label_frequence_list , key=lambda x:x[1], reverse=True)
print('新数据所属标签为',label_frequence_sorted[0][0])
label\_frequence变成列表后为: dict\_items([('A', 2), ('B', 1)])
新数据所属标签为 A

推荐阅读:


欢迎关注我的知乎专栏适合初学者的机器学习神经网络理论到实践
4 阅读 549
推荐阅读
0 条评论
关注数
4
内容数
15
理工思维科普编程、读书、AI、机器人
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
Arm中国学堂公众号
关注Arm中国学堂
实时获取免费 Arm 教学资源信息
Arm中国招聘公众号
关注Arm中国招聘
实时获取 Arm 中国职位信息