机器学习实战第二章——KNN算法(源码解析)

#coding=utf-8  
''''' 
Created on 2015年12月29日 

@author: admin 
'''  
from numpy import array  
from numpy import tile  
from numpy import zeros  
import operator  
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  

# 对新数据进行分类  
def classify0(inX,dataSet,labels,k):  
    #dataSet.shape[0]是dataSet第一维的数目  
    dataSetSize = dataSet.shape[0]   
    #要分类的新数据与原始数据做差  
    diffMat = tile(inX,(dataSetSize,1)) - dataSet  
    #求差的平方  
    sqDiffMat = diffMat**2  
    #求差的平方的和  
    sqDistance = sqDiffMat.sum(axis=1)   
    #求标准差  
    distances = sqDistance**0.5  
    #距离排序  
    sortDistIndicies = distances.argsort()   
    #定义元字典  
    classCount = {}   
    #遍历前k个元素  
    for i in range(k):  
        #获得前k个元素的标签  
        voteIlabel = labels[sortDistIndicies[i]]  
        #计算前k个数据标签出现的次数  
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1   
    #对得到的标签字典按降序排列  
    sortedClassCount =sorted(classCount.iteritems(),key = operator.itemgetter(1),reverse = True)  
    #返回出现次数最多的标签  
    return sortedClassCount[0][0]  

# 读取文本文件中的数据  
def file2matrix(filename):  
    # 打开文件  
    fr = open(filename)  
    # 计算文本文件的行数  
    numberOfLines = len(fr.readlines())  
    # 创建返回的数据矩阵  
    returnMat = zeros((numberOfLines,3))  
    # 创建类标签  
    classLabelVector = []  
    # 打开文件  
    fr = open(filename)  
    # 定义索引  
    index = 0  
    # 读取文件的每一行并处理  
    for line in fr.readlines():  
        # 去除行的尾部的换行符  
        line = line.strip()  
        # 将一行数据按空进行分割  
        listFromLine = line.split('\t')  
        # 0:3列为数据集的数据  
        returnMat[index,:] = listFromLine[0:3]  
        # 最后一列为数据的分类标签  
        classLabelVector.append(int(listFromLine[-1]))  
        # 索引加1  
        index += 1  
    # 返回数据集和对应的类标签  
    return returnMat,classLabelVector  

# 归一化函数  
def autoNorm(dataSet):  
    # 求数据矩阵每一列的最小值  
    minVals = dataSet.min(0)  
    # 求数据矩阵每一列的最大值  
    maxVals = dataSet.max(0)  
    # 求数据矩阵每一列的最大最小值差值  
    ranges = maxVals - minVals  
#    normDataSet = zeros(shape(dataSet))  
    # 返回数据矩阵第一维的数目  
    m = dataSet.shape[0]  
    # 求矩阵每一列减去该列最小值,得出差值  
    normDataSet = dataSet - tile(minVals,(m,1))  
    # 用求的差值除以最大最小值差值,即数据的变化范围,即归一化  
    normDataSet = normDataSet / tile(ranges,(m,1))  
    # 返回归一化后的数据,最大最小值差值,最小值  
    return normDataSet,ranges,minVals  

# 分类器测试函数  
def datingClassTest():  
    # 测试集所占的比例  
    hoRatio = 0.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],2)  
        # 输出分类结果和实际的类别  
        print "the classifer came back with: %d,the real answer is: %d" %(classifierResult,datingLabels[i])  
        # 如果分类结果与实际结果不一致  
        if(classifierResult != datingLabels[i]):  
            # 误分类数加1  
            errorCount += 1.0  
    # 输出错误率  
    print "the total error rate is: %f" %(errorCount/float(numTestVecs))  

# 对人分类  
def classiyPerson():  
    # 定义分类结果的类别  
    resultList = ['not at all','in small doses','in large doses']  
    # 读取输入数据  
    percentTats = float(raw_input("percentage of time spent playing video games?"))  
    # 读取输入数据  
    ffMiles = float(raw_input("frequent flier miles earned per year?"))  
    # 读取输入数据  
    iceCream = float(raw_input("liters of ice cream consumed per year?"))  
    # 从文件中读取已有数据  
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')  
    # 对数据进行归一化  
    normMat,ranges,minVals = autoNorm(datingDataMat)  
    # 将单个输入数据定义成一条数据  
    inArr =array([ffMiles,percentTats,iceCream])  
    # 对输入数据进行分类  
    classifierResult = classify0(inArr,datingDataMat,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()  
        # 对读取数据赋值到returnVect中  
        for j in range(32):  
            returnVect[0,32*i+j] = int(lineStr[j])  
    # 返回向量  
    return returnVect  
# 手写字符识别测试  
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中  
        hwLabels.append(classNumStr)  
        # 把文件变成向量并赋值到trainingMat中  
        trainingMat[i,:] = img2vector('digits/trainingDigits/%s' % fileNameStr)  
    # 列出测试目录下的所有文件  
    testFileList = listdir('digits/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('digits/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 "\nthe total number of errors is:%d" % errorCount  
    # 输出分类的错误率  
    print "\nthe total error rate is:%f" % (errorCount/float(mTest))  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值