### 一、KNN算法描述
KNN(K-nearest neighbor algorithm),也就是K近邻算法,顾名思义,可以形象的理解为求K个最近的邻居。当K=1时,KNN算法就成了最近邻算法,即寻找最近的那个邻居。
所谓K近邻算法,就是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例(就是上面提到的K个邻居),如果这K个实例的多数属于某个类,就将该输入实例分类到这个类中,如下图所示。
![](https://box.kancloud.cn/2016-02-25_56ceab8276adf.jpg)
在上图中,有两类不同的样本数据,分别用正方形和三角形表示,而图正中间的那个圆标示的数据则是待分类的数据。换句话说就是,我们不知道中间那个圆标示的数据是从属于哪一类(是正方形还是三角形)?下面我们就要解决这个问题:给这个圆分类。
我们常说“物以类聚,人以群分”。判别一个人是一个什么样品质特征的人常常可以从他身边的朋友入手,所谓“观其友,而识其人”。要判别上图中那个圆是属于哪一类数据?好,从它的邻居下手。但是一次看多少个邻居呢?
从图中还能看出:如果K=3,圆的最近的3个邻居是2个三角形和1个正方形,少数从属于多数,基于统计的方法,判定圆标示的这个待分类数据属于三角形一类。但是如果K=5,圆的最近的5个邻居是2个三角形和3个正方形,还是少数从属于多数,判定圆标示的这个待分类数据属于正方形这一类。
由此我们可以看到,当无法判定当前待分类数据从属于已知分类中的哪一类时,可以看它所处的位置特征,衡量它周围邻居的权重,而把它归为权重更大的一类,这就是K近邻算法分类的核心思想。
### 二、Python代码实现
算法步骤:
(1)计算已知类别数据集中的点与当前点之间的距离;
(2)按照距离递增依次排序;
(3)选取与当前点距离最小的K个点;
(4)确定前k个点所在类别的出现频率;
(5)返回前k个点出现频率最高的类别作为当前点的预测分类
~~~
kNN: k Nearest Neighbors
Input: inX: vector to compare to existing dataset (1xN)
dataSet: size m data set of known vectors (NxM)
labels: data set labels (1xM vector)
k: number of neighbors to use for comparison (should be an odd number)
Output: the most popular class label
from numpy import *
import operator
from os import listdir
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = tile(inX, (dataSetSize,1)) - dataSet #将inX重复成dataSetSize行1列,tile(A,n),功能是将数组A重复n次,构成一个新的数组
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1) #sum(axis=1)就是将矩阵的每一行向量相加
distances = sqDistances**0.5
sortedDistIndicies = distances.argsort() #argsort()得到的是排序后数据原来位置的下标
classCount={}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]#确定前k个距离最小元素所在的主要分类labels
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
#计算各个元素标签的出现次数(频率),当voteIlabel在classCount中时,classCount.get()返回1,否则返回0
#operator.itemgetter(1)表示按照第二个元素的次序对元组进行排序,reverse=True表示为逆序排序,即从大到小排序
sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0] #最后返回发生频率最高的元素标签
~~~
新建一个kNN.py文件,将上面的KNN的核心代码加到里面,同时加入创建数据集函数createDataSet():
~~~
#创建数据集和标签
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
~~~
K-近邻算法:带有四个数据点的简单例子
![](https://box.kancloud.cn/2016-02-25_56ceab8286c3b.jpg)
![](https://box.kancloud.cn/2016-02-25_56ceab82a21eb.jpg)
上图的实现代码是Matlab实现的,因为是Python新手,绘制带标签A,B的图还不会,所以只要用强大的Matlab来实现了。
~~~
x=[1,1,0,0];
y=[1.1,1,0,0.1];
L={'A','A','B','B'}; %4个标注
plot(x,y,'.'); %画4个点
axis([-0.2 1.2 -0.2 1.2])
for ii=1:4
text(x(ii)+0.01,y(ii)+0.01,L{ii}); %利用4个点的坐标添加对应标注
%适当增加一些距离,让文字和点分开会美观一些
end
figure(gcf);
~~~
预测数据所在分类的测试:
~~~
>>> kNN.classify0([0,0],group,labels,3)
'B'
>>> kNN.classify0([1,0],group,labels,3)
'B'
>>> kNN.classify0([2,2],group,labels,3)
'A'
~~~
参考文献:
1.July.《编程之法.面试和算法心得》
2.Peter Harrington.《Machine Learning in Action》