数据
标称型和数值型
算法
归一化处理:防止数值较大的特征对距离产生较大影响
计算欧式距离:测试样本与训练集
排序:选取前k个距离,统计频数(出现次数)最多的类别
1 def classify0(inX, dataSet, labels, k): 2 ''' 3 4 :param inX: 测试样本(arr) 5 :param dataSet: 训练数据集(arr) 6 :param labels: 类别(list) 7 :param k:(int) 8 :return: 类别 9 ''' 10 #计算距离 11 dataSetSize = dataSet.shape[0] # 样本数量 12 diffMat = tile(inX, (dataSetSize, 1)) - dataSet #tile(inX{数组},(dataSetSize{倍数},1{竖向})):将数组(inX)竖向(1)复制dataSetSize倍 13 sqDiffMat = diffMat ** 2 #先求平方 14 sqDistances = sqDiffMat.sum(axis=1) #再求平方和 15 distances = sqDistances ** 0.5 #开根号,欧式距离 16 sortedDistIndicies = distances.argsort() #距离从小到大排序的索引 17 classCount = {} 18 for i in range(k): 19 voteIlabel = labels[sortedDistIndicies[i]] #用索引得到相应的类别 20 classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 21 return max(classCount, key=lambda k: classCount[k]) # 返回频数最大的类别
ps:
需要先 from numpy import *
训练集(dataSet)可先归一化处理
arr值numpy的数组(array)类型
例子:
约会网站的配对
header:每年获得的飞行常客里程数 玩视频游戏所耗时间百分比 每周消费的冰激凌数 评价(类别)
from numpy import * import re #从文件导入数据 def file2array(filename): ''' :param filename: 文件名 :return: 数据集(arr)、类别(list) ''' label={ 'didntLike':0, 'smallDoses':1, 'largeDoses':2 } with open(filename) as fr: lines =fr.readlines() tempLine =re.split('\s+',lines[0].strip()) #'\s+'表示tab或多个空格 #strip()除去换行符 returnArr = zeros((len(lines),len(tempLine)-1)) #初始化数组(存放数据集) classLabelVector = [] #存放类别 for index,line in enumerate(lines): listFromLine = re.split('\s+',line.strip()) #空格或tab都行 returnArr[index,:] = listFromLine[0:-1] classLabelVector.append(label[listFromLine[-1]]) return returnArr,classLabelVector #数据归一化 def Norm(dataSet): minVals = dataSet.min(0) #0:列(特征)的最小值;1:行(样本)的最小值 maxVals = dataSet.max(0) ranges = maxVals - minVals normDataSet = zeros(dataSet.shape) m = dataSet.shape[0] normDataSet = dataSet - tile(minVals, (m,1)) normDataSet /= tile(ranges, (m,1)) #element wise divide return normDataSet, ranges, minVals #约会网站配对例子 def datingClassTest(): hoRatio = 0.80 #80%作为测试集,20%为训练集 datingDataMat,datingLabels = file2array('..dataCh02datingTestSet.txt') #加载数据 normMat, ranges, minVals = Norm(datingDataMat) #数据归一化 m = normMat.shape[0] #数据集大小(样本的数目) numTestVecs = int(m*hoRatio) errorCount = 0.0 for i in range(numTestVecs): classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3) print("预测类别: %d, 真实类别: %d" % (classifierResult, datingLabels[i])) if (classifierResult != datingLabels[i]): errorCount += 1.0 #统计预测错误的次数 print ("平均错误率是: %f" % (errorCount/float(numTestVecs))) print("总测试数目:",numTestVecs,"总错误数目:",errorCount) #kNN分类器 def classify0(inX, dataSet, labels, k): ''' :param inX: 测试样本(arr) :param dataSet: 训练数据集(arr) :param labels: 类别(list) :param k:(int) :return: 类别 ''' #计算距离 dataSetSize = dataSet.shape[0] # 样本数量 diffMat = tile(inX, (dataSetSize, 1)) - dataSet #tile(inX{数组},(dataSetSize{倍数},1{竖向})):将数组(inX)竖向(1)复制dataSetSize倍 sqDiffMat = diffMat ** 2 #先求平方 sqDistances = sqDiffMat.sum(axis=1) #再求平方和 distances = sqDistances ** 0.5 #开根号,欧式距离 sortedDistIndicies = distances.argsort() #距离从小到大排序的索引 classCount = {} for i in range(k): voteIlabel = labels[sortedDistIndicies[i]] #用索引得到相应的类别 classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 return max(classCount, key=lambda k: classCount[k]) # 返回频数最大的类别 if __name__ =='__main__': datingClassTest()
手写数字图象识别
数据:转成txt格式的32*32图象
1 from numpy import * 2 from os import listdir 3 4 def loadData(dirname): 5 listData =listdir(dirname) 6 #把32*32文本文件读为1*1024 7 def file2arr(filename): 8 with open(filename) as f: 9 vec =f.read() 10 return list(vec.replace(' ','')) 11 sizeData =len(listData) #文件的数量 12 cLabel=zeros(sizeData,dtype='int16') #文件类别 13 arrTrain =zeros((sizeData,1024),dtype='int16') #训练样本数组 14 for i,j in enumerate(listData): 15 cLabel[i] =int(j[0]) #每个文件对应的类别 16 arrTrain[i,:] =file2arr(dirname + '\' +j) 17 return cLabel,arrTrain 18 19 if __name__ =='__main__': 20 from knn import classify0 21 fTrain = r'..dataCh02digits rainingDigits' 22 fTest = r'..dataCh02digits estDigits' 23 cLabel,arrTrain =loadData(fTrain) 24 cLabelTest,arrTest =loadData(fTest) 25 err=0 26 for j,i in enumerate(arrTest): 27 label =classify0(i,arrTrain,cLabel,3) 28 if cLabelTest[j] !=label:err+=1 29 print('错误率:',err/len(cLabelTest)) 30 31 #sklearn库knn对比 32 from sklearn.neighbors import KNeighborsClassifier as knn 33 model =knn(n_neighbors=3,n_jobs=4,algorithm='auto') 34 model.fit(arrTrain,cLabel) 35 cLabelPredict =model.predict(arrTest) 36 print('错误率',sum(cLabelPredict!=cLabelTest)/len(cLabelTest))
代码+数据集放在https://github.com/vvlj/ml
直观理解https://cuijiahua.com/blog/2017/11/ml_1_knn.html