概述
近邻法的工作机制很简单:给定测试样本,基于某种距离度量找出训练集中与其最靠近的 个训练样本,然后基于这 个“邻居”的信息来进行预测。
简单地说, -近邻算法采用测量不同特征值之间的距离的方法进行分类
-近邻算法:
优点:精度高、对异常值不敏感、无数据输入假定
缺点:计算复杂度高、空间复杂度高
适用数据范围:数值型、标称型
我们来看一个例子
有人曾经统计过很多电影的打斗镜头和接吻镜头,那么我们是否可以通过这些数据判断一个未知类型的电影属于动作片还是爱情片呢?
假如我们得到的数据如下表:
电影名称 | 打斗镜头 | 接吻镜头 | 电影类型 |
---|---|---|---|
California Man | 3 | 104 | 爱情片 |
He’s Not Really into Dundes | 2 | 100 | 爱情片 |
Beautiful Women | 1 | 81 | 爱情片 |
Kevin Longblade | 101 | 10 | 动作片 |
Robo Slayer 3000 | 99 | 5 | 动作片 |
Amped II | 98 | 2 | 动作片 |
? | 10 | 90 | 未知 |
即使不知道未知电影的类型,我们也可以通过某种方法计算出来。首先计算未知电影与样本集中其他电影的距离,计算结果如下表:(此处暂时不关心如何计算的)
电影名称 | 与未知电影的距离 |
---|---|
California Man | 20.5 |
He’s Not Really into Dundes | 218.7 |
Beautiful Women | 19.2 |
Kevin Longblade | 115.3 |
Robo Slayer 3000 | 117.4 |
Amped II | 118.9 |
现在我们得到了样本集中所有电影与未知电影的距离,按照距离递增排序,可以找到 个距离最近的电影,这里 取3,则前三个最靠近,然后根据分类决策规则(多数表决)来判断未知电影的类型,这里前三个都属性爱情片,因此我们可以判定未知电影为爱情片。
通过上面的例子,我们基本知道了 -近邻法是如何进行分类的。下面我们通过具体的数据以及python代码实现。
python3实现
实现kNN分类算法的伪代码
对未知类别属性的数据集中的每个点依次执行一下操作:
(1)计算已知类别数据集中的点与当前点之间的距离
(2)按照距离递增次序排序
(3)选取与当前点距离最小的k个点
(4)确定前k个点所在类别的出现频数
(5)返回当前k个点出现频数最高的类别作为当前点的预测分类
代码:
from numpy import * # 科学计算包Numpy
import operator # 运算符模块
# 数据准备
def createDataSet():
group = array([
[1.0, 1.1],
[1.0, 1.0],
[0, 0],
[0, 0.1]
])
labels = ['A', 'A', 'B', 'B']
return group, labels
# 测试
group, labels = createDataSet()
print("训练数据:", group)
print("标签:", labels)
# k-近邻算法
def classify0(inX, dataSet, labels, k): # 输入向量,训练数据,标签,参数k
dataSetSize = dataSet.shape[0] # 数据个数
diffMat = tile(inX, (dataSetSize, 1)) - dataSet # tile函数,求输入数据与训练数据对应值的相减
sqDiffMat = diffMat ** 2 # 平方
sqDistances = sqDiffMat.sum(axis=1) # 求和
distances = sqDistances ** 0.5 # 开根号 欧氏距离
sortedDistIndicies = distances.argsort() # 返回数组值从小到大的索引
classCount = {} # 创建一个字典,用于记录每个实例对应的频数
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]] # 选择k个距离最小的点,对应标签
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 # 统计频数
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) # 排序,reverse=True降序
# python2中用iteritems
return sortedClassCount[0][0] # 返回最多的
# tile函数
a = [0, 1, 2]
b = tile(a, 2)
print(b) # [0 1 2 0 1 2]
b = tile(a, (1, 2))
print(b) # [[0 1 2 0 1 2]]
b = tile(a, (2, 1))
print(b) # [[0 1 2],[0 1 2]]
# 测试
result = classify0([1.2, 1], group, labels, 3)
print("预测标签为:", result)
测试结果1:
如何测试分类器
以上代码构造了一个简单的分类器,那么,该分类器是否符合我们的预期呢?
我们可以通过多种方法来检测分类器的正确率。为了测试分类器的效果,我们可以使用已知类别的数据(当然不告诉分类器),检验分类器给出的结果是否与已知类别相同,通过大量的测试数据,我们可以计算出分类器的错误率。
注:
这里只是简单的介绍了k-近邻算法的python实现,在实际的应用中,我们所得到的数据不会正好满足我们的计算要求,这是就需要我们进行一些数据的预处理。