KNN(K-近邻算法):算法本身是一个有监督学习的算法,故训练数据是有标签的,算法的原理是计算测试数据距离训练数据的距离(一般是欧式距离),将计算出的距离进行从小到大的排序,取前K个距离对应的训练数据,计算这K个数据中不同标签所占比例,比例最高的标签即为测试数据所属于的类。
Python实现:
from numpy import *
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
def classify(x,dataSet,labels,k):
dataSetSize = dataSet.shape[0]
diffMat = tile(x,(dataSetSize,1))-dataSet
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]]
classCount[voteIlabel] = classCount.get(voteIlabel,0)+1
sortedClassCount = sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse=True)
#print classCount
return sortedClassCount[0][0]
groups,labels=createDataSet()
classes=classify([0.2,0.2],groups,labels,3)
关于上述代码中涉及的方法的解释:
1.shape返回数组的行列数,shape[0]即为数组的行数
2.tile(x,(dataSetSize,1)):
tile方法是将数组x,复制dataSetSize行,具体情况如下所示:
>>> import numpy
>>> numpy.tile([0,0],5)#在列方向上重复[0,0]5次,默认行1次
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
>>> numpy.tile([0,0],(1,1))#在列方向上重复[0,0]1次,行1次
array([[0, 0]])
>>> numpy.tile([0,0],(2,1))#在列方向上重复[0,0]1次,行2次
array([[0, 0],
[0, 0]])
>>> numpy.tile([0,0],(3,1))
array([[0, 0],
[0, 0],
[0, 0]])
>>> numpy.tile([0,0],(1,3))#在列方向上重复[0,0]3次,行1次
array([[0, 0, 0, 0, 0, 0]])
>>> numpy.tile([0,0],(2,3))#在列方向上重复[0,0]3次,行2次
array([[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]])
3.diffMat**2:将diffMat数组中的每个元素进行平方
4.sqDiffMat.sum(axis=1):将数组sqDiffMat按行相加
5. distances.argsort():进行排序,不过返回的不是排序后的数组,而是排序后数组中元素序号:
如:
>>> a=[1,3,6,2]
>>> argsort(a)
array([0, 3, 1, 2], dtype=int64)
6.sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse=True):
(1),第一个参数指定要排序的list或者iterable
(2),key为函数,指定取待排序元素的哪一项进行排序,在这里用的是operator.itemgetter(1)。
operator.itemgetter函数
operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号(即需要获取的数据在对象中的序号),下面看例子。
a = [1,2,3]
b=operator.itemgetter(1) //定义函数b,获取对象的第1个域的值
b(a) 2
b=operator.itemgetter(1,0) //定义函数b,获取对象的第1个域和第0个的值
b(a) (2, 1)要注意,operator.itemgetter函数获取的不是值,而是定义了一个函数,通过该函数作用到对象上才能获取值。
在这里用operator.itemgetter(1)就表示,根据第二个域进行排序。(因为要排序的数据在classCount中,这是一个字典,形式为:{‘A’: 1, ‘B’: 2},所以要根据第二个域进行排序,来获得测试数据是属于哪个类的)
(3),reverse参数就不用多说了,是一个bool变量,表示升序还是降序排列,默认为false(升序排列),定义为True时将按降序排列。