zoukankan      html  css  js  c++  java
  • knn算法(分类)-机器学习

    K最近邻(k-Nearest Neighbor,KNN)分类算法可以说是最简单的机器学习算法了。它采用测量不同特征值之间的距离方法进行分类。它的思想很简单:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。

    其算法描述如下:

    1)计算已知类别数据集中的点与当前点之间的距离;

    2)按照距离递增次序排序;

    3)选取与当前点距离最小的k个点;

    4)确定前k个点所在类别的出现频率;

    5)返回前k个点出现频率最高的类别作为当前点的预测分类。

    对于机器学习而已,Python需要额外安装三件宝,分别是Numpy,scipy和Matplotlib。前两者用于数值计算,后者用于画图。安装很简单,直接到各自的官网下载回来安装即可。安装程序会自动搜索我们的python版本和目录,然后安装到python支持的搜索路径下。反正就python和这三个插件都默认安装就没问题了。

    一般实现一个算法后,我们需要先用一个很小的数据库来测试它的正确性,否则一下子给个大数据给它,它也很难消化,而且还不利于我们分析代码的有效性。

    补充用python实现的代码,要给python装numpy和matplotlib库,建议直接装anaconda,装好了anaconda默认安装了spyder,里面集成了这两个库,比较方便。

    首先,我们新建一个kNN.py脚本文件,文件里面包含两个函数,一个用来生成小数据库,一个实现kNN分类算法。代码如下:

    # -*- coding: utf-8 -*-
    from numpy import * def createDataSet():#创建一个很小的数据库 group=array([[1.0,0.9],[1.0,1.0],[0.1,0.2],[0.0,0.1]]) labels=['A','A','B','B'] return group,labels #[1.2,1.0] def kNNClassify(newInput,dataset,labels,k):#knn算法核心 #先求数据库中每个点到所求点之间的距离 numSamples=dataset.shape[0] #获取数据库的行数 diff=tile(newInput,(numSamples,1))-dataset#使用tile函数迭代创建一个numSample行1列的array与dataset做差 squaredDiff=diff**2#diff中的每一个数都平方 squaredDist=sum(squaredDiff,axis=1)#每一行两数求和 distance=squaredDist**0.5#再开方 #再对距离进行排序 sortedDistIndices=argsort(distance)#argsort函数对distance中元素从小到大排序,返回序号 classCount={} #统计距离小于等于k的每个点的类别 for i in xrange(k): voteLabel=labels[sortedDistIndices[i]] classCount[voteLabel]=classCount.get(voteLabel,0)+1 maxCount=0 #找出离所求点最近的k个点中最多的类别 for key,value in classCount.items(): if maxCount<value: maxCount=value maxIndex=key #返回所求点的类型,算法到此结束 return maxIndex

      然后我们在命令行中或在建一个python文件这样测试即可:

    import kNN
    from numpy import *
    
    dataSet,labels=kNN.createDataSet()
    testX=array([0,0.05])
    k=3
    maxIndex=kNN.kNNClassify(testX,dataSet,labels,3)
    print maxIndex
    

      运行程序:此时点[0,0.05]最接近B类。

     应用:这里我们用kNN来分类一个大点的数据库,包括数据维度比较大和样本数比较多的数据库。这里我们用到一个手写数字的数据库,可以到这里下载。这个数据库包括数字0-9的手写体。每个数字大约有200个样本。每个样本保持在一个txt文件中。手写体图像本身的大小是32x32的二值图,转换到txt文件保存后,内容也是32x32个数字,0或者1.

    数据库解压后有两个目录:目录trainingDigits存放的是大约2000个训练数据,testDigits存放大约900个测试数据。

    编写kNN2.py:

    # -*- coding: utf-8 -*-
    from numpy import *
    import os
    def kNNClassify(newInput,dataset,labels,k):#knn算法核心
        #先求数据库中每个图像与所要分类图像像素值差的平方再开方,用这种计算方法表示距离(相似度)俗称欧氏距离
        numSamples=dataset.shape[0] #获取数据库的行数(即文件夹下的文件数)
        diff=tile(newInput,(numSamples,1))-dataset#使用tile函数迭代创建一个numSample行1列的array与dataset做差
        squaredDiff=diff**2#diff中的每一个数都平方
        squaredDist=sum(squaredDiff,axis=1)#每一行的数求和
        distance=squaredDist**0.5#再开方
        #再对距离进行排序
        sortedDistIndices=argsort(distance)
        classCount={}
        #统计距离为k的每个图像的类别(即统计相似度最小的k个图像所表示的数字)
        for i in xrange(k):  
            voteLabel = labels[sortedDistIndices[i]]  
            classCount[voteLabel] = classCount.get(voteLabel, 0) + 1
        
        maxCount=0            
        #找出离所求图像类别最近的k个图像中最多的类别       
        for key,value in classCount.items():
            if maxCount<value:
                maxCount=value
                maxIndex=key
        #返回所求图像的类型(类型即数字)
        return maxIndex
     
    #函数img2vector把一张32*32的图像转化成一行向量imgVector
    def img2vector(filename):
        rows=32
        cols=32
        imgVector=zeros((1,rows*cols))
        fileIn=open(filename)
        for row in xrange(rows):
            lineStr=fileIn.readline()
            for col in xrange(cols):
                imgVector[0,row*32+col]=int(lineStr[col])
        return imgVector
     
    #函数loadDataSet从文件夹中加载多个文件数据,python对文件数据流加载到内存的操作很方便,这里的代码可以仔细理解加记忆一下
    def loadDataSet():
        dataSetDir='/home/chao/Desktop/python_work/knn/'
        trainingFileList=os.listdir(dataSetDir+'trainingDigits')
        numSamples=len(trainingFileList)
        train_x=zeros((numSamples,1024))#使用zeros函数为train_x分配numSamples行,每行1024列,每行为一个图像转化后的数据,总共numSamples行
        train_y=[]#用来存放每个图像的真实值
        for i in xrange(numSamples):
            filename=trainingFileList[i]
            train_x[i,:]=img2vector(dataSetDir+'trainingDigits/%s'%filename)
            label=int(filename.split('_')[0])
            train_y.append(label)
        testingFileList=os.listdir(dataSetDir+'testDigits')
        numSamples=len(testingFileList)
        test_x=zeros((numSamples,1024))#同train_x,但这里表示的是测试图像文件的
        test_y=[]
        for i in xrange(numSamples):
            filename=testingFileList[i]
            test_x[i,:]=img2vector(dataSetDir+'testDigits/%s'%filename)
            label=int(filename.split('_')[0])
            test_y.append(label)
        return train_x,train_y,test_x,test_y
     
    #测试预测准确率
    def testHandWritingClass():
        print "第一步:加载数据。。。"
        train_x,train_y,test_x,test_y=loadDataSet()
         
        numTestSamples=test_x.shape[0]#返回待测试图像的个数
        print "数据加载完成"
        matchCount=0#用来表示预测正确的图像的个数
        #每个待测图像都要调用一次knn预测其值
        for i in xrange(numTestSamples):
            print i
            predict=kNNClassify(test_x[i],train_x,train_y,3)#这里k=3准确率达98.63%,如果改成k=1的话会达到98.97%
            if predict==test_y[i]:
                matchCount+=1
        accuracy=float(matchCount)/numTestSamples
        print matchCount#打印正确预测个数
        print "accuracy is:%.2f%%"%(accuracy*100)#打印正确预测准确率
    

    测试非常简单,编写一个main.py:

    # -*- coding: utf-8 -*-
    import kNN2
    kNN2.testHandWritingClass()
    

    然后运行main.py观察正确率:

    933个预测正确
    accuracy is:98.63%
    

     版权声明:原文地址http://www.cnblogs.com/lcbg/p/6491900.html

  • 相关阅读:
    18-行列式及其性质
    17-正交矩阵和Gram-Schmidt正交化
    14-正交向量与子空间
    centOS7.3 离线安装docker
    10-四个基本子空间
    使用vim打造python-ide
    09-线性相关性、基、维数
    python小实例
    Elasticsearch学习之ES节点类型以及各种节点的分工
    基于Kibana和ES的苏宁实时日志分析平台
  • 原文地址:https://www.cnblogs.com/lcbg/p/6491900.html
Copyright © 2011-2022 走看看