优点:精度高,对异常值不敏感,无输入数据假定
缺点:时间复杂度高,空间复杂度高。
适用数据范围:数值行和标称型。
简单的K-近邻算法。 直接上代码,看注释就行,
K-近邻算法识别书写数字数据集,错误率为1.2%。当然改变K的值或者修改训练数据会对结果产生影响。
实际使用这个算法的时候执行的效率并不高,因为算法需要位每个测试向量做2000次计算,每个距离包含1024个维度浮点运算,总计需要执行900此,此外还需要准备2M的空间。这个缺点很让人遗憾。
K-近邻算法虽然是最简单最有效的算法,但是使用算法的时候我们必须要有接近实际数据的训练样本数据。K-近邻算法必须保存全部数据集,如果训练的数据集很大,则必须使用大量的储存空间。此外如果必须对数据集中的每个数据都进行求距离的话,消耗的时间也不是一个小数目。
其另一个缺点就是它无法给出任何数据的基础结构信息,因此我们也无法知晓平均实例样本和典型案例样本具有什么特征。下一章我们将用概率测量的方法来处理分类问题。该算法可以解决该问题。
1 from numpy import * 2 import operator 3 import os 4 def createDataSet () : 5 group = array([[0.5,0.5],[0.9,0.9],[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])#创建数组 6 labels = ['c','A','A','A','B','B'] #列表 7 return group,labels 8 9 def classify0(inX,dataSet,labels,k): 10 dataSetSize = dataSet.shape[0] #dataSet[0] 中有几个元素 答案是4 11 diffMat = tile(inX,(dataSetSize,1)) - dataSet 12 sqDiffMat = diffMat**2 #计算出来距离 13 sqDistances = sqDiffMat.sum(axis=1) #将一个小数组合并的距离的平方 14 distances = sqDistances**0.5 #得到具体的距离 15 sortedDistIndicies = distances.argsort() #根据索引值进行排序 16 # print(sortedDistIndicies) 17 classCount = {} 18 for i in range(k): 19 voteIlabel = labels[sortedDistIndicies[i]] #取出来最小值 20 # print(voteIlabel) 21 classCount[voteIlabel] = classCount.get(voteIlabel,0)+1 # 记录每组分类的案例数。 22 # print(classCount) 23 sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse = True) # 按照案例数的大小进行排序。 24 return sortedClassCount[0][0] 25 26 27 def file2matrix(filename): 28 fr = open(filename) 29 arrayOlines = fr.readlines() #读取所有行 30 numberOfLines = len(arrayOlines) #计算行数 31 returnMat = zeros((numberOfLines,3)) # 创建返回矩阵 32 classLabelVector = [] #创建列表 33 index = 0 34 for line in arrayOlines: 35 line = line.strip() # 用于删除一行结尾的换行符。 36 listFromLine = line.split(' ') #以制表符为界,将该字符串分开。 37 returnMat[index,:]=listFromLine[0:3] #切片操作 38 if(listFromLine[-1][0]=='l'): # 不同的类型赋成不同的值 39 jack = 3 40 elif(listFromLine[-1][0]=='s'): 41 jack = 2 42 else: 43 jack = 1 44 classLabelVector.append(jack) # 将 不同的类型加入 classLabelVector内 45 index+=1 46 return returnMat,classLabelVector 47 48 def autoNorm(dataSet): 49 minVal = dataSet.min(0) #找出这个数组中最小值例如([0,0,0]) 50 maxVal = dataSet.max(0) 51 ranges = maxVal -minVal #取值范围 52 normDataSet = zeros(shape(dataSet)) #制作同样大小的矩阵 53 m = dataSet.shape[0] #总共有m行 54 normDataSet = dataSet - tile(minVal,(m,1)) # 得到差值 55 normDataSet = normDataSet/tile(ranges,(m,1)) #归一化 56 return normDataSet,ranges,minVal 57 58 def datingClassTest(): 59 hoRatio = 0.10 60 datingDataMat,datingLabels = file2matrix('datingTestSet.txt') 61 normMat,ranges,minVals = autoNorm(datingDataMat) 62 m = normMat.shape[0] 63 numTestVecs = int(hoRatio*m) 64 errorCount = 0.0 65 for i in range(numTestVecs): 66 classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3) 67 print("The classifier came back with: %d,the real answer is: %d" % (classifierResult,datingLabels[i])) 68 if(classifierResult != datingLabels[i]): 69 errorCount += 1.0 70 71 print("The total error rate is :%f" % (errorCount/float(numTestVecs))) 72 73 def img2vector(filename): 74 returnVect = zeros((1,1024)) 75 fr = open(filename) 76 for i in range(32): 77 lineStr = fr.readline() 78 for j in range(32): 79 returnVect[0,32*i+j] = int(lineStr[j]) 80 return returnVect 81 82 def handWritingClassTest(): 83 hwLabels = [] 84 trainingFileList = os.listdir('trainingDigits') # 获取目录内容 85 m = len(trainingFileList) #总共有多少个文件。 86 trainingMat = zeros((m,1024)) # 一个文件算一行矩阵,列出来一个矩阵用于保存数据。 87 for i in range(m): #一个一个文件处理 88 fileNameStr = trainingFileList[i] #读取文件名称 89 fileStr = fileNameStr.split('.')[0] # 90 classNumStr = int(fileStr.split('_')[0]) # 这三行表示确定出来 图片的实际数字 91 hwLabels.append(classNumStr) # 将实际数字加入 hwLabels 92 trainingMat[i] = img2vector('trainingDigits/%s' % fileNameStr) # 将文件内容放到 trainingMat矩阵当中 93 testFileList = os.listdir('testDigits') # 获取文件内容 94 errorCount = 0.0 95 mTest = len(testFileList) #文件数 96 for i in range(mTest): #从测试文件中一个一个进行尝试 97 fileNameStr = testFileList[i] # 98 fileStr = fileNameStr.split('.')[0] # 99 classNumberStr = int(fileStr.split('_')[0]) # 获取测试文件的实际数字 100 vectorUnderTest = img2vector('testDigits/%s' % fileNameStr) # 获取文件实际内容 101 classifierResult = classify0(vectorUnderTest,trainingMat,hwLabels,3) # 用分类器进行测试 102 print("The classifier came back with: %d,the real answer is : %d" 103 %(classifierResult,classNumberStr)) 104 if(classNumberStr != classifierResult): 105 errorCount += 1 106 print(" The total number of error is :%d " % errorCount) 107 print(" The total error rate is:%f" % float(errorCount/float(mTest)))