zoukankan      html  css  js  c++  java
  • kNN--近邻算法

    kNN--近邻算法

       kNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。

    在机器学习中常用于分类。

    数学内容:

      欧氏距离公式,矩阵运算,归一化数值

    python模块:

      numpy,operator(用其中的itemgetter做排序),listdir(列出目录中的文件),matplotlib.pyplot(可视化数据分析数据),

      PIL(对图片进行处理)

    from numpy import *
    import operator
    from os import listdir
    
    def createDataSet():
        groups=array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
        lables=['A','A','B','B']
        return groups,lables
    
    #k-近邻算法
    def classify0(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
        #按距离递增排列,返回样本集中的index
        sortedDistances=distances.argsort()
        classCount={}
        for i in range(k):
            #根据距离递增的顺序,获取与其对应的类别(即目标变量)
            voteIlabel=labels[sortedDistances[i]]
            #为k个元素所在的分类计数
            classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
        #通过对比每个类别出现的次数(即classCount value),以递减的顺序排序    
        sortedCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
        #返回计数最大的那个类别的值
        return sortedCount[0][0]    
    
    #准备数据
    def file2matrix(filename):
        fr=open(filename)
        arrayOLines=fr.readlines()
        #获取文件行数
        numberOflines=len(arrayOLines)
        #创建一个以文件行数为行,3列的矩阵
        returnMatrix=zeros((numberOflines,3))
        #定义一个存放目标变量(类别)的数组
        classLabelVector=[]
        index=0
        #遍历文件
        for line in arrayOLines:
            line=line.strip()
            listFromLine=line.split('	')
            #把文件前三列添加到返回的矩阵中
            returnMatrix[index:]=listFromLine[0:3]
            #文件最后一列(对应的类别)添加到类别数组中
            classLabelVector.append(int(listFromLine[-1]))
            index+=1
        #返回数据特征矩阵和类别数组    
        return returnMatrix,classLabelVector
    
    #通过公式 "newValue=(oldValue-min)/(max-min)" 将任意取值范围的特征值转化为0到1区间内的值
    def autoNorm(dataset):
        #返回每列的最小值
        minVals=dataset.min(0)
        #返回每列的最大值
        maxVals=dataset.max(0)
        #返回最大值与最小值的差
        ranges=maxVals-minVals
        #创建与dataset同行同列的0矩阵
        normDataset=zeros(shape(dataset))
        #返回dataset的行数
        m=dataset.shape[0]
        #创建一个重复m次的minVals矩阵,并与dataset相减
        normDataset=dataset-tile(minVals,(m,1))
        #newValue=(oldValue-min)/(max-min)
        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
        #向k-近邻算法中传numTestVecs个测试数据,并把返回的预测数据与真实数据比较返回,若错误,计数器加1
        for i in range(numTestVecs):
            """
            调用k-近邻算法,为其传入参数,
            normMat[i]:第i个测试数据,
            normMat[numTestVecs:m,:]:从numTestVecs到m个样本数据,(m可以不写,相当于从numTestVecs索引开始,取剩下所有的normMat数据)
            datingLabels[numTestVecs:m]:从numTestVecs到m个样本数据对应的标签
            3:k的值
            """
            classifierResult=classify0(normMat[i],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
            #判断预测数据与真实数据,如果是错误的,则以红字体输出,并错误预测计数器加1
            if (classifierResult!=datingLabels[i]): 
                print("33[0;31mthe classifier came back with: %d, the real answer is: %d33[0m" % (classifierResult, datingLabels[i]))
                errorCount+=1.0
            else:
                print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]))
        print("the total error rate is:%f" %(errorCount/float(numTestVecs)))
    
    #约会系统
    def classifiyPerson():
        #设定分类(标签)列表
        resultList=["not at all", "in small doses", "in large doses"]
        #提示用户输入相应内容
        percentTats=float(input("percentage of time spent playing video games?"))
        ffMiles=float(input("frequent filer miles earned per year?"))
        iceCream=float(input("liters of ice cream consumed per year?"))
        #把用户输入的三个特征值格式化成numpy.array数据类型
        inArr=array([ffMiles,percentTats,iceCream])
        #准备样本数据及对应标签
        datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
        #归一化样本数据并返回ranges和minVals,以便归一化用户输入的数据
        normMat,ranges,minVals=autoNorm(datingDataMat)
        #调用k-近邻算法,并把传入的预测数据特征做归一化
        classifierResult=classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
        #打印出预测出的类别,因为样本数据中的类别(标签)为1,2,3,其index是0,1,2,所以要用预测出的分类(1,2,3)减1
        print("You will probably like this person: %s" %(resultList[classifierResult-1]))
    
    #将32x32的二进制图像文件转换成1x1024的向量
    def img2vector(filename):
        #创建一个1x1024的0矩阵
        returnVect=zeros((1,1024))
        fr=open(filename)
        """
        因为已知文件是32x32,即有文件中32行内容,通过readline()方法遍历文件,得到文件的每行内容lineStr
        再遍历每行内容lineStr,并把遍历出的内容添加到returnVect矩阵里
        """
        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('digits/trainingDigits')
        #得到文件个数,也就是训练数据的行数
        m=len(trainingFileList)
        #创建一个m行,1024列的0矩阵
        trainingMat=zeros((m,1024))
        """
        通过遍历所有训练文件,得到文件名,其对应的数字(eg:0_7.txt),并把数字添加到hwLabels集合,
        通过上面的img2vector函数,得到一个与该文件对应的1x1024矩阵,并添加到trainingMat矩阵中
        """
        for i in range(m):
            fileNameStr=trainingFileList[i]
            fileStr=fileNameStr.split('.')[0]
            classNumStr=int(fileStr.split('_')[0])
            hwLabels.append(classNumStr)
            trainingMat[i,:]=img2vector('digits/trainingDigits/%s' % fileNameStr)
        #对测试数据做同样的操作    
        testFileList=listdir('digits/testDigits')
        mTest=len(testFileList)
        errorCount=0.0
        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)
            if (classifierResult!=classNumStr):
                print("33[0;31mthe classifier came back with: %d, the real answer is: %d33[0m" % (classifierResult,classNumStr))
                errorCount+=1
            else:
                print("the classifier came back with: %d, the real answer is: %d" %(classifierResult,classNumStr))
        print("
    the total number of errors is: %d" % errorCount)
        print("
    the total error rate is: %f" %(errorCount/float(mTest)))
    
    #在网上找数字图片做测试
    def imgNumClassTest(filename):
        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.append(classNumStr)
            trainingMat[i,:]=img2vector('digits/trainingDigits/%s' % fileNameStr)
        vectorUnderTest=img2vector(filename)
        classifierResult=classify0(vectorUnderTest,trainingMat,hwLabels,3)
        print(classifierResult)

    约会网站案列数据分析代码:

    """
    分析数据
    """
    
    import kNN
    from numpy import *
    import matplotlib
    import matplotlib.pyplot as plt
    
    datingDataMat,datingLabels=kNN.file2matrix('datingTestSet2.txt')
    #创建一个图片窗口,默认是1(figure1)
    fig=plt.figure()
    #在图片窗口创建两行一列的子图,并使用第一行第一列,即211的含义
    ax1=fig.add_subplot(211)
    """
    创建散点图,x轴是datingDataMat第一列的数据,y轴是datinDataMat第二列的数据,
    后面两个参数一个代表颜色,一个代表点的大小,两个参数同时放大15倍,然后这个时候就是同一个label用一种颜色和大小表示出来,
    不同的label的点的大小和颜色会不一样。
    """
    ax1.scatter(datingDataMat[:,1],datingDataMat[:,2],15*array(datingLabels),15*array(datingLabels))
    #设置x轴标签
    plt.xlabel('Play game takes time')
    #设置y轴标签
    plt.ylabel('Eat ice-cream')
    
    #在图片窗口中使用第一行第二列
    ax2=fig.add_subplot(212)
    #把datingLabels转成numpy.array类型
    datingLabels=array(datingLabels)
    #取datingLabels中值等于1的index
    idx_1=where(datingLabels==1)
    #idx_1即datingTestSet2.txt文件中第四列值为1的行数,则获取idx_1行,第一二列的数据创建散点图,为这些点设置颜色,大小,label
    p1=ax2.scatter(datingDataMat[idx_1,0],datingDataMat[idx_1,1],color = 'm', label='Hate', s = 50)
    idx_2=where(datingLabels==2)
    p2=ax2.scatter(datingDataMat[idx_2,0],datingDataMat[idx_2,1],color = 'c', label='General', s = 30)
    idx_3=where(datingLabels==3)
    p3=ax2.scatter(datingDataMat[idx_3,0],datingDataMat[idx_3,1],color = 'r', label='Like', s = 10)
    plt.xlabel('Flying')
    plt.ylabel('Play game takes time')
    #创建图示放置在左上角
    plt.legend(loc='upper left')
    #显示图片
    plt.show()

    手写数字识别系统图片转文本文件代码:

    from PIL import Image
    import numpy as np
    import matplotlib.pyplot as plt
    
    
    def img2txt(img_path, txt_name):
        """
        将图像数据转换为txt文件
        :param img_path: 图像文件路径
        :type txt_name: 输出txt文件路径
        """
    
        #把图片转成二值图像,并设长宽均为32
        im = Image.open(img_path).convert('1').resize((32, 32))  # type:Image.Image
        #plt.imshow(im)
        #plt.show()
        
        #将上面得到的图像转成array数组
        data = np.asarray(im)
        #将上面得到的数组保存在到文本文件中,指定存储数据类型为整型,分隔符
        np.savetxt(txt_name, data, fmt='%d', delimiter='')
  • 相关阅读:
    java io系列23之 BufferedReader(字符缓冲输入流)
    java io系列22之 FileReader和FileWriter
    java io系列21之 InputStreamReader和OutputStreamWriter
    java io系列20之 PipedReader和PipedWriter
    java io系列19之 CharArrayWriter(字符数组输出流)
    java io系列18之 CharArrayReader(字符数组输入流)
    java io系列17之 System.out.println("hello world")原理
    java io系列16之 PrintStream(打印输出流)详解
    java io系列15之 DataOutputStream(数据输出流)的认知、源码和示例
    java io系列14之 DataInputStream(数据输入流)的认知、源码和示例
  • 原文地址:https://www.cnblogs.com/tuokid/p/10088268.html
Copyright © 2011-2022 走看看