机器学习 k-近邻算法
1、使用python导入数据
from numpy import * def createDataSet(): group=array([[1.1,1.1],[1.0,1.0],[0,0],[0,0.1]]) labels=['A','A','B','B'] return group,labels
kNN分类算法:
from numpy import * import operator def classify0(inX,dataSet,labels,k): dataSetSize=dataSet.shape[0] #shape[0]表示dataSet的行数 diffMat=tile(inX,(dataSetSize,1))-dataSet 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 sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) return sortedClassCount[0][0]
distances是1*4的矩阵,分别表示待分类的点与所有已知点的距离;
sortedDistIndicies是distances从小到大的索引值;
voteIlabel相当于临时变量,用来取得标签值;
classCount[voteIlabel]=classCount.get(voteIlabel,0)+1 如果在字典classCount中找到key=voteIlabel的value,就加1,找不到的话classCount.get(voteIlabel,0)返回0然后加1
sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) 先把字典classCount变成列表,再按照第二维降序排列,返回的仍是列表
执行算法:
import kNN from classify_kNN import * g,l=kNN.createDataSet() result=classify0([0,0],g,l,3) print(result)
输出:
B
items():将字典中的项按照列表返回,无序:
get():返回字典对应key的value值,不存在key时返回第二个参数:
dic={'a':1,'b':2,'c':3} print(dic.items()) print(dic.get('c','no')) 输出: dict_items([('b', 2), ('c', 3), ('a', 1)]) 3
shape:返回矩阵的维数;
from numpy import * c=array([[1,1],[2,3,],[5,6]]) print(c) print(c.shape) print(c.shape[0]) print(c.shape[1]) 输出: [[1 1] [2 3] [5 6]] (3, 2) 3 2
operator.itemgetter():返回对象特定维的数据,结合sorted()方法使用:
import operator students=[['刚田武',20,'gangtw'],['朱二娃',25,'zhuerw'],['咪咪two',30,'miomitwo']] print(sorted(students,key=operator.itemgetter(1),reverse=True)) 输出: [['咪咪two', 30, 'miomitwo'], ['朱二娃', 25, 'zhuerw'], ['刚田武', 20, 'gangtw']]
argsort():返回数组值从小到大的索引值
归一化数值:在计算欧氏距离的过程中,数值较大的属性对结果的贡献大,如果认为不同属性权重应该相同的话,就需要将数值归一化处理。
from numpy import * def autoNorm(dataset): minVals=dataset.min(0) #取每列的最小值,返回数组 print(minVals) maxVals=dataset.max(0) print(maxVals) ranges=maxVals-minVals #ranges是每列的最大值与最小值之差组成的数组 print(ranges) normDataset=zeros(shape(dataset)) print(normDataset) m=dataset.shape[0] #取dataset的行数 normDataset=dataset-tile(minVals,(m,1)) print(normDataset) normDataset=normDataset/tile(ranges,(m,1)) print(ranges) return normDataset
minVals=dataset.min(0) #取数据集每列的最小值,返回数组
from numpy import * dataset=array(([6,5], [3,1000], [10,300])) print(dataset.min()) #返回所有元素中的最小值 print(dataset.min(0)) #返回每列的最小值组成的数组 print(dataset.min(1)) #返回每行的最小值组成的数组 输出: 3 [3 5] [ 5 3 10]
m=dataset.shape[0] #取dataset的行数
from numpy import * dataset=array(([6,5], [3,1000], [10,300])) print(dataset.shape) #返回数据集的“形状”,行数和列数 print(dataset.shape[0]) #返回行数 print(dataset.shape[1]) #返回列数 输出: (3, 2) 3 2
测试分类器:
def datingClassTest(): hoRatio=0.1 datingDataMat,datingLabels=file2matrix('datingTestSet2.txt') normMat,ranges,minVals=autoNorm(datingDataMat) m=normMat.shape[0] numTestVecs=int(m*hoRatio) errorCount=0 for i in range(numTestVecs): classifyerResult=classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3) print('classify result is %s ,the real answer is %s'%(classifyerResult,datingLabels[i])) if classifyerResult!=datingLabels[i]: errorCount+=1 print('the total error rate is %f'%(errorCount/float(numTestVecs)))
hoRatio=0.1 测试数据占数据集的10%
使用:输入各参数,输出分类结果:
def classifyPerson(): resultList=['not at all','in small doses','in largr doses'] timeOnGames=float(input('请输入游戏时间百分比:')) flyMiles=float(input('请输入每年飞行里程数:')) iceCream=float(input('请输入每周消耗的冰淇淋升数:')) datingDataMat,datingLabels=file2matrix('datingTestSet2.txt') normMat,ranges,minVals=autoNorm(datingDataMat) person2test=array([flyMiles,timeOnGames,iceCream]) classifierResult=classify0((person2test-minVals)/ranges,normMat,datingLabels,5) print('you may like thie one:',resultList[classifierResult-1])
通过调节k值可以调整分类器的正确率。
使用k近邻算法识别手写数字:
def handwritingClassTest(): hwLabels=[] trainingFileList=listdir('digits/trainingDigits') m=len(trainingFileList) trainingMat=zeros((m,1024)) for i in range(m): fileNameStr=trainingFileList[i] fileStr=fileNameStr.split('.')[0] classNumStr=int(fileStr.split('_')[0]) hwLabels.append(classNumStr) trainingMat[i,:]=img2vector('digits/trainingDigits/%s'%fileNameStr) testFileList=listdir('digits/testDigits') errorCount=0 mTest=len(testFileList) for i in range(mTest): fileNameStr=testFileList[i] fileStr=fileNameStr.split('.')[0] classNumStr=int(fileStr.split('_')[0]) vectorUnderTest=img2vector('digits/testDigits/%s'%fileNameStr) classifierResult=classify0(vectorUnderTest,trainingMat,hwLabels,3) #print('分类结果:%s,实际结果:%s'%(classifierResult,classNumStr)) if(classifierResult!=classNumStr): errorCount+=1 print('分类错误总计:',errorCount) print('分类错误率:',errorCount/float(mTest))
注释:
trainingMat用来存储数据集,每个待测记录都要计算与此数据集之间的距离
hwLabels用来存储trainingMat对应的标签
fileNameStr存储文件名
fileStr存储不含后缀的文件名
classNumStr存储每条记录实际标签
vectorUnderTest表示待分类记录
计算分类错误率时,使用float()将int型数据变成浮点型