from numpy import * #导入科学计算包
import operator #导入运算符模块,KNN执行排序算法时,会用到这个模块提供的函数
import matplotlib.pyplot as plt #matplotlib.pyplot是一个有命令风格的函数集合,每一个pyplot函数都使一副图像做出些许改变,例如创建一幅图,在图中创建一个绘图区域,在绘图区域中添加一条线等等。
from os import listdir
#定义了一个函数,创建数据集和标签
def createDataSet():
group=array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
labels=['A','A','B','B']
return group,labels
#定义了一个函数,用于分类,inX用于分类的输入向量,dataSet是训练样本集,k选择最近邻居的数目
def classify0(inX,dataSet,labels,k):
dataSetSize=dataSet.shape[0] #表明有几个数据集
diffMat=tile(inX,(dataSetSize,1))-dataSet #tile(A,n),功能是将数组inX重复n次,比如输入【0,0】变成【【0,0】【0,0】【0,0】【0,0】】
sqDiffMat=diffMat**2 #数组的每一个值进行平方
sqDistances=sqDiffMat.sum(axis=1) #axis=1就是将一个矩阵的每一行向量相加
distances=sqDistances**0.5 #将求的和进行开根号
sortedDistIndicies=distances.argsort() #argsort函数返回的是数组值从小到大的索引值
classCount={ } #大括号{ }花括号:代表dict字典数据类型,字典是由键对值组组成。冒号':'分开键和值,逗号','隔开组.这里用于存储不同标签出现的次数
for i in range(k):
voteIlabel=labels[sortedDistIndicies[i]] #按照距离先后顺序,通过第i个索引值找到对应的标签
classCount[voteIlabel]=classCount.get(voteIlabel,0)+1 #计算标签在字典中出现的次数,如果还没有在classCount中出现就默认为0,如果之前出现过,就+1
sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) #按照第二个元素的顺序对元祖进行排序,发生频率最高就是结果
return sortedClassCount[0][0] #频率最高e的元素标签就是所分类的结果
#测试分类器
# group,labels=createDataSet()
# print(classify0([0,0],group,labels,3))#结果为B
#处理输入格式的问题,函数输入为文件名字符串,输入为训练样本矩阵和类标签向量
def file2matrix(filename):
fr=open("datingTestSet2.txt")#返回的是一个叫做“file object”的东西,通过它,可以得到文件的内容,但是这并不表示它就是文件的内容,例如输出为<_io.TextIOWrapper name='datingTestSet2.txt' mode='r' encoding='cp936'>
arrayOLines=fr.readlines()#输出:['40920\t8.326976\t0.953952\t3\n', '14488\t7.153469\t1.673904\t2\n',...]
numberOfLines=len(arrayOLines)#获取文件行数
returnMat=zeros((numberOfLines,3))#创建一个numberOfLines行,3列的0矩阵
classLabelVector=[] #[ ]代表list列表数据类型
index=0
for line in arrayOLines:
line=line.strip() #strip() 方法用于移除字符串头尾指定的字符(默认为空格),截取掉所有的回车字符
listFromLine=line.split('\t') #得到的整行数据分割成一个元素列表
returnMat[index,:]=listFromLine[0:3] #选取前三个元素存到特征矩阵中去,取从0开始到3之前的,即取第0 1 2 个
classLabelVector.append(int(listFromLine[-1])) #append() 方法用于在列表末尾添加新的对象。索引值-1表示列表中的最后一列元素。需注意的是,要告诉解释器,列表中存储的元素值为整形,否则python会将这些元素当做字符串处理。
index+=1
return returnMat,classLabelVector
#测试读取文件的结果
datingDataMat,datingLabels=file2matrix("datingTestSet2.txt")
# print(datingDataMat)
# print(datingLabels)
# fig=plt.figure()#创建一幅图,可以没有参数,也可以有参数
# ax=fig.add_subplot(111)#将画布分割成1行41列,图像画在从左到右从上到下的第1块,参考http://blog.csdn.net/s201402023/article/details/51536687
# ax.scatter(datingDataMat[:,0],datingDataMat[:,1],15.0*array(datingLabels),15.0*array(datingLabels)) #第一个代表列,第二个代表行,例如这个就代表了取所有行,第1 2列,详情https://www.cnblogs.com/shanlizi/p/6850318.html
# plt.show()
#归一化特征值
def autoNorm(dataSet):
minVals=dataSet.min(0)#将每一列的最小值放在minVals中,0代表使得函数可以从列中选取最小值,而不是选取当前行的最小值
maxVals=dataSet.max(0)
ranges=maxVals-minVals
normDataSet=zeros(shape(dataSet))
m=dataSet.shape[0]#]#得到数组的行数。即知道有几个训练数据
normDataSet=dataSet-tile(minVals,(m,1))#将矩阵中每个值减去当前列的最小值。注:因为最小值矩阵是(1,3),要复制成(m,3列的)
normDataSet=normDataSet/tile(ranges,(m,1))#将矩阵中每个值除以取值范围(最大值-最小值)
return normDataSet,ranges,minVals#分别为归一化后的矩阵,每一列的取值范围,每一列的最小值
#测试归一化
# normMat,ranges,minVals=autoNorm(datingDataMat)
# print(normMat)
# print(ranges)
# print(minVals)
#针对约会网站的测试精确率的代码
def datingClassTest():
hoRatio=0.10
datingDataMat,datingLabels=file2matrix('datingTestSet.txt')#获取datingTestSet文本的数据和标签
normMat,ranges,minVals=autoNorm(datingDataMat)#将datingTestSet数据归一化
m=normMat.shape[0]#计算datingTestSet的总行数
numTestVecs=int(m*hoRatio)#取百分之十的数据作为测试数据
errorCount=0.0
for i in range(numTestVecs):
classifierResult=classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
print("the classifier came back with:%d,the real answer is : %d" % (classifierResult,datingLabels[i]))
if(classifierResult!=datingLabels[i]):errorCount+=1.0
print("the total error rate is:%f" % (errorCount/float(numTestVecs)))
#测试上面测试函数的代码:
# print(datingClassTest())
#该函数是为了使用户能够自己输入三个特征,然后输出结果
def classifyPerson():
resultList=['not at all','in small doses','in large doses']
percentTats=float(input("percentage of time spent playing video games?"))#??????????要加float
ffMiles=float(input("frequent flier miles earned per year?"))
iceCream=float(input("liters of ice cream earned per year?"))
datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
normat,ranges,minVals=autoNorm(datingDataMat)
inArr=array([ffMiles,percentTats,iceCream])
classfierResult=classify0((inArr-minVals)/ranges,normat,datingLabels,3)
print(classfierResult)
print("you will probably like this person:",resultList[classfierResult-1])
# classifyPerson()#执行代码
#手写识别系统
#将图片转换成向量,图片为32*32大小,向量为1*1024的向量。打开给定文件,循环读出前32行,将每行的前32个字符值放在numpy数组中
def img2vector(filename):
returnVect=zeros((1,1024))
fr=open(filename)#<_io.TextIOWrapper name='testDigits/0_13.txt' mode='r' encoding='cp936'>
# print(fr)
# lineStr1 = fr.readlines()
# print(lineStr1)
for i in range (32):
lineStr=fr.readline()#输出整个文件
# print(lineStr)
for j in range(32):
returnVect[0,32*i+j]=int(lineStr[j])
return returnVect
#测试上面函数
# testVector=img2vector('testDigits/0_13.txt')
# print(testVector[0,0:31])#输出结果的1-31列,总共31个
#手写数字识别系统的测试代码
def handwritingClassTest():
hwLabels=[]#存储每个文件的类别。是1 还是2 3 4 。。。
trainingFileList=listdir('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('trainingDigits/%s'% fileNameStr)#将每个训练文件的所有数据整理成一行
testFileList=listdir('testDigits')
errorCount=0.0
mTest=len(testFileList)
for i in range(mTest):
fileNameStr=testFileList[i]
fileStr=fileNameStr.split('.')[0]
classNumStr=int(fileStr.split('_')[0])
vectorUnderTest=img2vector('testDigits/%s'% fileNameStr )
classifierResult=classify0(vectorUnderTest,trainingMat,hwLabels,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)))
#测试代码:
handwritingClassTest()
注:直接将代码复制运行出错,将
classCount.iteritems()换成classCount.items()即可