首先讲,什么是k-近邻算法?
k-近邻算法是一种有监督学习方法,即训练样本中的每个样本的类别标签都是已知的。对于一个新来的样本,我们将它的特征与训练样本集中的每个样本进行特征比较,然后算出与该样本最相似的k个样本,利用投票法,将k个样本中类别出现次数最多的那个类作为新来样本的类别。特别地,当k=1时,k-近邻算法就简化为最近邻分类算法。
其中刻画相似性的度量方法有:欧氏距离、曼哈顿距离、切比雪夫距离、马氏距离等等。常用的是欧式距离。
k-近邻算法
优点:精度高、对异常值不敏感、无数据输入假定
缺点:计算复杂度高、空间复杂度高
适用数据范围;数值型和标称型
我们结合例子来进行讲解:为了简单起见,假设训练集中存在四个样本,它们分别是二维平面上的四个点,(1.0,1.1)、(1.0,1.0)、(0,0)、(0,0.1),假定分别属于A、A、B、B类,明显这是一个二分类问题。测试数据是(0.5,0.5),我们的目标是根据k-近邻算法判定(0.5,0.5)属于哪一类。
首先创建训练数据集,添加createDataSet()函数:
from numpy import *
import operator
def createDataSet():
group = [[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("样本的特征:")
print(group)
print("样本的标签:")
print(labels)
结果如下:
然后,我们为了便于理解,把每个步骤的运算结果打印出来(使用欧式距离)。
print(len(group)) #得到训练集中样本数量
diffMat = tile([0.5,0.5],(len(group),1)) - group #将新样本数据与训练集中的每个样本作差
print(diffMat)
sqDiffMat = diffMat**2 #差的平方
print(sqDiffMat)
sqDistances = sqDiffMat.sum(axis=1) #作和
print(sqDistances)
distances = sqDistances**0.5 #开根号,求欧式距离
print(distances)
sortedDistanceIndices = distances.argsort() #根据距离大小由大到小排序,并将其索引输出
print(sortedDistanceIndices)
classCount = {} #一个字典,记录每个标签和它对应的次数
labels = ['A','A','B','B']
for i in range(3): #假设k=3
voteLabel = labels[sortedDistanceIndices[i]] #得到前三个的标签
classCount[voteLabel] = classCount.get(voteLabel,0) + 1 #将对应的标签的value加1
print(classCount)
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) #根据value的大小对字典进行排序
print(sortedClassCount)
print(sortedClassCount[0][0]) #得到新样本的类别
运行结果:
从结果中,我们可以看到根据k-近邻算法,该新样本属于B类。
下面,我们写一个函数classify()将以上代码综合起来,方便以后又来了一个新样本,可以直接调用classify函数识别。
from numpy import *
import operator
def createDataSet():
group = [[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]]
labels = ['A','A','B','B']
return group,labels
group,labels = createDataSet()
def classify(input,dataSet,labels,k):
dataSetSize = len(dataSet)
diffMat = tile(input,(dataSetSize,1)) - group
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5
sortedDistanceIndices = distances.argsort()
classCount = {}
for i in range(k):
voteLabel = labels[sortedDistanceIndices[i]]
classCount[voteLabel] = classCount.get(voteLabel,0) + 1
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
print(classify([0.5,0.5],group,labels,3))