一、序
机器学习实战_K近邻算法 ——手写数字预测 调用的是自己编写的分类器classify0,主要是为了学习理论原理;在实际是项目中通常调用工具包的api接口,比如sklearn,这也体现了python的一个便利性,不用总是自己造轮子。虽然python提供了很多机器学习的工具包,但是也是在我们了解和熟悉算法的基本实现原理。
二、sklearn中KNeighborsClassifier的介绍
class sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, weights=‘uniform’, algorithm=‘auto’, leaf_size=30, p=2, metric=‘minkowski’, metric_params=None, n_jobs=None, **kwargs)
官方api文档:KNeighborsClassifier
1、KNeighborsClassifier的参数(官方文译):
n_neighbors: int, 可选参数(默认为 5)
用于kneighbors查询的默认邻居的数量
weights(权重): str or callable(自定义类型), 可选参数(默认为 ‘uniform’)
用于预测的权重函数。可选参数如下:
- ‘uniform’ : 统一的权重. 在每一个邻居区域里的点的权重都是一样的。
- ‘distance’ : 权重点等于他们距离的倒数。使用此函数,更近的邻居对于所预测的点的影响更大。
- [callable] : 一个用户自定义的方法,此方法接收一个距离的数组,然后返回一个相同形状并且包含权重的数组。
algorithm(算法): {‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}, 可选参数(默认为 ‘auto’)
计算最近邻居用的算法:
注意 : 如果传入fit方法的输入是稀疏的,将会重载参数设置,直接使用暴力搜索。
leaf_size(叶子数量): int, 可选参数(默认为 30)
传入BallTree或者KDTree算法的叶子数量。此参数会影响构建、查询BallTree或者KDTree的速度,以及存储BallTree或者KDTree所需要的内存大小。 此可选参数根据是否是问题所需选择性使用。
p: integer, 可选参数(默认为 2)
用于Minkowski metric(闵可夫斯基空间)的超参数。p = 1, 相当于使用曼哈顿距离 (l1),p = 2, 相当于使用欧几里得距离(l2) 对于任何 p ,使用的是闵可夫斯基空间(l_p)
metric(矩阵): string or callable, 默认为 ‘minkowski’
用于树的距离矩阵。默认为闵可夫斯基空间,如果和p=2一块使用相当于使用标准欧几里得矩阵. 所有可用的矩阵列表请查询 DistanceMetric 的文档。
metric_params(矩阵参数): dict, 可选参数(默认为 None)
给矩阵方法使用的其他的关键词参数。
n_jobs: int, 可选参数(默认为 1)
用于搜索邻居的,可并行运行的任务数量。如果为-1, 任务数量设置为CPU核的数量。不会影响fit方法。
2、 KNeighborsClassifier的方法(官方文译)
方法名 | 含义 |
---|---|
fit(X, y) | 使用X作为训练数据,y作为目标值(类似于标签)来拟合模型。 |
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) | 设置估值器的参数。 |
三、手写数字预测(sklearn api)
1、修改内容
- 1)、增加的代码
# 构造kNN分类器
knn = KNeighborsClassifier(n_neighbors=3, algorithm='auto')
# 拟合模型,trainingMat为测试矩阵,hwLabels为对应标签
knn.fit(trainingMat, hwLabels)
- 2)、替换的内容
# 获得预测结果
classifierResult = knn.predict(vectorUnderTest) # 替换 classifierResult = classify0(vectorUnderTest)
2、代码
import numpy as np
from os import listdir
from sklearn.neighbors import KNeighborsClassifier
def img2vector(filename):
"""
函数说明:将32*32的二进制图像转换为1*1024向量
Parameters:
filename - 文件名
Returns:
returnVect - 返回二进制图像的1*1024向量
"""
# 创建1*1024零向量
returnVect = np.zeros((1, 1024))
with open(filename) as fr:
# 按行读取
for i in range(32):
# 读取一行数据
lineStr = fr.readline()
# 每一行的前32个数据依次存储到returnVect中
for j in range(32):
returnVect[0, 32 * i + j] = int(lineStr[j])
# 返回转换后的1*1024向量
return returnVect
def handwritingClassTest():
"""
函数说明:手写数字分类测试
Parameters:
None
Returns:
None
"""
# 测试集的Labels
hwLabels = []
# 返回trainingDigits目录下的文件名
trainingFileList = listdir('trainingDigits')
# 返回文件夹下文件的个数
m = len(trainingFileList)
# 初始化训练的Mat矩阵(全零阵),测试集
trainingMat = np.zeros((m, 1024))
# 从文件名中解析出训练集的类别
for i in range(m):
# 获得文件的名字
fileNameStr = trainingFileList[i]
# 获得分类的数字
classNumStr = int(fileNameStr.split('_')[0])
# 将获得的类别添加到hwLabels中
hwLabels.append(classNumStr)
# 将每一个文件的1x1024数据存储到trainingMat矩阵中
trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
# 构造kNN分类器
knn = KNeighborsClassifier(n_neighbors=3, algorithm='auto')
# 拟合模型,trainingMat为测试矩阵,hwLabels为对应标签
knn.fit(trainingMat, hwLabels)
# 返回testDigits目录下的文件列表
testFileList = listdir('testDigits')
# 错误检测计数
errorCount = 0.0
# 测试数据的数量
mTest = len(testFileList)
# 从文件中解析出测试集的类别并进行分类测试
for i in range(mTest):
# 获得文件名字
fileNameStr = testFileList[i]
# 获得分类的数字
classNumStr = int(fileNameStr.split('_')[0])
vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
# 获得预测结果
classifierResult = knn.predict(vectorUnderTest)
print("分类返回结果为%d\t真实结果为%d" % (classifierResult, classNumStr))
if classifierResult != classNumStr:
errorCount += 1.0
print("总共错了%d个数据\n错误率为%f%%" % (errorCount, errorCount / mTest * 100))
if __name__ == '__main__':
handwritingClassTest()