机器学习实战第二章kNN算法详解

来源:互联网 发布:手机画图软件排行 编辑:程序博客网 时间:2024/06/06 03:09
from numpy import *
import operator
from os import listdir


#2.1.2 k-近邻算法
def classify0(inX, dataSet, labels, k):    #inX:分类的输入向量,dataSet:输入的训练样本集,labels:标签向量,k:选择最近邻居数量
    dataSetSize = dataSet.shape[0]          #读取训练样本集的一维长度
    diffMat = tile(inX, (dataSetSize,1)) - dataSet
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)    #每一个样本集与输入向量距离的平方值
    distances = sqDistances**0.5             #求出各个训练集与输入向量的距离,并以数组形式存储在变量distance中
    sortedDistIndicies = distances.argsort()    #将distance中的元素从小到大排列,提取其对应的index(索引),然后输出到sortedDistIndicies中      
    classCount={}                           
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1   #对距离最小的k个点添加标签并以字典方式存储在classCount中
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)#对字典内的元祖按照降序第二个元素(标签所对应元素的频率)排列存储在数组sortedClassCount中(此时字典内的键为标签,值为对应标签的频率)
    return sortedClassCount[0][0]       #返回频率最高的元素标签


 #2.1.1 创建数据集和标签
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
    
#2.2.1   从文本中解析数据
def file2matrix(filename):          
    fr = open(filename)                         #打开文件
    numberOfLines = len(fr.readlines())         #获得文件行数
    returnMat = zeros((numberOfLines,3))        #创建一个全部为0名称为returnMat的矩阵
    classLabelVector = []                       #创造一个空向量来存储数据,当作方法结束返回向量 
    fr = open(filename)                         
    index = 0
    for line in fr.readlines():
        line = line.strip()                     #截取回车字符
        listFromLine = line.split('\t')         #将上一步得到的数据分割为元素列表
        returnMat[index,:] = listFromLine[0:3]  #每三个元素为一组存储到特征矩阵中
        classLabelVector.append(int(listFromLine[-1]))  #通过索引值-1将列表的最后一列元素存储到向量classLabelVector中
        index += 1                                  
    return returnMat,classLabelVector
    
#2.2.3 归一化特征值    
def autoNorm(dataSet):
    minVals = dataSet.min(0)                #minVals 每一列的最小值
    maxVals = dataSet.max(0)                #maxVals 每一列的最大值
    ranges = maxVals - minVals              
    normDataSet = zeros(shape(dataSet))     #创建一个长度为dataSet的维度值的0向量
    m = dataSet.shape[0]                    #读取dataSet的第一维长度存储在变量m中
    normDataSet = dataSet - tile(minVals, (m,1))    #将变量内容变成与输入矩阵同样大小的矩阵        
    normDataSet = normDataSet/tile(ranges, (m,1))   #特征值归一化公式
    return normDataSet, ranges, minVals
   
 #2.2.4 约会网站测试代码   
def datingClassTest():
    hoRatio = 0.10      #hold out 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)   #将以上取得的数据输入到kNN分类函数classify0中
        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 ("thr errorCount is: %d "  % errorCount)              #计算错误率并输出结果
    
    
#2.3.1 将图像转化为测试向量    
def img2vector(filename):
    returnVect = zeros((1,1024))        #创建一个1*1024的0向量
    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])     
        hwLabels.append(classNumStr)            #从文件名中切割出分类的数字并加入在向量hwLables中
        trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)    #用img2vector函数载入图像
    testFileList = listdir('testDigits')        #iterate through the test set
    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) #用classify0函数测试该目录下的每一个文件
        print ("the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr))
        if (classifierResult != classNumStr): errorCount += 1.0     #对错误数据进行统计
    print ("\ntotal numbers:  %d" % mTest)
    print ("\nthe total number of errors is: %d " % errorCount)
    print ("\nthe total error rate is: %f" % (errorCount/float(mTest)))         #输出结果
    
#handwritingClassTest()  
#datingClassTest()
原创粉丝点击