代码来自《机器学习实战》https://github.com/wzy6642/Machine-Learning-in-Action-Python3
K-近邻算法(KNN)
介绍
简单地说,k-近邻算法采用测量不同特征值之间的距离方法进行分类。
优点:精度高、对异常值不敏感,无数据输入假定。
缺点:计算复杂度高、空间复杂度高,无法给出数据的内在含义。
使用数据范围:数值型、标称型。
分类函数的伪代码:
对未知类别属性的数据集中的每个点依次执行以下操作:
(1)计算已知类别数据集中的点与当前点之间的距离;
(2)按照距离递增次序排序;
(3)选取与当前点距离最小的k个点;
(4)确定前k个点所在类别的出现概率;
(5)返回前k个点出现频率最高的类别作为当前点的预测分类。
1 """创建数据集 2 返回: group - 数据集 3 labels - 分类标签 4 """ 5 def createDataSet(): 6 # 四组二维特征 7 group = np.array([[1, 101], [5, 89], [108, 5], [115, 8]]) 8 # 四组特征的标签 9 labels = ['爱情片', '爱情片', '动作片', '动作片'] 10 return group, labels 11 12 13 """ 14 KNN算法,分类器 15 参数: 16 inX - 用于分类的数据(测试集) 17 dataSet - 用于训练的数据(训练集)(n*1维列向量) 18 labels - 分类标准(n*1维列向量) 19 k - KNN算法参数,选择距离最小的k个点 20 返回: 21 sortedClasscount[0][0] - 分类结果 22 """ 23 def classify0(inX, dataSet, labels, k): 24 # numpy函数shape[0]返回dataSet的行数(维度) 25 dataSetSize = dataSet.shape[0] 26 # 将inX重复dataSetSize次并排成一列 27 diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet 28 # 二维特征相减后平方 29 sqDiffMat = diffMat**2 30 # sum()所有元素相加,sum(0)列相加,sum(1)行相加 31 sqDistances = sqDiffMat.sum(axis=1) 32 # 开方,计算出距离 33 distances = sqDistances**0.5 34 # argsort函数返回的是distances值从小到大的索引值 35 sortedDistIndicies = distances.argsort() 36 # 定义一个记录类别次数的词典 37 classCount = {} 38 # 选择距离最小的k个点 39 for i in range(k): 40 # 取出前k个元素的类别 41 voteIlabel = labels[sortedDistIndicies[i]] 42 # 字典的get()方法,返回指定键的值,如果值不在字典中返回0 43 # 计算类别次数 44 classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 45 # reverse降序排序字典,operator.itemgetter(1)按值排序,(0)按键排序 46 sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) 47 # 返回次数最多的类别,即所要分类的类别 48 return sortedClassCount[0][0] 49 50 # 测试 51 group, labels = createDataSet() 52 classify0([0,0], group, labels, 3) # output: '爱情片'
实战:手写数字识别系统
这里只能识别数字0到9,图像为32*32像素的黑白图像,将图像转换为文本格式。
将图像格式化处理为一个向量,把32*32的二进制图像矩阵为1*2014的向量。
1 """ 2 将32*32的二进制图像转换为1*1024向量 3 参数: 4 filename - 文件名 5 返回: 6 returnVect - 返回二进制图像的1*1024向量 7 """ 8 9 def img2vector(filename): 10 returnVect = np.zeros((1, 1024)) 11 fr = open(filename) 12 # 按行读取 13 for i in range(32): 14 # 读取一行数据 15 lineStr = fr.readline() 16 # 每一行的前32个数据依次存储到returnVect中 17 for j in range(32): 18 returnVect[0, 32*i+j] = int(lineStr[j]) 19 # 返回转换后的1*1024向量 20 return returnVect 21 22 # 测试 23 testVector = img2vector('testDigits/0_13.txt') 24 testVector[0, 0:31] 25 # output: array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 26 # 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
测试算法
1 """ 2 手写数字分类测试 3 参数: 4 None 5 返回: 6 None 7 """ 8 def handwritingClassTest(): 9 # 测试集的labels 10 hwLabels = [] 11 # 返回trainingDigits目录下的文件名 12 trainingFilesList = listdir('trainingDigits') 13 # 返回文件夹下文件的个数 14 m = len(trainingFilesList) 15 # 初始化训练的Mat矩阵(全零针),测试集 16 trainingMat = np.zeros((m, 1024)) 17 # 从文件名中解析出训练集的类别 18 for i in range(m): 19 # 获得文件的名字 20 fileNameStr = trainingFilesList[i] 21 # 获得分类的数字 22 classNumber = int(fileNameStr.split('_')[0]) 23 # 将获得的类别添加到hwLabels中 24 hwLabels.append(classNumber) 25 # 将每个文件的1*1024数据存储到trainingMat矩阵中 26 trainingMat[i, :] = img2vector('trainingDigits/%s' % (fileNameStr)) 27 # 构造KNN分类器 28 neigh = KNN(n_neighbors=3, algorithm='auto') 29 # 拟合模型,trainingMat为测试矩阵,hwLabels为对应标签 30 neigh.fit(trainingMat, hwLabels) 31 # 返回testDigits目录下的文件列表 32 testFileList = listdir('testDigits') 33 # 错误检测计数 34 errorCount =0.0 35 # 测试数据的数量 36 mTest = len(testFileList) 37 # 从文件中解析出测试集的类别并进行分类测试 38 for i in range(mTest): 39 # 获得文件名字 40 fileNameStr = testFileList[i] 41 # 获得分类的数字 42 classNumber = int(fileNameStr.split('_')[0]) 43 # 获得测试集的1*1024向量,用于训练 44 vectorUnderTest = img2vector('testDigits/%s' % (fileNameStr)) 45 # 获得预测结果 46 classifierResult = neigh.predict(vectorUnderTest) 47 print("分类返回结果为%d\t真实结果为%d" % (classifierResult, classNumber)) 48 if(classifierResult != classNumber): 49 errorCount += 1.0 50 print("总共错了%d个数据\n错误率为%f%%" % (errorCount, errorCount/mTest * 100))
来源:https://www.cnblogs.com/harbin-ho/p/12026276.html