注:本文基于python 2.7版本编写
kNN即为(K Nearest Neighbors)K近邻算法,属于监督学习。
kNN的算法可以简单理解为一个分类器,其大概过程如下:
- 计算待分类数据和已分类数据的距离
- 按照距离从小到大排序
- 根据用户传递的参数k,统计前k个距离中对应的各个目标分类数量,返回分类数量最多的标签
总的来说,也就是可以理解为按照距离远近,少数服从多数的概念。
下面看下代码实现:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from numpy import *
import operator
import sys
# 为了能够让系统识别中文,修改默认编码方式
if sys.getdefaultencoding() != 'utf-8':
reload(sys)
sys.setdefaultencoding('utf-8')
# 定义已分类数据集及对应标签
def createDataSet():
group = array([[1.0, 1.0], [1.1, 1.0], [0, 0], [0, 0.1]])
labels = ['A', 'A', 'B', 'B']
return group, labels
def classify(intX, dataSet, labels, k):
rowSize = dataSet.shape[0] # 计算数据集的行变量长度,即数据集个数
diffMat = dataSet - tile(intX, (rowSize, 1)) # 计算数据集和待分类数据的坐标距离,x1-x2
sqDiffMat = diffMat ** 2 # 计算距离查的平方,(x1-x2)^2
sqDis = sqDiffMat.sum(axis=1) # 计算横纵坐标平方差的和,(x1-x2)^2+(y1-y2)^2
Dis = sqDis ** 0.5 # 开根号
sortedDisIndex = Dis.argsort() # 对距离排序,不过这返回的是对应距离在数组的下标
resultLabels={}
for i in range(k): # 统计前k个距离对应的各个分类标签的数量
# 获取前k个距离对应的分类标签
# 这里之所以用数组下标是因为在已分类数据上,其下标和分类标签下标是一致的,一个点对应一个分类标签
# 所以用距离的下标就能获取对应的分类标签
vote = labels[sortedDisIndex[i]]
votecount = resultLabels.get(vote, 0) # 使用字典统计对应标签的数量
resultLabels[vote] = votecount + 1
# 将字典按照各个分类标签的数量进行从大到小排序
sortedClass = sorted(resultLabels.iteritems(), key=operator.itemgetter(1), reverse=True)
return sortedClass[0][0] # 返回标签数量最多的对应的分类标签
如果有不懂的函数,可以参看下列链接:
shape函数
tile函数
sum函数
argsort函数
get函数
iteritems函数
itemgetter
sorted函数
测试代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import mykNN
rawData=[1,1.3]
dataSet, labels = mykNN.createDataSet()
print(mykNN.classify(rawData, dataSet, labels, 3))
对于kNN算法,有两个参数是模型正确率的关键,一个自然是k,另一个是距离的定义和计算。在这里,我们使用的是欧式几何距离,不过这只适用于连续变量。除此之外还有余弦距离、汉明距离、曼哈顿距离等等。