Knn(k-nearestNeighbor)算法是一种基本的分类与回归的方法。是最简单易懂的机械学习算法,没有之一。
概括性的一句话就是:近朱者赤近墨者黑。
knn的应用场景大多在,字符识别,文本分类,以及图像识别当中。
该算法的核心意思即是:一个样本在数据集中于其他的K个样本相似,而其他的样本属于一类,那么这个样本也属于这个类别。
下面我们用实例分析一下:
序号 |
电影名称 |
搞笑镜头 |
拥抱镜头 |
打斗镜头 |
电影类型 |
1. |
宝贝当家 |
45 |
2 |
9 |
喜剧片 |
2. |
美人鱼 |
21 |
17 |
5 |
喜剧片 |
3. |
澳门风云3 |
54 |
9 |
11 |
喜剧片 |
4. |
功夫熊猫3 |
39 |
0 |
31 |
喜剧片 |
5. |
谍影重重 |
5 |
2 |
57 |
动作片 |
6. |
叶问3 |
3 |
2 |
65 |
动作片 |
7. |
伦敦陷落 |
2 |
3 |
55 |
动作片 |
8. |
我的特工爷爷 |
6 |
4 |
21 |
动作片 |
9. |
奔爱 |
7 |
46 |
4 |
爱情片 |
10. |
夜孔雀 |
9 |
39 |
8 |
爱情片 |
11. |
代理情人 |
9 |
38 |
2 |
爱情片 |
12. |
新步步惊心 |
8 |
34 |
17 |
爱情片 |
13. |
唐人街探案 |
23 |
3 |
17 |
? |
我们首先简单的构思一下:上面的13部影片中,其中1-4部中的搞笑镜头占每部戏全部镜头成分的比重较大,所以我们给他们划分到喜剧片的类别;5-8部片中打斗镜头居多,所以我们给划分为动作片;9-12 接吻镜头居多,我们就给分为爱情片。那没第13步呢?我们可以看出,搞笑镜头居多,所以也可以分为喜剧片。
这是我们的一种思维方式的判断,还有另一种方式可以解决我们的问题;
利用欧式距离公式我们来寻找新片所接近的影片类型。
这个欧式距离公式可以计算样本数据与所有样本的距离。
例如:x样本就是我们的新片,那么数据就为[23,3,17] 设y为样本中的夜孔雀:[9,39,8,"爱情片"]
则我们计算就是d=(23−9)2+(3−39)2+(17−8)2 这样我们就能计算出“夜孔雀 ” 和我们所要判断的新片的距离 ,同理将其他数据样本也用公式计算出来,最后 我们分析出距离新片最近的几个影片中,那类的影片概率颇高,我们就能根据这个数据进行判断。
下面我们来构建代码,理解代码表达我们的算法:
#首先我们需要导入我们需要的库,这里面我们使用numpy库居多。
import numpy as np
#其次,我们需要将我们收集到的数据建立成我们可以使用的数集。
#这里,因为数据量小我们可以手动输入,也可以通过读取数据的函数进行操作。
dian_ying_set = {"宝贝当家": [45, 2, 9, "喜剧片"],
"美人鱼": [21, 17, 5, "喜剧片"],
"澳门风云3": [54, 9, 11, "喜剧片"],
"功夫熊猫3": [39, 0, 31, "喜剧片"],
"谍影重重": [5, 2, 57, "动作片"],
"叶问3": [3, 2, 65, "动作片"],
"伦敦陷落": [2, 3, 55, "动作片"],
"我的特工爷爷": [6, 4, 21, "动作片"],
"奔爱": [7, 46, 4, "爱情片"],
"夜孔雀": [9, 39, 8, "爱情片"],
"代理情人": [9, 38, 2, "爱情片"],
"新步步惊心": [8, 34, 17, "爱情片"]}
#由于我们要计算的新片:唐人街探案[23, 3, 17, "?片"] 就可以使用欧式距离公式来计算。欧式距离是一个最简单也是最常用的距离计算公式,
#这其中,我们可以定义三个镜头的数据为参数,求距离新片的距离最近的影片,就可以确定新片的类别了。
x = [23,3,17]
KNN = []
for key, v in dian_ying_set.items():
d = float(np.sqrt((x[0]- v[0])**2 + (x[1]- v[1])**2 + (x[2]-v[2])**2))
KNN.append([key,round(d,2)])
print(KNN)
第三步:按照距离大小进行递增排序。
KNN.sort(key=lambda dis:dis[1])
第四步:选取距离最小的k个样本。
这里取k=5;
KNN = KNN[:5]
print(KNN)
第五步:确定前k个样本所在类别出现的频率,并输出出现频率最高的类别。
labels = {"喜剧片":0,"动作片":0,"爱情片":0}
for s in KNN:
label = dian_ying_set[s[0]]
labels[label[3]] += 1
labels =sorted(labels.items(),key=lambda l: l[1],reverse=True)
print(labels,labels[0][0],sep='\n')
分析KNN的特点:
1.通过上面的例子我们可以发现 KNN 是属于惰性学习的。
这是与急切学习(eager learning)相对应的,因为KNN没有显式的学习过程!也就是说没有训练阶段,从上面的例子就可以看出,数据集事先已有了分类和特征值,待收到新样本后直接进行处理。
2.KNN的计算复杂度较高
我们从上面的例子可以看到,新样本需要与数据集中每个数据进行距离计算,计算复杂度和数据集中的数据数目n成正比,也就是说,KNN的时间复杂度为O(n),因此KNN一般适用于样本数较少的数据集。
3.k取不同值时,分类结果可能会有显著不同。
上例中,如果k取值为k=1,那么分类就是动作片,而不是喜剧片。一般k的取值不超过20,上限是n的开方。