《机器学习实战》之k-近邻算法-使用sklearn

2022-08-07,,,,

之前直接使用python代码来实现了k近邻算法,但自己编写这么多的代码总归是有些繁琐,因而我们可以直接使用 轮子 来帮助我们,分分钟搞定这些算法。

1、Sklearn简介

sklearn全称是scikit-learn,是一个开源的基于python语言的机器学习工具包。它通过NumPy, SciPy和Matplotlib等python数值计算的库实现高效的算法应用,并且涵盖了几乎所有主流机器学习算法。sklearn有一个完整而丰富的官网,里面讲解了基于sklearn对所有算法的实现和简单应用,但是是英文的:http://scikit-learn.org/stable/index.html

在工程应用中,用python手写代码来从头实现一个算法的可能性非低,因为这样不仅耗时耗力,而且还不一定能够写出构架清晰,稳定性强的模型。在实际中,我们是分析采集到的数据,然后根据数据特征选择适合的算法,再去工具包中调用算法,调整算法的参数,获取需要的信息,从而实现算法效率和效果之间的平衡。而sklearn,正是这样一个可以帮助我们高效实现算法应用的工具包。

2、Sklearn的常用模块

sklearn对常用的机器学习方法进行了封装,常用的模块包括回归(Regression)、降维(Dimensionality Reduction)、分类(Classfication)、聚类(Clustering)等方法。这里,我们会主要简介分类方法的使用。

3、Sklearn的建模流程

sklearn的基本建模流程可以分为三步:

下面,按照这三步并以手写数字识别为例来进一步学习sklearn的使用。

4、使用Sklearn库实现手写数字识别

4.1 sklearn中k-近邻算法简介

要使用sklearn实现k近邻,我们可以使用其中的sklearn.neighbors模块。sklearn.neighbors中的具体函数方法如下:

使用其中的KNeighborsClassifier 函数就可以实现k-近邻算法了,该函数有8个参数,具体如下:

将其主要参数解释翻译成中文:

  • n_neighbors:int类型,默认为5。其为K-NN查询使用的邻居数,也就是k-NN的k的值,选取最近的k个点。
  • weights:str或可调用,默认是uniform,参数可以是uniform、distance,也可以是用户自己定义的函数。
  • uniform:是均等的权重,就说所有的邻近点的权重都是相等的。
  • distance:是不均等的权重,距离近的点比距离远的点的影响大。
  • 用户自定义的函数:接收距离的数组,返回一组维数相同的权重。algorithm:{‘auto’,‘ball_tree’,‘kd_tree’,‘brute’},快速k近邻搜索算法,默认参数为auto,相当于算法自己决定合适的搜索算法。除此之外,用户也可以自己指定搜索算法ball_tree、kd_tree、brute方法进行搜索。
  • brute:是蛮力搜索,也就是线性扫描,当训练集很大时,计算非常耗时时。
  • kd_tree:构造kd树存储数据以便对其进行快速检索的树形数据结构,kd树也就是数据结构中的二叉树。以中值切分构造的树,每个结点是一个超矩形,在维数小于20时效率高。
  • ball tree:是为了克服kd树高纬失效而发明的,其构造过程是以质心C和半径r分割样本空间,每个节点是一个超球体。
  • leaf_size:int类型,默认是30,这个是构造的kd树和ball树的大小。这个值的设置会影响树构建的速度和搜索速度,同样也影响着存储树所需的内存大小。需要根据问题的性质选择最优的大小。
  • p:int类型,默认为2。距离度量公式。p=1时,使使用曼哈顿距离;p=2时,使用欧氏距离;对于任意p,就是minkowski距离。
  • metric:字符串或可调用,默认为’minkowski。用于距离度量,默认度量是minkowski,也就是p=2的欧氏距离(欧几里德度量)。
  • metric_params:dict,默认=None。距离公式的其他关键参数,这个可以不管,使用默认的None即可。
  • n_jobs:int或None,默认=None。并行处理的个数,默认为1。如果为-1,那么CPU的所有cores都用于并行工作。

同时,KNeighborsClassifier 还有一些函数供我们使用

这里,我们主要会用到训练模型的函数fit,预测函数predict。其余的可以自己去官网阅读,这里不再一一赘述。

提醒:最近邻居算法中,如果发现两个邻居,邻居k+1和k具有相同距离但不同标签,
      则结果将取决于训练数据的排序。

4.2 数据处理

与前面一样,我们这里是用的简便的二进制图片。为了方便,其是以txt形式存储在文本中(与上一篇文章使用的是同一个数据集)。

数字2的一个的二进制表示文件

同样,首先定义一个函数用于将这个转换成1*1024的向量。

import numpy as np
import operator

def img2vector(filename):  #将图像转化为向量
    returnVect = np.zeros((1, 1024))  #创建 1*1024 的Numpy数组
    fr = open(filename)
    for i in range(32):  #循环读出文件的 前32行
        lineStr = fr.readline()
        for j in range(32):  #将每行的头32个字符值存储在Numpy数组中
            returnVect[0, 32*i+j] = int(lineStr[j])
    return returnVect

4.3 使用sklearn库实现算法

接下来就可以编写主要的代码了。在这里面,我们先读取训练集trainingDigits文件夹,并从文件名中解析出该文件实际表示的数字,同时,使用img2vector函数将文件转化为1*1024的向量。

from os import listdir
from sklearn.neighbors import KNeighborsClassifier as kNN

def handwritingClassTest():
    hwLabels = []
    trainingFileList = listdir('trainingDigits')  #load the training set--- 获取训练集文件夹下的文件目录
    m = len(trainingFileList)  #获得文件个数
    trainingMat = np.zeros((m, 1024))
    for i in range(m):  #从文件名解析分类的数字
        fileNameStr = trainingFileList[i]
        fileStr = fileNameStr.split('.')[0]     #take off .txt
        classNumStr = int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)  #图片向量列表对应的 数字 标签
        trainingMat[i, :] = img2vector('trainingDigits/%s' % fileNameStr)  # trainingMat的第i行的所有列(:)存储 该图片的向量

现在就是最重要的时刻了,使用sklearn库,按照上面所写的三步方法来进行。需要注意的是,在进行完前两步后,我们就已经构建好了模型,后面要先去读取测试集的文件,然后才可以进行第三步,也就是使用测试集对模型进行测试。

  # 第一步:实例化,构建kNN分类器,基于sklearn构建
  neigh = kNN(n_neighbors = 3, algorithm = 'auto')
  # 第二步:训练模型,trainingMat为训练集的矩阵,hwLabels为对应的标签
  neigh.fit(trainingMat,hwLabels)

  #返回testDigits目录下的文件列表
  testFileList = listdir('testDigits')
  '''因为这里是使用的for循环一个个数据依次进行预测,所以不能使用score函数来返回预测的正确率,因此自己计数来计算错误率
        score函数传入的两个参数一个为测试集,一个为标签集。两者都是集合,
        而这里我是在for循环里使用predict函数依次测试每一个数据,没有用集合'''  
  errorCount = 0  #错误检测计数
  mTest = len(testFileList)  #测试集数据的数量
  
  #从文件名中解析出测试集的类别并进行分类测试
  for i in range(mTest):
      #获取文件的名字
      fileNameStr = testFileList[i]
      #根据文件名获得数字
      classNumber = int(fileNameStr.split('_')[0])
      #获得测试集的1x1024向量,用于预测
      vectorUnderTest = img2vector('testDigits/%s' % (fileNameStr))
      
      # 第三步:进行预测,并获得预测结果
      classifierResult = neigh.predict(vectorUnderTest)
      print("分类返回结果为%d\t真实结果为%d" % (classifierResult, classNumber))
      if classifierResult != classNumber:  # 计算 使用模型预测时,预测错误的个数
          errorCount += 1
      print("总共错了%d个数据\n错误率为%f%%" % (errorCount, errorCount / mTest * 100))

运行结果:

测试集中总共有946个文件,将其使用k近邻进行预测后,总共预测错误12个数据,错误率为1.268%,这与上一篇文章使用的方法得到的错误率基本相同。

5、总结

使用sklearn库确实要比用python手写代码来从头实现一个算法简单方便的多,并且两者效果也差不多。其使用主要也就是按照三步基本流程就可以了,但还是建议自己能够敲一遍代码,从头实现一个算法,这对我们的编程能力和对算法的理解都是有好处的!

PS感觉这一篇写的比前一篇要详细一些,后面也会不断提高,完善!

本文地址:https://blog.csdn.net/qq_28053421/article/details/107288812

《《机器学习实战》之k-近邻算法-使用sklearn.doc》

下载本文的Word格式文档,以方便收藏与打印。