1. k-近邻法简介
k近邻法(k-nearest neighbor, k-NN)是1968年由Cover THart 提出的一种基本分类与回归方法。它的工作原理是:存在一个样本数据集合,也称作为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据后,将新的数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
注意: k-近邻法不具有显式的学习过程,它实际上是利用训练数据集对特征向量空间进行划分,并作为其分类的“模型”.其中K值的选取、距离度量及分类决策规则是k近邻算法的三个基本要素。
2. k近邻算法的数学语言表达:
3. k近邻算法中k值的选取标准:
4. 在k近邻算法中的距离度量公式如下图所示:
6. K近邻算法的一般流程
本次案例主要是使用k-近邻算法来对电影进行分类。这里我们主要将电影分为两种:爱情片和动作片。根据电影中出现的打斗和接吻镜头来进行判定。本案例所使用的距离度量为欧氏距离。
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5
sortedDistIndices = distances.argsort()
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndices[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
#返回次数最多的类别,即所要分类的类别
return sortedClassCount[0][0]
if __name__ == '__main__':
#创建数据集
group, labels = createDataSet()
#对输入数据进行分类
x = input("请输入测试数据:")
xlist=x.split(" ")
test = [int(xlist[i]) for i in range(len(xlist))]
#kNN分类
test_class = classify0(test, group, labels, 3)
#打印分类结果
print(test_class)
本节我们一步步地构造使用k-近邻分类器的手写识别系统。为了简单起见,这里构造的系统
只能识别数字0到9.需要识别的数字已经使用图形处理软件,处理成具有相同的色
彩和大小,其中宽高是32像素×32像素的黑白图像。尽管采用文本格式存储图像不能有效地利用内
存空间,但是为了方便理解,我们还是将图像转换为文本格式。
存储的数字文件格式为:数字的值_该数字的样本序号,如下图所示:
数据集分为训练集和测试集,通过上述电影分类的方法,设计一个k-近邻算法分类器实现数字分类。其中数据集和实现代码下载地址:数据集下载
代码展示:
import numpy as np
import operator
from os import listdir
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
#欧式距离计算
diffMat = tile(inX, (dataSetSize,1)) - dataSet
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5
sortedDistIndicies = distances.argsort()
classCount={}
#选择距离最小的K个点
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
def img2vector(filename):
returnVect = np.zeros((1,1024))
fr = open(filename)
for i in range(32):
lineStr = fr.readline()
for j in range(32):
returnVect[0,32*i+j] = int(lineStr[j])
return returnVect
def handwritingClassTest():
hwLabels = []
trainingFileList = listdir('trainingDigits') #load the training set
m = len(trainingFileList)
trainingMat = np.zeros((m,1024))
for i in range(m):
fileNameStr = trainingFileList[i]
fileStr = fileNameStr.split('.')[0] #take off .txt
classNumStr = int(fileStr.split('_')[0])
hwLabels.append(classNumStr)
trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
testFileList = listdir('testDigits') #iterate through the test set
errorCount = 0.0
mTest = len(testFileList)
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0] #take off .txt
classNumStr = int(fileStr.split('_')[0])
vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr))
if (classifierResult != classNumStr): errorCount += 1.0
print("\nthe total number of errors is: %d" % errorCount)
print("\nthe total error rate is: %f" % (errorCount/float(mTest)))
kNN算法的优缺点
优点:
缺点:
参考资料:
本文中提到的电影分类、手写数字识别实例和数据集,均来自于《机器学习实战》的第二章k-近邻算法。
本文的算法理论部分,参考自《统计学习方法 李航》的第三章k近邻法以及《机器学习实战》的第二章k-近邻算法。