Python3.7机器学习第一章k-近邻算法代码详细注释

强迫症一点点。代码注释很详细。第一次用这个。。。。

#k-近邻算法示例代码
from numpy import *
import operator
from os import listdir    #列出给定目录的文件名
import matplotlib
import matplotlib.pyplot as plt

#定义样本
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

#简单分类器
def classify0(inX,dataSet,labels,k):             #4个输入参数:用于分类的输入向量是inX,输入的训练样本集为dataSet,向量标签为labels,k表示用于选择最近邻居的数目,标签向量数域矩阵dataSet的行数相同
    dataSetSize=dataSet.shape[0]                 #.shape[0]返回的是矩阵的行数(一维的长度),.shpae[1]返回的是矩阵的列数(二维的长度)
    diffMat=tile(inX,(dataSetSize,1))-dataSet    #tile函数参数:inX这个整体,在行上(行变)重复dataSetSize次,列上重复1次
    sqDiffMat=diffMat**2                         #数组类型(array)的平方表示每个元素进行单独平方,而矩阵类型(matrix)的平方表示矩阵的数乘运算
    sqDistances=sqDiffMat.sum(axis=1)            #axis=1矩阵中按行的方向相加并返回每一行的和值(行相同,列不同),axis=0是在列上操作(列相同,行不同)
    distances=sqDistances**0.5                   #距离的平方进行开方
    sortedDistIndicies=distances.argsort()       #argsort(a)返回a数组元素从小到大排序后的原来元素的下标排序
    classCount={}                                #定义一个空字典
    for i in range(k):                           #选择距离最小的k个点
        voteIlabel=labels[sortedDistIndicies[i]]
        classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
    sortedClassCount=sorted(classCount.items(),  #classCount.items()函数返回字典的一个迭代器,reverse的布尔值设置是否为倒序,默认为从小到大,itemgetter是获取第1个域的值
                            key=operator.itemgetter(1),reverse=True)#这里对classCount.iteritems()作修改,python3中将迭代器改为:items()
    return sortedClassCount[0][0]

#文件解析
def file2matrix(filename):
    fr=open(filename)
    arrayOLines=fr.readlines()                   #将文件列表化,每一行为一个列表元素
    numberOfLines=len(arrayOLines)               #获得列表元素个数,即文件行数
    returnMat=zeros((numberOfLines,3))           #np.zeros((n)):创建一个一维数组有n个元素,并初始化为0;np.zeros((n,m)):初始化一个n×m的数组类型矩阵,并初始化为0
    classLabelVector=[]                          #声明一个空列表
    fr=open(filename)
    index=0
    for line in arrayOLines:          
        line=line.strip()                        #strip()方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列,但不能移除串内的符号
        listFromLine=line.split('\t')            #以原文中的'\t'为标准划分字符数组元素,可设置第二个参数指定划分个数,从0开始计数1
        returnMat[index,:]=listFromLine[0:3]     #将每行的前三个放入矩阵,mat[index,:]是取第index行,mat[:,index]是取第index列
        classLabelVector.append(int(listFromLine[-1]))   #在列表末尾添加元素(此处添加的是字符串数组每个元素的最后一个)
        index+=1                                 #矩阵行数加一移动
    return returnMat,classLabelVector
#listFromLine=list(map(float,listFromLine))   #这句话可以将字符串类型的数字转换为标准数字类型

#归一化数值
def autoNorm(dataSet):
    minVals=dataSet.min(0)                       #取得列中的最小值,minVals是一个数组
    maxVals=dataSet.max(0)                       #取得列中的最大值,maxVals是一个数组
    ranges=maxVals-minVals                       #取得范围值
    normDataSet=zeros(shape(dataSet))            #初始化一个和给定数组类型矩阵一样形状的数组矩阵,元素全部为0
    m=dataSet.shape[0]                           #得到数组矩阵的行数
    normDataSet=dataSet-tile(minVals,(m,1))      #和下一行按照newValu=(oldValue-min)/(max-min)计算新的数组矩阵
    normDataSet=normDataSet/tile(ranges,(m,1))
    return normDataSet,ranges,minVals

#分类器对约会网站的测试代码                       
def datingClassTest():                           
    hoRatio=0.10                                 #测试量10%
    datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')    #获得评估项目矩阵和结果列表
    normMat,ranges,minVals=autoNorm(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("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)))
#datingClassTest()

#约会网站测试函数
def classifyPerson():
    resultList=['not at all','in small does','in large does']      #字符列表,将标识数字转换为人可见分类(相当于第一个函数里面的Labels[])
    percentTats=float(input("percentage of time spent playing vedio games?"))   #以下三行输入检测数据
    ffMiles=float(input('frequent filer miles earned per year?'))
    iceCream=float(input('liters of icecream consumed per year?'))
    datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')   #对样本进行检测,得到分类标准
    normMat,ranges,minVals=autoNorm(datingDataMat)                 #归一化数据
    inArr=array([ffMiles,percentTats,iceCream])                    #将输入的数据列表化
    classifierResult=classify0((inArr-minVals)/ranges,normMat,datingLabels,3)    #将输入的数据归一化并对其分类处理
    print('you will probably like this person: ',resultList[classifierResult-1]) #得到分类结果

#手写识别对象(数字转换为可读的向量形式,转换为矩阵识别)
def img2vector(filename):
    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():
    hwLabels=[]                             #创建一个列表,用于记录分类
    trainingFileList=listdir('trainingDigits')   #列出给定目录的文件名(不包括子目录,但是得到的文件名包含文件类型,即包括文件名的后缀)
    m=len(trainingFileList)                 #获得给定目录下的文件数量
    trainingMat=zeros((m,1024))             #创建一个m*1024的数组类型矩阵
    for i in range(m):                      #文件遍历
        fileNameStr=trainingFileList[i]     #开始逐个访问文件名
        fileStr=fileNameStr.split('.')[0]   #将文件名和后缀名分开并去文件名
        classNumStr=int(fileStr.split('_')[0])  #理解文件命名方式:1_111.txt,“1”表示中是手写的1,“111”表示这是第111个手写体样本,以“_”划分字符数组并取文件表示的数字是几,并将字符转换为int类型
        hwLabels.append(classNumStr)        #在列表末尾添加取到的数字
        trainingMat[i,:]=img2vector('trainingDigits/%s'%fileNameStr)   #将得到的0,1数字列表赋值给trainingMat的第i行,后面的参数列表可以等同于print()的输出列表形式。
    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)   #trainingMat和hwLabels里面的东西是一一对应的,是0,1序列和其所表示的数字的映射关系。这里挑分类器认为最接近的三个结果
        print("the classifier came back with: %d,the real answer is: %d"%(classifierResult,classNumStr))  #打印分类器判断结果和真实结果
        if(classifierResult!=classNumStr):errorCount+=1.0                    #错误数目计算
    print("\nthe total number of errors is:%d"%errorCount)                   #打印判断错误的数量
    print("\nthe total number of rate is:%f"%(errorCount/float(mTest)))      #打印错误率
        

猜你喜欢

转载自blog.csdn.net/qq_43078427/article/details/86490247