一.算法描述
该算法的思想是:一个样本与数据集中的k个样本最相似,如果这k个样本中的大多数属于某一个类别,则该样本也属于这个类别。
我以电影分类为例,描述该算法:
1.准备好电影分类数据集
上面数据集中序号1-13为已知的电影分类,分为喜剧片、动作片、爱情片三个种类,使用的特征值分别为搞笑镜头、打斗镜头、拥抱镜头的数量。那么有一部新电影《碟中谍6》,用KNN算法求它属于上述3个电影分类中的哪个类型。
2.使用Python的字典dict构造数据集
3.计算新样本与数据集中所有数据的距离
这里的新样本就是:“碟中谍6”: [21, 10, 118, “?片”]。距离计算方法采用欧式距离:
求新样本与数据集中所有数据的距离代码:
4.按照距离大小进行递增排序并选取距离最小的k个样本
5.确定前k个样本所在类别出现的频率,并输出频率最高的类别
二.流程图
三、源代码
import math
#使用字典构造数据集
train_data = {"无问西东": [1, 101, 10, "爱情片"],
"红海行动": [1, 17, 60, "动作片"],
"鼠胆英雄": [98, 29, 43, "喜剧片"],
"捉妖记2": [78, 19, 68, "喜剧片"],
"扫毒2": [5, 10, 45, "动作片"],
"复仇者联盟4": [9, 23, 98, "动作片"],
"追龙2": [1, 6, 20, "动作片"],
"唐人街探案2": [23, 3, 17, "喜剧片"],
"海王": [3, 45, 108, "动作片"],
"西虹市首富": [46, 23, 9, "喜剧片"],
"前任3": [12, 98, 20, "爱情片"],
"美人鱼": [28, 65, 20, "爱情片"],
"最好的我们":[20,110,8,"爱情片"]}
#求新样本x与数据集中所有数据的距离
test_data = [21, 10, 118]#测试集
KNN = []
for key, v in movie_data.items():
d = math.sqrt((test_data[0] - v[0]) ** 2 + (test_data[1] - v[1]) ** 2 + (test_data[2] - v[2]) ** 2)
KNN.append([key, round(d, 2)])
KNN.sort(key=lambda dis: dis[1]) #按照距离大小进行递增排序
KNN=KNN[:7] #选取距离最小的k个样本 k=7
#确定前k个样本所在类别出现的频率,并输出出现频率最高的类别
labels = {"喜剧片":0,"动作片":0,"爱情片":0}
for s in KNN:
label = movie_data[s[0]]#取出训练集的样本
labels[label[3]] += 1#确定出现的次数
labels =sorted(labels.items(),key=lambda l :l[1],reverse=True)
print(labels, labels[0][0], sep='\n')
四、总结
1.KNN属于惰性学习
KNN没有显式的训练阶段,数据集事先已经有了分类和特征值,待收到新样本后直接进行处理。
2.k取不同值时,分类结果可能会有显著不同
3.KNN的计算复杂度较高
新样本需要与数据集中每个数据进行距离计算,计算复杂度和数据集中的数据数目n成正比。
在写该算法时参考了CSDN上其他前辈的笔记