k-近邻算法(k-Nearest Neighbor,简称kNN),工作原理:
存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系.
输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似的数据(最近邻)的分类标签.一般来说,只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数.
最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类.
算法实现
创建一个kNN.py文件
1 | from numpy import * |
上面的程序使用了欧式距离公式,计算两个n维向量A和B之间的距离:
$$d=\sqrt{\sum_{i=1}^n{(A_i- B_i)^2}}$$
例如,点(2,1,5)和(1,2,3)之间的距离计算为:
$$d=\sqrt{(2-1)^2+(1-2)^2+(5-3)^2}$$
测试算法
已知6部电影的打斗镜头,接吻镜头及其类型(模拟的数据),判断一部已知打斗镜头和接吻镜头数的新电影,它的类型是动作片,还是爱情片,具体数据如下:
电影名称 | 打斗镜头 | 接吻镜头 | 电影类型 |
---|---|---|---|
小时代 | 0 | 50 | 爱情片 |
鬼吹灯之寻龙诀 | 100 | 15 | 动作片 |
战狼 | 150 | 5 | 动作片 |
让子弹飞 | 80 | 2 | 动作片 |
左耳 | 6 | 50 | 爱情片 |
心花路放 | 5 | 40 | 爱情片 |
? | 18 | 90 | 待定 |
我们当然可以一眼看出来,这部新电影应该是爱情片,但是,如何让程序自动预测它的类别呢?
创建一个test.py,代码如下:
1 | import kNN |
输出结果:
1 | 爱情片 |
可以看到,kNN算法确实准确的预测了新电影的分类.
算法改进
欧式距离中,数字差值越大的属性对计算结果的影响也越大.若想消除这种影响,使各属性权重相等,可以将数值归一化,如将取值范围处理为0到1,或者-1到1之间.
下面的公式可以将任意取值范围的特征值转化为0到1区间内的值:
$$newValue = \frac{oldValue-min}{max-min}$$
其中,min和max分别是数据集中某一特征(属性)的最小值和最大值
在kNN.py中新增如下代码:
1 | def autoNorm(dataSet): |
接着修改classify()函数
1 | def classify(inputData,dataSet,labels,k): |