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

  • 相关阅读:
    Codeforces Round 546 (Div. 2)
    Codeforces Round 545 (Div. 2)
    Codeforces Round 544(Div. 3)
    牛客小白月赛12
    Codeforces Round 261(Div. 2)
    Codeforces Round 260(Div. 2)
    Codeforces Round 259(Div. 2)
    Codeforces Round 258(Div. 2)
    Codeforces Round 257 (Div. 2)
    《A First Course in Probability》-chaper5-连续型随机变量-随机变量函数的分布
  • 原文地址:https://www.cnblogs.com/lcbg/p/6491900.html
Copyright © 2011-2022 走看看