当前位置:   article > 正文

机器学习实战(一):K近邻算法(sklearn)_sklearn k近邻

sklearn k近邻

我的个人网站:天风的人工智能小站

我的CSDN账号:**Tian-Feng的博客_CSDN博客-机器学习领域博主

我的github账号:zhangwei668 - Overview

我的知乎账号:天风

一 丶k-近邻算法实战之sklearn手写数字识别

1、实战背景

对于需要识别的数字已经使用图形处理软件,处理成具有相同的色彩和大小:宽高是32像素x32像素。尽管采用本文格式存储图像不能有效地利用内存空间,但是为了方便理解,我们将图片转换为文本格式,数字的文本格式如图所示。

与此同时,这些文本格式存储的数字的文件命名也很有特点,格式为:数字的值_该数字的样本序号,如图所示。

对于这样已经整理好的文本,我们可以直接使用Python处理,进行数字预测。数据集分为训练集和测试集,使用上小结的方法,自己设计k-近邻算法分类器,可以实现分类。数据集和实现代码下载地址:数据集下载

这里不再讲解自己用Python写的k-邻域分类器的方法,因为这不是本小节的重点。接下来,我们将使用强大的第三方Python科学计算库Sklearn构建手写数字系统。

2、sklearn简介

Scikit learn 也简称sklearn,是机器学习领域当中最知名的python模块之一。sklearn包含了很多机器学习的方式:

  • Classification 分类
  • Regression 回归
  • Clustering 非监督分类
  • Dimensionality reduction 数据降维
  • Model Selection 模型选择
  • Preprocessing 数据与处理

使用sklearn可以很方便地让我们实现一个机器学习算法。一个复杂度算法的实现,使用sklearn可能只需要调用几行API即可。所以学习sklearn,可以有效减少我们特定任务的实现周期。

3、sklearn安装

在安装sklearn之前,需要安装两个库,即numpy+mkl和scipy。不要使用pip3直接进行安装,因为pip3默安装的是numpy,而不是numpy+mkl。第三方库下载地址:http://www.lfd.uci.edu/~gohlke/pythonlibs/

直接Ctrl f:查找到对应python版本的numpy+mkl和scipy下载安装即可,如图所示。 

3.1、Scipy简介

Scipy 是一个用于数学、科学、工程领域的常用软件包,可以处理最优化、线性代数、积分、插值、拟合、特殊函数、快速傅里叶变换、信号处理、图像处理、常微分方程求解器等。 。

SciPy 包含的模块有最优化、线性代数、积分、插值、特殊函数、快速傅里叶变换、信号处理和图像处理、常微分方程求解和其他科学与工程中常用的计算。

NumPy 和 SciPy 的协同工作可以高效解决很多问题,在天文学、生物学、气象学和气候科学,以及材料科学等多个学科得到了广泛应用。

3.2、numpy+mkl简介

Python下有很多关于机器学习的库,最常用的组合有一下四个:

numpy :主要用来做一些科学运算,主要是矩阵的运算。NumPy为Python带来了真正的多维数组功能,并且提供了丰富的函数库处理这些数组。它将常用的数学函数都进行数组化,使得这些数学函数能够直接对数组进行操作,将本来需要在Python级别进行的循环,放到C语言的运算中,明显地提高了程序的运算速度。

scipy:主要是一些科学工具集,信号处理工具集(如线性代数使用LAPACK库,快速傅立叶变换使用FFTPACK库)及数值计算的一些工具(常微分方程求解使用ODEPACK库,非线性方程组求解以及最小值求解等)。

scikit-learn:里面有很多机器学习相关的算法(如聚类算法,SVM等)。

matplotlib:是一个画图工具和Matlab中的画图工程类似。


3.3安装指南

直接使用指令pip3 install scrapy,发现有诸多错误。这时候就需要我们手动安装了,如果以后安装python包失败,可以直接手动安装。

(1)win+r cmd打开终端,输入python,显示python版本,上图的cp38,amd64,代表python3.8版本,64位。注意如果你是anaconda管理python库,anaconda安装多少位,python就下载多少位的。

(2)在cmd中输入DOS指令,进入下载好的whl文件夹下,例如我的三个whl文件放在了pythonbao文件夹下:

像下图依次执行,我下载就不演示了:

  1. pip3 install wheel
  2. pip3 install numpy-1.22.4+mkl-cp38-cp38-win32.whl
  3. pip3 install SciPy-1.8.1-cp38-cp38-win32.whl

使用pip3安装好这两个whl文件后,使用如下指令安装sklearn。

pip3 install -U scikit-learn

4、sklearn实现k-近邻算法简介

官方文档         主界面

 4.1 我来教教简单运用:打开主界面,分别为分类,回归,聚类

4.2 点击第一个进去,左边都是分类算法,随便点一个knn算法,右边给出一些例子作为参考。

4.3 点击页面顶部API,给出算法的具体算法函数

     

4.4 点击sklearn.neighbors.KNeighborsClassifier,函数的参数信息。

4.5  对于处理好的数据,仅仅以下操作就能实现knn算法。

  1. from sklearn.neighbors import KNeighborsClassifier
  2. neigh = KNeighborsClassifier(n_neighbors=3)
  3. neigh.fit(X, y)
  4. KNeighborsClassifier(...)
  5. print(neigh.predict(data))

Parameters:

  • n_neighbors*int, default=5*

    默认为5,就是k-NN的k的值,选取最近的k个点。

  • weights*{‘uniform’, ‘distance’} or callable, default=’uniform’*

    默认是uniform,参数可以是uniform、distance,也可以是用户自己定义的函数。uniform是均等的权重,就说所有的邻近点的权重都是相等的。distance是不均等的权重,距离近的点比距离远的点的影响大。用户自定义的函数,接收距离的数组,返回一组维数相同的权重。

  • algorithm*{‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, default=’auto’*

    快速k近邻搜索算法,默认参数为auto,可以理解为算法自己决定合适的搜索算法。除此之外,用户也可以自己指定搜索算法ball_tree、kd_tree、brute方法进行搜索,

  • leaf_size*int, default=30*

    默认是30,这个是构造的kd树和ball树的大小。这个值的设置会影响树构建的速度和搜索速度,同样也影响着存储树所需的内存大小。需要根据问题的性质选择最优的大小。

  • p*int, default=2*

    距离度量公式。在上小结,我们使用欧氏距离公式进行距离度量。除此之外,还有其他的度量方法,例如曼哈顿距离。这个参数默认为2,也就是默认使用欧式距离公式进行距离度量。也可以设置为1,使用曼哈顿距离公式进行距离度量。

  • metric*str or callable, default=’minkowski’*

    用于距离度量,默认度量是minkowski,也就是p=2的欧氏距离(欧几里德度量)。

  • metric_params*dict, default=None*

    使用默认的None即可。

  • n_jobs*int, default=None*

    并行处理设置。默认为1,临近点搜索并行工作数。如果为-1,那么CPU的所有cores都用于并行工作。

Methods

fit(X, y)拟合从训练数据集得到的k个最近邻分类器。
get_params([deep])获取这个估计器的参数。
kneighbors([X, n_neighbors, return_distance])找到一个点的k个邻居。
kneighbors_graph([X, n_neighbors, mode])计算X中的点的k个邻居的(加权)图。
predict(X)预测所提供的数据的类标签。
predict_proba(X)对测试数据X的返回概率估计值。
score(X, y[, sample_weight])返回对给定的测试数据和标签的平均精度。
set_params(**params)设置此估计器的参数。

5、sklearn实战

我们知道数字图片是32x32的二进制图像,为了方便计算,我们可以将32x32的二进制图像转换为1x1024的向量。对于sklearn的KNeighborsClassifier输入可以是矩阵,不用一定转换为向量,不过为了跟自己写的k-近邻算法分类器对应上,这里也做了向量化处理。然后构建kNN分类器,利用分类器做预测。创建kNN_test04.py文件,编写代码如下:

不使用sklearn

  1. # -*- coding: UTF-8 -*-
  2. import numpy as np
  3. import operator
  4. from os import listdir
  5. """
  6. 函数说明:kNN算法,分类器
  7. Parameters:
  8. inX - 用于分类的数据(测试集)
  9. dataSet - 用于训练的数据(训练集)
  10. labes - 分类标签
  11. k - kNN算法参数,选择距离最小的k个点
  12. Returns:
  13. sortedClassCount[0][0] - 分类结果
  14. """
  15. def classify0(inX, dataSet, labels, k):
  16. #numpy函数shape[0]返回dataSet的行数
  17. dataSetSize = dataSet.shape[0]
  18. #在列向量方向上重复inX共1次(横向),行向量方向上重复inX共dataSetSize次(纵向)
  19. diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
  20. #二维特征相减后平方
  21. sqDiffMat = diffMat**2
  22. #sum()所有元素相加,sum(0)列相加,sum(1)行相加
  23. sqDistances = sqDiffMat.sum(axis=1)
  24. #开方,计算出距离
  25. distances = sqDistances**0.5
  26. #返回distances中元素从小到大排序后的索引值
  27. sortedDistIndices = distances.argsort()
  28. #定一个记录类别次数的字典
  29. classCount = {}
  30. for i in range(k):
  31. #取出前k个元素的类别
  32. voteIlabel = labels[sortedDistIndices[i]]
  33. #dict.get(key,default=None),字典的get()方法,返回指定键的值,如果值不在字典中返回默认值。
  34. #计算类别次数
  35. classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
  36. #python3中用items()替换python2中的iteritems()
  37. #key=operator.itemgetter(1)根据字典的值进行排序
  38. #key=operator.itemgetter(0)根据字典的键进行排序
  39. #reverse降序排序字典
  40. sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
  41. #返回次数最多的类别,即所要分类的类别
  42. return sortedClassCount[0][0]
  43. """
  44. 函数说明:将32x32的二进制图像转换为1x1024向量。
  45. Parameters:
  46. filename - 文件名
  47. Returns:
  48. returnVect - 返回的二进制图像的1x1024向量
  49. """
  50. def img2vector(filename):
  51. #创建1x1024零向量
  52. returnVect = np.zeros((1, 1024))
  53. #打开文件
  54. fr = open(filename)
  55. #按行读取
  56. for i in range(32):
  57. #读一行数据
  58. lineStr = fr.readline()
  59. #每一行的前32个元素依次添加到returnVect中
  60. for j in range(32):
  61. returnVect[0, 32*i+j] = int(lineStr[j])
  62. #返回转换后的1x1024向量
  63. return returnVect
  64. """
  65. 函数说明:手写数字分类测试
  66. Parameters:
  67. Returns:
  68. """
  69. def handwritingClassTest():
  70. #测试集的Labels
  71. hwLabels = []
  72. #返回trainingDigits目录下的文件名
  73. trainingFileList = listdir("F:\machinelearning\machinelearninginaction\Ch02\\trainingDigits")
  74. #返回文件夹下文件的个数
  75. m = len(trainingFileList)
  76. #初始化训练的Mat矩阵,测试集
  77. trainingMat = np.zeros((m, 1024))
  78. #从文件名中解析出训练集的类别
  79. for i in range(m):
  80. #获得文件的名字
  81. fileNameStr = trainingFileList[i]
  82. #获得分类的数字
  83. classNumber = int(fileNameStr.split('_')[0])
  84. #将获得的类别添加到hwLabels中
  85. hwLabels.append(classNumber)
  86. #将每一个文件的1x1024数据存储到trainingMat矩阵中
  87. # %s 代表后面的文件已字符型输出
  88. trainingMat[i,:] = img2vector("F:\machinelearning\machinelearninginaction\Ch02\\trainingDigits/%s" % (fileNameStr))
  89. #返回testDigits目录下的文件名
  90. testFileList = listdir("F:\machinelearning\machinelearninginaction\Ch02\\testDigits")
  91. #错误检测计数
  92. errorCount = 0.0
  93. #测试数据的数量
  94. mTest = len(testFileList)
  95. #从文件中解析出测试集的类别并进行分类测试
  96. for i in range(mTest):
  97. #获得文件的名字
  98. fileNameStr = testFileList[i]
  99. #获得分类的数字
  100. classNumber = int(fileNameStr.split('_')[0])
  101. #获得测试集的1x1024向量,用于训练
  102. vectorUnderTest = img2vector("F:\machinelearning\machinelearninginaction\Ch02\\testDigits/%s" % (fileNameStr))
  103. #获得预测结果
  104. classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
  105. print("分类返回结果为%d\t真实结果为%d" % (classifierResult, classNumber))
  106. if(classifierResult != classNumber):
  107. errorCount += 1.0
  108. print("总共错了%d个数据\n错误率为%f%%" % (errorCount, errorCount/mTest))
  109. """
  110. 函数说明:main函数
  111. Parameters:
  112. Returns:
  113. """
  114. if __name__ == '__main__':
  115. handwritingClassTest()

运行:

使用sklearn

  1. # -*- coding: UTF-8 -*-
  2. import numpy as np
  3. import operator
  4. from os import listdir
  5. from sklearn.neighbors import KNeighborsClassifier as kNN
  6. """
  7. 函数说明:kNN算法,分类器
  8. Parameters:
  9. inX - 用于分类的数据(测试集)
  10. dataSet - 用于训练的数据(训练集)
  11. labes - 分类标签
  12. k - kNN算法参数,选择距离最小的k个点
  13. Returns:
  14. sortedClassCount[0][0] - 分类结果
  15. """
  16. def classify0(inX, dataSet, labels, k):
  17. #numpy函数shape[0]返回dataSet的行数
  18. dataSetSize = dataSet.shape[0]
  19. #在列向量方向上重复inX共1次(横向),行向量方向上重复inX共dataSetSize次(纵向)
  20. diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
  21. #二维特征相减后平方
  22. sqDiffMat = diffMat**2
  23. #sum()所有元素相加,sum(0)列相加,sum(1)行相加
  24. sqDistances = sqDiffMat.sum(axis=1)
  25. #开方,计算出距离
  26. distances = sqDistances**0.5
  27. #返回distances中元素从小到大排序后的索引值
  28. sortedDistIndices = distances.argsort()
  29. #定一个记录类别次数的字典
  30. classCount = {}
  31. for i in range(k):
  32. #取出前k个元素的类别
  33. voteIlabel = labels[sortedDistIndices[i]]
  34. #dict.get(key,default=None),字典的get()方法,返回指定键的值,如果值不在字典中返回默认值。
  35. #计算类别次数
  36. classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
  37. #python3中用items()替换python2中的iteritems()
  38. #key=operator.itemgetter(1)根据字典的值进行排序
  39. #key=operator.itemgetter(0)根据字典的键进行排序
  40. #reverse降序排序字典
  41. sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
  42. #返回次数最多的类别,即所要分类的类别
  43. return sortedClassCount[0][0]
  44. """
  45. 函数说明:将32x32的二进制图像转换为1x1024向量。
  46. Parameters:
  47. filename - 文件名
  48. Returns:
  49. returnVect - 返回的二进制图像的1x1024向量
  50. """
  51. def img2vector(filename):
  52. #创建1x1024零向量
  53. returnVect = np.zeros((1, 1024))
  54. #打开文件
  55. fr = open(filename)
  56. #按行读取
  57. for i in range(32):
  58. #读一行数据
  59. lineStr = fr.readline()
  60. #每一行的前32个元素依次添加到returnVect中
  61. for j in range(32):
  62. returnVect[0, 32*i+j] = int(lineStr[j])
  63. #返回转换后的1x1024向量
  64. return returnVect
  65. """
  66. 函数说明:手写数字分类测试
  67. Parameters:
  68. Returns:
  69. """
  70. def handwritingClassTest():
  71. #测试集的Labels
  72. hwLabels = []
  73. #返回trainingDigits目录下的文件名
  74. trainingFileList = listdir('F:\machinelearning\machinelearninginaction\Ch02\\trainingDigits')
  75. #返回文件夹下文件的个数
  76. m = len(trainingFileList)
  77. #初始化训练的Mat矩阵,测试集
  78. trainingMat = np.zeros((m, 1024))
  79. #从文件名中解析出训练集的类别
  80. for i in range(m):
  81. #获得文件的名字
  82. fileNameStr = trainingFileList[i]
  83. #获得分类的数字
  84. classNumber = int(fileNameStr.split('_')[0])
  85. #将获得的类别添加到hwLabels中
  86. hwLabels.append(classNumber)
  87. #将每一个文件的1x1024数据存储到trainingMat矩阵中
  88. trainingMat[i,:] = img2vector('F:\machinelearning\machinelearninginaction\Ch02\\trainingDigits/%s' % (fileNameStr))
  89. #构建kNN分类器
  90. neigh = kNN(n_neighbors = 3, algorithm = 'auto')
  91. #拟合模型, trainingMat为训练矩阵,hwLabels为对应的标签
  92. neigh.fit(trainingMat, hwLabels)
  93. #返回testDigits目录下的文件列表
  94. testFileList = listdir('F:\machinelearning\machinelearninginaction\Ch02\\testDigits')
  95. #错误检测计数
  96. errorCount = 0.0
  97. #测试数据的数量
  98. mTest = len(testFileList)
  99. #从文件中解析出测试集的类别并进行分类测试
  100. for i in range(mTest):
  101. #获得文件的名字
  102. fileNameStr = testFileList[i]
  103. #获得分类的数字
  104. classNumber = int(fileNameStr.split('_')[0])
  105. #获得测试集的1x1024向量,用于训练
  106. vectorUnderTest = img2vector('F:\machinelearning\machinelearninginaction\Ch02\\testDigits/%s' % (fileNameStr))
  107. #获得预测结果
  108. # classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
  109. classifierResult = neigh.predict(vectorUnderTest)
  110. print("分类返回结果为%d\t真实结果为%d" % (classifierResult, classNumber))
  111. if(classifierResult != classNumber):
  112. errorCount += 1.0
  113. print("总共错了%d个数据\n错误率为%f%%" % (errorCount, errorCount/mTest * 100))
  114. """
  115. 函数说明:main函数
  116. Parameters:
  117. Returns:
  118. """
  119. if __name__ == '__main__':
  120. handwritingClassTest()

错误率并没有减少,可能sklearn处理大数据更适合,可能跟数据量和k的个数取值,搜索方式等等有关有关,留给你们慢慢研究。

参考资料:

  1. 本文中提到的电影类别分类、约会网站配对效果判定、手写数字识别实例和数据集,均来自于《机器学习实战》的第二章k-近邻算法。
  2. 本文的理论部分,参考自《统计学习方法 李航》的第三章k近邻法以及《机器学习实战》的第二章k-近邻算法。
  3. Jack-Cui的博客_CSDN博客-深度学习实战,LeetCode,Python3网络爬虫入门领域博主
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/1008047
推荐阅读
相关标签
  

闽ICP备14008679号