手写数字是32x32的黑白图像。为了能使用KNN分类器,我们需要把32x32的二进制图像转换为1x1024

1. 将图像转化为向量

from numpy import *
# 导入科学计算包numpy和运算符模块operator
import operator
from os import listdir
def img2vector(filename):
"""
将图像数据转换为向量
:param filename: 图片文件 因为我们的输入数据的图片格式是 32 * 32的
:return: 一维矩阵
该函数将图像转换为向量:该函数创建 1 * 1024 的NumPy数组,然后打开给定的文件,
循环读出文件的前32行,并将每行的头32个字符值存储在NumPy数组中,最后返回数组。
"""
returnVect = zeros((1, 1024))
fr = open(filename)
for i in range(32):
lineStr = fr.readline()
for j in range(32):
returnVect[0, 32 * i + j] = int(lineStr[j])
return returnVect

测试:

testVector = img2vector('F:/迅雷下载/machinelearninginaction/Ch02/testDigits/0_13.txt')
testVector[0, 0:31]
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1.,
1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])

2. KNN分类器

def classify0(inX, dataSet, labels, k):
"""
inX: 用于分类的输入向量
dataSet: 输入的训练样本集
labels: 标签向量
k: 选择最近邻居的数目
注意:labels元素数目和dataSet行数相同;程序使用欧式距离公式.
"""
# 求出数据集的行数
dataSetSize = dataSet.shape[0]
# tile生成和训练样本对应的矩阵,并与训练样本求差
"""
tile: 列: 3表示复制的行数, 行:1/2 表示对inx的重复的次数
例:In []: inX = [1, 2, 3]
tile(inx, (3, 1)) Out[]: array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
"""
# 用inx(输入向量)生成和dataSet类型一样的矩阵,在减去dataSet
diffMat = tile(inX, (dataSetSize, 1)) - dataSet
# 取平方
sqDiffMat = diffMat ** 2
# 将矩阵的每一行相加
sqDistances = sqDiffMat.sum(axis=1)
# 开方
distances = sqDistances ** 0.5
# 根据距离排序从小到大的排序,返回对应的索引位置
# argsort() 是将x中的元素从小到大排列,提取其对应的index(索引),然后输出到y。
"""
In [] : y = argsort([3, 0, 2, -1, 4, 5])
print(y[0])
print(y[5])
Out[] : 3
5
由于最小的数是-1,它的序号是3,因此y[0] = 3, 最大的数是5,它的序号是5,因此y[5] = 5
"""
sortedDistIndicies = distances.argsort()
# 2. 选择距离最小的k个点
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]

3. 手写数字识别系统的测试代码

def handwritingClassTest():
# 1. 导入数据
hwLabels = []
trainingFileList = listdir('F:/迅雷下载/machinelearninginaction/Ch02/trainingDigits') # load the training set
m = len(trainingFileList)
trainingMat = zeros((m, 1024))
# hwLabels存储0~9对应的index位置, trainingMat存放的每个位置对应的图片向量
for i in range(m):
fileNameStr = trainingFileList[i]
fileStr = fileNameStr.split('.')[0] # take off .txt
classNumStr = int(fileStr.split('_')[0])
hwLabels.append(classNumStr)
# 将 32*32的矩阵->1*1024的矩阵
trainingMat[i, :] = img2vector('F:/迅雷下载/machinelearninginaction/Ch02/trainingDigits/%s' % fileNameStr) # 2. 导入测试数据
testFileList = listdir('F:/迅雷下载/machinelearninginaction/Ch02/testDigits') # iterate through the test set
errorCount = 0.0
mTest = len(testFileList)
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0] # take off .txt
classNumStr = int(fileStr.split('_')[0])
vectorUnderTest = img2vector('F:/迅雷下载/machinelearninginaction/Ch02/testDigits/%s' % fileNameStr)
classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr))
if (classifierResult != classNumStr): errorCount += 1.0
print("\nthe total number of errors is: %d" % errorCount)
print("\nthe total error rate is: %f" % (errorCount / float(mTest)))
handwritingClassTest()
the classifier came back with: 0, the real answer is: 0
the classifier came back with: 0, the real answer is: 0
...
the classifier came back with: 9, the real answer is: 9
the classifier came back with: 9, the real answer is: 9 the total number of errors is: 10 the total error rate is: 0.010571
k-近邻算法识别手写数字,错误率在1.1%.改变k的值、修改函数 handwritingClassTest 随机选取训练样本、改变训练样本的数目,都会对k-近邻算法的错误率产生影响。
实际上,这个算法的执行效率并不高。因为每个算法需要为每个测试向量做2000次距离计算,每个距离计算包括了1024个维度浮点运算,总计执行900次。
而K决策树就是k-近邻的优化版。

4. 总结

k-近邻算法的特点:

1. 是分类数据最简单最有效的算法

2. 必须保存全部数据集,会使用大量存储空间

3. 必须对每个数据计算距离值,非常耗时

												

k-近邻算法-手写识别系统的更多相关文章

  1. 第三篇:基于K-近邻分类算法的手写识别系统

    前言 本文将继续讲解K-近邻算法的项目实例 - 手写识别系统. 该系统在获取用户的手写输入后,判断用户写的是什么. 为了突出核心,简化细节,本示例系统中的输入为32x32矩阵,分类结果也均为数字.但对 ...

  2. 机器学习实战一:kNN手写识别系统

    实战一:kNN手写识别系统 本文将一步步地构造使用K-近邻分类器的手写识别系统.由于能力有限,这里构造的系统只能识别0-9.需要识别的数字已经使用图形处理软件,处理成具有相同的色彩和大小:32像素*3 ...

  3. 吴裕雄--天生自然python机器学习:KNN-近邻算法在手写识别系统上的应用

    需要识别的数字已经使用图形处理软件,处理成具有相同的色 彩和大小® : 宽髙是32像 素 *32像素的黑白图像.尽管采用文本格式存储图像不能有效地利用内 存空间,但是为了方便理解,我们还是将图像转换为 ...

  4. 【Machine Learning in Action --2】K-近邻算法构造手写识别系统

    为了简单起见,这里构造的系统只能识别数字0到9,需要识别的数字已经使用图形处理软件,处理成具有相同的色彩和大小:宽高是32像素的黑白图像.尽管采用文本格式存储图像不能有效地利用内存空间,但是为了方便理 ...

  5. K近邻实战手写数字识别

    1.导包 import numpy as np import operator from os import listdir from sklearn.neighbors import KNeighb ...

  6. 《机器学习实战》之k-近邻算法(手写识别系统)

    这个玩意和改进约会网站的那个差不多,它是提前把所有数字转换成了32*32像素大小的黑白图,然后转换成字符图(用0,1表示),将所有1024个像素点用一维矩阵保存下来,这样就可以通过knn计算欧几里得距 ...

  7. 《机器学习实战》-k近邻算法

    目录 K-近邻算法 k-近邻算法概述 解析和导入数据 使用 Python 导入数据 实施 kNN 分类算法 测试分类器 使用 k-近邻算法改进约会网站的配对效果 收集数据 准备数据:使用 Python ...

  8. 机器学习实战kNN之手写识别

    kNN算法算是机器学习入门级绝佳的素材.书上是这样诠释的:“存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都有标签,即我们知道样本集中每一条数据与所属分类的对应关系.输入没有标签的新数据 ...

  9. python 实现 KNN 分类器——手写识别

    1 算法概述 1.1 优劣 优点:进度高,对异常值不敏感,无数据输入假定 缺点:计算复杂度高,空间复杂度高 应用:主要用于文本分类,相似推荐 适用数据范围:数值型和标称型 1.2 算法伪代码 (1)计 ...

随机推荐

  1. flask基本介绍及虚拟环境

    Flask Flask诞生于2010年,是Armin ronacher(人名)用 Python 语言基于 Werkzeug 工具箱编写的轻量级Web开发框架. Flask 本身相当于一个内核,其他几乎 ...

  2. Struts2学习(二)

    1.Struts2的Servlet的API的访问 1.1   完全解耦合的方式 ActionContext context = ActionContext.getContext( ); 通过conte ...

  3. C++拷贝构造函数(深拷贝&浅拷贝)

    对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a=88; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量.下面看一个类对象拷贝的简单例子. ...

  4. hibernate框架学习第五天:数据查询、投影等

    复习day1环境搭建CRUD操作DB6个核心的APIday2TO PO DO 及其状态切换OID 自然主键 代理主键(uuid)一级缓存 Session绑定 load/get关系1对1 1对多(重点) ...

  5. 在Visual Studio中使用C++创建和使用DLL

    [什么是DLL(动态链接库)?] DLL是一个包含可由多个程序同时使用的代码和数据的库.例如:在Windows操作系统中,Comdlg32 DLL执行与对话框有关的常见函数.因此,每个程序都可以使用该 ...

  6. ansible笔记(8):常用模块之系统类模块(二)

    ansible笔记():常用模块之系统类模块(二) user模块 user模块可以帮助我们管理远程主机上的用户,比如创建用户.修改用户.删除用户.为用户创建密钥对等操作. 此处我们介绍一些user模块 ...

  7. T-SQL LIKE子句 模糊查询

    MS SQL Server LIKE子句用于使用通配符运算符将值与类似值进行比较. 有两个通配符与LIKE运算符结合使用: 百分号(%) 下划线(_) 百分号表示零个,一个或多个字符. 下划线表示单个 ...

  8. thinkphp中的内置操作数据库与mysql中的函数汇总

    8.4.4 Model类getModelName() 获取当前Model的名称getTableName() 获取当前Model的数据表名称switchModel(type,vars=array()) ...

  9. LA 4108 (线段树)

    区间更新 + 统计更新长度 稍稍不注意就T了 #include<bits/stdc++.h> #define lson l, m, rt<<1 #define rson m+1 ...

  10. 走进科学之揭开神秘的"零拷贝"

    前言 "零拷贝"这三个字,想必大家多多少少都有听过吧,这个技术在各种开源组件中都使用了,比如kafka,rocketmq,netty,nginx等等开源框架都在其中引用了这项技术. ...