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

TianFeng 人工智能 机器学习2072阅读模式

机器学习实战(一):K近邻算法(sklearn)一 丶k-近邻算法实战之sklearn手写数字识别

1、实战背景

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

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

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

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

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

 

 

对于这样已经整理好的文本,我们可以直接使用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。第三方库下载地址:lfd.uci.edu/~gohlke/pyt

直接Ctrl f:查找到对应python版本的numpy+mkl和scipy下载安装即可,如图所示。机器学习实战(一):K近邻算法(sklearn) 机器学习实战(一):K近邻算法(sklearn)

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就下载多少位的。

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

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

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

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

机器学习实战(一):K近邻算法(sklearn)
pip3 install wheel

pip3 install numpy-1.22.4+mkl-cp38-cp38-win32.whl

pip3 install SciPy-1.8.1-cp38-cp38-win32.whl

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

pip3 install -U scikit-learn

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

官方文档         主界面

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

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

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

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

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

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

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

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

 

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

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

机器学习实战(一):K近邻算法(sklearn)
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

# -*- coding: UTF-8 -*-
import numpy as np
import operator
from os import listdir

"""
函数说明:kNN算法,分类器
Parameters:
	inX - 用于分类的数据(测试集)
	dataSet - 用于训练的数据(训练集)
	labes - 分类标签
	k - kNN算法参数,选择距离最小的k个点
Returns:
	sortedClassCount[0][0] - 分类结果
"""
def classify0(inX, dataSet, labels, k):
	#numpy函数shape[0]返回dataSet的行数
	dataSetSize = dataSet.shape[0]
	#在列向量方向上重复inX共1次(横向),行向量方向上重复inX共dataSetSize次(纵向)
	diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
	#二维特征相减后平方
	sqDiffMat = diffMat**2
	#sum()所有元素相加,sum(0)列相加,sum(1)行相加
	sqDistances = sqDiffMat.sum(axis=1)
	#开方,计算出距离
	distances = sqDistances**0.5
	#返回distances中元素从小到大排序后的索引值
	sortedDistIndices = distances.argsort()
	#定一个记录类别次数的字典
	classCount = {}
	for i in range(k):
		#取出前k个元素的类别
		voteIlabel = labels[sortedDistIndices[i]]
		#dict.get(key,default=None),字典的get()方法,返回指定键的值,如果值不在字典中返回默认值。
		#计算类别次数
		classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
	#python3中用items()替换python2中的iteritems()
	#key=operator.itemgetter(1)根据字典的值进行排序
	#key=operator.itemgetter(0)根据字典的键进行排序
	#reverse降序排序字典
	sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
	#返回次数最多的类别,即所要分类的类别
	return sortedClassCount[0][0]

"""
函数说明:将32x32的二进制图像转换为1x1024向量。
Parameters:
	filename - 文件名
Returns:
	returnVect - 返回的二进制图像的1x1024向量
"""
def img2vector(filename):
	#创建1x1024零向量
	returnVect = np.zeros((1, 1024))
	#打开文件
	fr = open(filename)
	#按行读取
	for i in range(32):
		#读一行数据
		lineStr = fr.readline()
		#每一行的前32个元素依次添加到returnVect中
		for j in range(32):
			returnVect[0, 32*i+j] = int(lineStr[j])
	#返回转换后的1x1024向量
	return returnVect
"""
函数说明:手写数字分类测试
Parameters:
	无
Returns:
	无
"""
def handwritingClassTest():
	#测试集的Labels
	hwLabels = []
	#返回trainingDigits目录下的文件名
	trainingFileList = listdir("F:\machinelearning\machinelearninginaction\Ch02\\trainingDigits")
	#返回文件夹下文件的个数
	m = len(trainingFileList)
	#初始化训练的Mat矩阵,测试集
	trainingMat = np.zeros((m, 1024))
	#从文件名中解析出训练集的类别
	for i in range(m):
		#获得文件的名字
		fileNameStr = trainingFileList[i]
		#获得分类的数字
		classNumber = int(fileNameStr.split('_')[0])
		#将获得的类别添加到hwLabels中
		hwLabels.append(classNumber)
		#将每一个文件的1x1024数据存储到trainingMat矩阵中
		# %s 代表后面的文件已字符型输出
		trainingMat[i,:] = img2vector("F:\machinelearning\machinelearninginaction\Ch02\\trainingDigits/%s" % (fileNameStr))
	#返回testDigits目录下的文件名
	testFileList = listdir("F:\machinelearning\machinelearninginaction\Ch02\\testDigits")
	#错误检测计数
	errorCount = 0.0
	#测试数据的数量
	mTest = len(testFileList)
	#从文件中解析出测试集的类别并进行分类测试
	for i in range(mTest):
		#获得文件的名字
		fileNameStr = testFileList[i]
		#获得分类的数字
		classNumber = int(fileNameStr.split('_')[0])
		#获得测试集的1x1024向量,用于训练
		vectorUnderTest = img2vector("F:\machinelearning\machinelearninginaction\Ch02\\testDigits/%s" % (fileNameStr))
		#获得预测结果
		classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
		print("分类返回结果为%d\t真实结果为%d" % (classifierResult, classNumber))
		if(classifierResult != classNumber):
			errorCount += 1.0
	print("总共错了%d个数据\n错误率为%f%%" % (errorCount, errorCount/mTest))

"""
函数说明:main函数

Parameters:
	无
Returns:
	无

"""
if __name__ == '__main__':
	handwritingClassTest()s

运行:

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

使用sklearn

# -*- coding: UTF-8 -*-
import numpy as np
import operator
from os import listdir
from sklearn.neighbors import KNeighborsClassifier as kNN

"""
函数说明:kNN算法,分类器

Parameters:
	inX - 用于分类的数据(测试集)
	dataSet - 用于训练的数据(训练集)
	labes - 分类标签
	k - kNN算法参数,选择距离最小的k个点
Returns:
	sortedClassCount[0][0] - 分类结果
"""
def classify0(inX, dataSet, labels, k):
	#numpy函数shape[0]返回dataSet的行数
	dataSetSize = dataSet.shape[0]
	#在列向量方向上重复inX共1次(横向),行向量方向上重复inX共dataSetSize次(纵向)
	diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
	#二维特征相减后平方
	sqDiffMat = diffMat**2
	#sum()所有元素相加,sum(0)列相加,sum(1)行相加
	sqDistances = sqDiffMat.sum(axis=1)
	#开方,计算出距离
	distances = sqDistances**0.5
	#返回distances中元素从小到大排序后的索引值
	sortedDistIndices = distances.argsort()
	#定一个记录类别次数的字典
	classCount = {}
	for i in range(k):
		#取出前k个元素的类别
		voteIlabel = labels[sortedDistIndices[i]]
		#dict.get(key,default=None),字典的get()方法,返回指定键的值,如果值不在字典中返回默认值。
		#计算类别次数
		classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
	#python3中用items()替换python2中的iteritems()
	#key=operator.itemgetter(1)根据字典的值进行排序
	#key=operator.itemgetter(0)根据字典的键进行排序
	#reverse降序排序字典
	sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
	#返回次数最多的类别,即所要分类的类别
	return sortedClassCount[0][0]

"""
函数说明:将32x32的二进制图像转换为1x1024向量。
Parameters:
	filename - 文件名
Returns:
	returnVect - 返回的二进制图像的1x1024向量
"""
def img2vector(filename):
	#创建1x1024零向量
	returnVect = np.zeros((1, 1024))
	#打开文件
	fr = open(filename)
	#按行读取
	for i in range(32):
		#读一行数据
		lineStr = fr.readline()
		#每一行的前32个元素依次添加到returnVect中
		for j in range(32):
			returnVect[0, 32*i+j] = int(lineStr[j])
	#返回转换后的1x1024向量
	return returnVect


"""
函数说明:手写数字分类测试
 
Parameters:
    无
Returns:
    无
"""
def handwritingClassTest():
    #测试集的Labels
    hwLabels = []
    #返回trainingDigits目录下的文件名
    trainingFileList = listdir('F:\machinelearning\machinelearninginaction\Ch02\\trainingDigits')
    #返回文件夹下文件的个数
    m = len(trainingFileList)
    #初始化训练的Mat矩阵,测试集
    trainingMat = np.zeros((m, 1024))
    #从文件名中解析出训练集的类别
    for i in range(m):
        #获得文件的名字
        fileNameStr = trainingFileList[i]
        #获得分类的数字
        classNumber = int(fileNameStr.split('_')[0])
        #将获得的类别添加到hwLabels中
        hwLabels.append(classNumber)
        #将每一个文件的1x1024数据存储到trainingMat矩阵中
        trainingMat[i,:] = img2vector('F:\machinelearning\machinelearninginaction\Ch02\\trainingDigits/%s' % (fileNameStr))
    #构建kNN分类器
    neigh = kNN(n_neighbors = 3, algorithm = 'auto')
    #拟合模型, trainingMat为训练矩阵,hwLabels为对应的标签
    neigh.fit(trainingMat, hwLabels)
    #返回testDigits目录下的文件列表
    testFileList = listdir('F:\machinelearning\machinelearninginaction\Ch02\\testDigits')
    #错误检测计数
    errorCount = 0.0
    #测试数据的数量
    mTest = len(testFileList)
    #从文件中解析出测试集的类别并进行分类测试
    for i in range(mTest):
        #获得文件的名字
        fileNameStr = testFileList[i]
        #获得分类的数字
        classNumber = int(fileNameStr.split('_')[0])
        #获得测试集的1x1024向量,用于训练
        vectorUnderTest = img2vector('F:\machinelearning\machinelearninginaction\Ch02\\testDigits/%s' % (fileNameStr))
        #获得预测结果
        # classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
        classifierResult = neigh.predict(vectorUnderTest)
        print("分类返回结果为%d\t真实结果为%d" % (classifierResult, classNumber))
        if(classifierResult != classNumber):
            errorCount += 1.0
    print("总共错了%d个数据\n错误率为%f%%" % (errorCount, errorCount/mTest * 100))
 
"""
函数说明:main函数
Parameters:
    无
Returns:
    无
"""
if __name__ == '__main__':
    handwritingClassTest()

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

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

参考资料:

  1. 本文中提到的电影类别分类、约会网站配对效果判定、手写数字识别实例和数据集,均来自于《机器学习实战》的第二章k-近邻算法。
  2. 本文的理论部分,参考自《统计学习方法 李航》的第三章k近邻法以及《机器学习实战》的第二章k-近邻算法。

相关文章
weinxin
我的公众号
微信扫一扫
TianFeng
  • 本文由 发表于 2022年 10月 20日 09:33:29
  • 转载请务必保留本文链接:https://tianfeng.space/157.html