ML in Action C2 k-近邻算法的实现与应用 K近邻算法改进约会网站 K近邻算法实现手写数字识别 附代码与注释

it2024-02-20  66

代码总共分为两部分,第一部分为k近邻算法改进约会网站,第二部分为手写数字识别

createDataSet 创建和一个用于测试的数据集

classify0 实现K近邻算法

file2matrix 实现将文件中的数据转化为矩阵

autoNorm 实现数据的归一化

datingClassTest 测试数据的分类

classifyPerson 用于自定义数据来进行预测

img2Vector 将手写数字识别对应的数据集文件转化为向量

handWritingClassTest 用于实现手写数字识别并分类

本文所有的代码和数据集链接:https://pan.baidu.com/s/1WM2zyE-br1-o4-wuZP2w0g  提取码:cube 

欢迎各位指点交流

# @Time : 2020/10/14 19:17 # @Author : cuber # @Software: PyCharm # @Blog :https://me.csdn.net/blog/Z_Dalao # @coding :utf-8 from numpy import * import numpy import operator as op from os import listdir #创建一个用于实验的数据例子 def createDataSet(): group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]]) lables = ['A','A','B','B'] return group,lables """ K近邻算法,即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例,这K个实例的 多数属于某个类,就把该输入实例分类到这个类中。 优点:精度高(计算距离),对异常值不敏感(单纯按距离分类,会忽略特殊情况),无数据输入假定(不会对数据进行预先判定) 缺点:时间复杂度高,空间复杂度高 适用数据范围:数据行和标称型 本例用来理解k近邻算法的思想,现在有很多封装的这样的算法只需要直接调用即可 """ def classify0(inX, dataSet, labels, k): # intX是测试的用例,dataset训练集,labels是训练集对应的标签,k是用于选择最近邻的数目 dataSetSize = dataSet.shape[0]#根据本例值为4 # 算出每个坐标点到输入坐标点的值 diffMat = numpy.tile(inX,(dataSetSize,1)) - dataSet sqDiffMat = diffMat**2 #算出矩阵的平方 sqDistance = sqDiffMat.sum(axis=1) #算出距离 distance = sqDistance**0.5#开方 #根据距离大小进行下标排序 sortedDistIndscies = distance.argsort() # 返回的是数组值从小到大的索引值 classCount = {} #选择距离最小的K个点进行判断 for i in range(k): voteIlabel = labels[sortedDistIndscies[i]] #存储从小到大的索引对应的标签 classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 # 统计每个标签出现的次数 sortedClassCount = sorted(classCount.items(), key=op.itemgetter(1), reverse=True) #将字典中的数据排序,从大到小 return sortedClassCount[0][0] #返回最接近的种类 #file2matrix,用于将文件读取的数据转化为矩阵 def file2matrix(filename): #首先打开文件,把文件中的每行文本作为字符串保存到列表中并返回该列表,用len函数算出有多少行 fr = open(filename) arrayOlines = fr.readlines() numberOflines = len(arrayOlines) #用zero函数创建一个全为0的,跟读取文件一样的行数,3列的矩阵 returnMat = zeros((numberOflines,3)) #声明一个列表来存储标签向量 classLabelVector = [] index = 0 for line in arrayOlines: line = line.strip()#去掉字符串的空格 listFromLine = line.split('\t')#将元素分隔开 returnMat[index,:] = listFromLine[0:3]#将数据的前三个存入returnMat中,即每行对应的三个特征值 classLabelVector.append(int(listFromLine[-1]))#将所对应的标签存入classLabelVector中,每行的最后一个 index += 1 return returnMat,classLabelVector#返回读取到的数据 ,returnMat 是一个line行 三列的数组,classLabelVector 是对应每一行的标签 """归一化特征值""" def autoNorm(dataSet): #找出数据集中的最大值最小值,和差值 参数0使得函数从列中选取 minVals = dataSet.min(0) maxVals = dataSet.max(0) ranges = maxVals-minVals m = dataSet.shape[0] print("m:",m) print(dataSet) #这里有一个公式在后边归一化中详细介绍(newValue = (oldValue - min)/(max - min)) #这里的tile 是 生成一个 1000行一列的minVals,而minVals是一行三列,最终生成1000行三列的矩阵来进行加减乘除 normDataset = dataSet - tile(minVals,(m,1)) normDataset = normDataset/tile(ranges,(m,1)) #返回归一化后的数据 return normDataset, ranges, minVals def datingClassTest(): hoRatio = 0.10#90%用于训练样本 10%用于测试分类器 #读取文件中的数据并返回矩阵和标签 datingDataMat,datingLables = file2matrix('./data/datingTestSet2.txt') #数据归一化 normMat, ranges, minVals = autoNorm(datingDataMat) m = normMat.shape[0]#读取矩阵第一维的长度,本例为总体样本 #一下两个分别用来记录测试用例和错误数量 numTestVecs = int(m*hoRatio) errorCount = 0.0 for i in range(numTestVecs): #利用classify0方法来一一判断该点所属的分类 classifierResult = classify0(normMat[i,:], normMat[numTestVecs:m,:],datingLables[numTestVecs:m],3) print("the classifier came back with: %d, the real answer is: %d"%(classifierResult,datingLables[i])) #如果判断的结果错误,errorCount +1 if (classifierResult) != datingLables[i] : errorCount += 1.0 print("the total error rate is:%f" %(errorCount/float(numTestVecs))) def classifyPerson(): #定义标签种类 resultList = ['not at all','in small dose','in large doses'] #接下来的三行用于接收输入的数值 precentTats = float(input("percentage of time spent playing video games?")) ffMiles = float(input("frequent filter mils earnd per year?")) iceCream = float(input("liters of ice cream consumed per year?")) #获取数据,归一化转化为数组,然后进行预测 datingDataMat, datingLabels = file2matrix('./data/datingTestSet2.txt') normMat, ranges, minVals = autoNorm(datingDataMat) inArr = array([ffMiles,precentTats,iceCream]) classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3) print("you will probably like this persion:",resultList[classifierResult-1]) """第二部分手写数字识别数据准备""" def img2Vector(filename): #创建一个1行1024列的向量,读取图片对应的文件并存入向量中,并返回该文件对应的向量 returnVect = 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(): hwLables = [] #用来存储数据对应的标签 trainingFileList = listdir('./data/digits/trainingDigits')#用于读取所有文件的名字,用于分析出文件所对应的标签 m = len(trainingFileList) trainingMat = zeros((m, 1024)) #声明一个M行 1024列的矩阵用于吧照片存储 #此循环用于读取所有文件所对应的标签,最终返回文件所对应的数字的元组 hwlables for i in range(m): fileNameStr = trainingFileList[i] fileStr = fileNameStr.split('.')[0] classNumStr = int(fileStr.split('_')[0]) hwLables.append(classNumStr) trainingMat[i,:] = img2Vector('./data/digits/trainingDigits/%s'% fileNameStr)#将照片存储在矩阵中 #基本同上,一下用于测试集 testFileList = listdir('./data/digits/testDigits') errorCount = 0.0 #用来计算错误率 mTest = len(testFileList) for i in range(mTest): fileNameStr = testFileList[i] fileStr = fileNameStr.split('.')[0] classNumStr = int(fileStr.split('_')[0]) vectorUndeTest = img2Vector('./data/digits/testDigits/%s'% fileNameStr) #前边已经求得了数据集,在测试集中用K临近算法来预测测试集中的数字 classifierResult = classify0(vectorUndeTest, trainingMat, hwLables, 3) print('the classifier came back with %d, the real answer is : %d' %(classifierResult,classNumStr)) if (classifierResult != classNumStr): errorCount += 1.0 print("\n the total number of errors is : %d" %errorCount) print("\n the total error rate is : %f" % (errorCount/float(mTest)))
最新回复(0)