Python学习系列1:KNN算法

来源:互联网 发布:慧心莲禅服 淘宝 编辑:程序博客网 时间:2024/05/19 04:54

         本文出至  机器学习实战  这本书

         算法使用的数据来至于 ML in Action 这本书提供的,算法也是,变成环境是在Eclipse,相关环境配置看我的上一篇博文 《Python学习系列0:配置Eclipse进行机器学习算法的准备工作》

         这本系列记录了我在机器学习过程中的点滴,主要注释放在了代码中,系列不是为了书本的重复,更多的是自己 Action 中的 accumulation。


        KNN 算法是机器学习中的有监督学习算法,该算法的优点是:分类算法中简单、有效的算法(有效2字我并不这么认为,因为我还没有与别的算法比较),理解起来比较简单;缺点是:1. 计算复杂度高,待分类特征向量需要与训练样本集中的每一个样本的向量进行比较;   2. KNN算法并不能反映出 训练数据集  中 内在结构信息,比如说训练样本集中特征的均值信息、分布律等其他的各种特征,在一些其他优秀的机器学习算法可以利用这些信息或者对距离进行一些优化。


         该算法总体比较简单,思想是:

             1. 待测样本的  特征向量 放在 numpy表示的  Matrix 中

             2. 提取出测试样本的特征  放在 mat 中,并且将这些测试样本的分类放在labels的array中

             3. 对带测试样本  和  训练集  的数据进行归一化  ( x-min) / (max-min)

             4. 比较每一条待分类样本特征向量与训练样本集中每个样本的距离,这个距离是有欧式距离标定的(你也可以使用其他的方式)

             5. 找到待测试验本与训练集的距离(即 相似度) 最高的 前 K 个 训练集的样本

             6 找到这k 个训练样本的 Label(比如label中有A,B 两类), 统计K个样本的label ,A有 3个,B 有1 个,则认为待测试样本的分类为A

         

         机器学习分类算法的一般步骤为:

         1. 准备数据

         2. 将数据表示成算法能够处理的形式

         3. 写出   分类算法

         4. 将训练样本  带入到   分类算法中进行训练

          5.将测试样本带入到  分类算法中  测试,如果满意

          6 将待分类样本  代入到 分类算法中 进行 预测




            我在eclipse 中是采取 包的方式   进行不同算法的管理,如上图所示

                     1. 我将KNN算法放在了 KNN的包中

                     2. 测试样例 我放在了  KNN_test.py 中

                         KNN 分类算法、数据准备函数 我放在了model 文件 : mKNN.py中

                         尽力实现 测试 和 代码 分离的方式

                        数据都是放在D:/data/python/*** 路径下

                      3. 通过   书写这个 工程,让我  练习了 python 

                      4. 我要将我 的代码  放在gitHub 上

以下是我的代码:

 KNN_test.py

# -*- coding:utf-8 -*-from KNN.mKNN import * import matplotlibimport matplotlib.pyplot as plt########### 用模拟数据  做KNN 实验group,labels = createDate()       #创建实验所需的数据集print(group)print(labels)a = classify0([0,0], group, labels,3)          #  调用KNN 的分类方法print(a)        # 获得所属的类型#######    读取  dataSet.txt   进行KNN分类   datingDataMat,datingLabels = file2matrix("D:\Data\python\datingTestSet2.txt")print(datingDataMat)               print(datingLabels[0:30])#  把数据点  画出来fig = plt.figure()ax = fig.add_subplot(111)ax.scatter(datingDataMat[:,1],datingDataMat[:,2])#plt.legend()plt.xlabel(u"飞行里程")plt.ylabel(u"看电影时间")plt.show()                #  必须把 画的图 关闭了  才可以进行后续的处理#对   数据集  进行 归一化NordataMat ,rangs, minVals = autoNorm(datingDataMat)print(NordataMat)# 准备  KNN 分类器 可以使用的  数据# start = time.time()datingClassTest("D:\Data\python\datingTestSet2.txt")#  k = 3 errorRate = 5%#  k = 4 errorRate = 4%########    写一个真实  的应用程序   进行相亲的  配对classifyPerson("D:\Data\python\datingTestSet2.txt")#直接在控制台输入      10 10000 0.5 就可以了得到结果############# 对   手写体图片 进行  KNN 分类#测试一下 图片到向量start = time.time()vet = img2vec('D:\\Data\\python\\digits\\testDigits\\0_0.txt')  # 使用  \\ 是为了避免转义字符!  \t \0 都是转义字符#print(vet[0,32:64])handwriteClassify("D:\\Data\\python\\digits\\testDigits", "D:\\Data\\python\\digits\\trainingDigits")ends = time.time() - startprint("一共消耗了 %.2f" %(ends))

在该注释的地方,我已经注释了

我用的是python 3.3 的环境,我在上一篇博文也介绍了  怎么  加入 3方包


mKNN.py:

# -*- coding:utf-8 -*-from numpy import *import operatorimport time   # 获得当前时间,用于计时from operator import itemgetterfrom pip.backwardcompat import raw_inputfrom os import listdir# 这个模块是KNN 算法的 各种函数#  创建  实验的  模拟数据集def createDate():    group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])    labels = ['A','A','B','B']    return group,labels#  KNN 分类器    intX 是输入测试数据的特征向量   dataSet 是训练样本集,labels 标签向量 ,  k 是选择最邻近的数目def  classify0(intX, dataSet, labels, k):    dataSetSize = dataSet.shape[0]                                  # 获得 有多少行     difMat = tile(intX, (dataSetSize,1)) - dataSet               # tile( ) 函数的用法    sqDiffMat = difMat**2    sqDistances = sqDiffMat.sum(axis=1)        distance = sqDistances**0.5    sortedDistIndecies = distance.argsort()    classCount = { }                    # 声明为一个 dic 类型      for i in range(k):        voteIlabel = labels[sortedDistIndecies[i]]                                    #取出前n个距离最小的label值        classCount[voteIlabel] = classCount.get(voteIlabel,0) +1            #如果没有    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)    # sorted 就是一个方法,里面穿值   3.3 版本中  classCount.items()  代替 classCount.iteritems()---应该已经弃用了  其实只要是iterable() 就可以的    return sortedClassCount[0][0]       # 读取  txt文本文件  的样本数据def  file2matrix(filename):      fr  = open(filename)    arrayOLines = fr.readlines()    numberOfLines = len(arrayOLines)    returnMat = zeros((numberOfLines,3))  # 使用的numpy的  zeros()   numberOfLines*3  的 零矩阵  3 是固定好的,可以通过 split 函数确定    classLabelVector = [ ]    index = 0     for line in arrayOLines:        line = line.strip()        listFromLine = line.split('\t')        returnMat[index,:] = listFromLine[0:3]        classLabelVector.append(int(listFromLine[-1]))        index += 1    return returnMat, classLabelVector# 数据的归一化def autoNorm(dataSet):    minVals = dataSet.min(0)             # 得到的是  列     中的最小值    是一个向量 Vector    maxVals = dataSet.max(0)    ranges = maxVals - minVals    NorMat = zeros(shape(dataSet))    m = dataSet.shape[0]    NorMat = dataSet - tile(minVals,(m,1))    NorMat = NorMat/tile(ranges,(m,1))    return NorMat,ranges,minVals# Test the KNN classify algorithm  测试 KNN 算法# 可以通过改变  hosRate  K 来观测不同的  错误率大小def datingClassTest(filename):      start = time.time()    hosRate = 0.10            # 选择 hosRate 比例作为  测试数据    dataMat,dataLab = file2matrix(filename)    norMat, ranges, minVals = autoNorm(dataMat)    testNum = int(dataMat.shape[0]*hosRate)    totNum = dataMat.shape[0]    errorRate = 0.0    for i in range(testNum):        # 选择 前  testNum 个样本作为测试数据, 后面 testNum-totNum 作为 训练样本     K 选择  3         classRes = classify0(norMat[i,:], norMat[testNum:totNum,:], dataLab[testNum:totNum], 5)            print("the classify result is %d, the real result is %d" %(classRes,dataLab[i]) )        if(classRes != dataLab[i]):            errorRate += 1.0    print("the error Rate is %.2f %%" %((errorRate/testNum)*100))    comTime = time.time() - start     print("一共耗时 %0.2f s" %(comTime))            # 真实的应用  程序                     主要是对   输入  输出 函数的   练习 def classifyPerson(filename):    resultValue = ['little','small does','large does']    game = float(raw_input("how many hours you play games?"))    fly = float(raw_input("How many kilometers you fly?"))    iceCream = float(raw_input("How many iceCream you eat?"))    personVec = array([game,fly,iceCream])    dataSet,dataLab = file2matrix(filename)    norMat,ranges,minVals = autoNorm(dataSet)    classRes = classify0((personVec-minVals)/ranges, norMat, dataLab, 3)    print("The person is %s",resultValue[classRes-1])# 对指定文件名下的图片转化为向量  准备数据  def img2vec(filename):    returnVec = zeros((1,1024))    fr = open(filename)    numLine = fr.readlines()    m = len(numLine)    for i in range(m):        line = numLine[i]        line = line.strip()           # strip() 去掉 每一行的  换行符  等        for j in range(len(line)):            returnVec[0,i*m+j]=int(line[j])    return returnVec#  测试 手写题的def handwriteClassify(dirtest,dirtrain):    hwLabels = []    trainfilelist = listdir(dirtrain)    m = len(trainfilelist)    returnMat =zeros((m,1024))  # 扩展 结果矩阵    1024  可以通过读取第一个文件 得到    for i in range(m):        filenamestr = trainfilelist[i]        filename = filenamestr.split('.')[0]        hwtype = filename.split('_')[0]        hwLabels.append(hwtype)        fileloc = dirtrain+"\\"+filenamestr        returnMat[i,:] = img2vec(fileloc)    # 解析  testdir    errNum = 0.0    testfilelist = listdir(dirtest)    n = len(testfilelist)    for j in range(n):        filenamestr = testfilelist[j]        filename = filenamestr.split('.')[0]        filetype = filename.split('_')[0]        fileloc = dirtest +"\\"+filenamestr        returnVec = img2vec(fileloc)        classtype = classify0(returnVec, returnMat, hwLabels, 3)        if(classtype != filetype):            errNum += 1    print("error rate is :%f" % (errNum/n))


       通过对KNN 对  手写体识别 的计算还是有些慢,一开始我以为程序死了

          后来加入 time 包查看  运行时间,  发现 对4000多条 的数据进行比较  用了40多秒!!

----------------------------------------------------------------------------------------------------------------------------------------------------------------

 让我收获的感觉是:

         1.  原来 Python  写  ML 的代码可以这么优美 , 易于构建,解析文件也很给力

         2.  自己对  第三方包   的熟悉程度不够

         3.  需要  根据  作者的思想   自己构建  算法,  而不是 照本宣科 的coding  

                                                                                                                                                                                          --------------------------------- edit  by   Jamin   

    

0 0
原创粉丝点击