您的位置:首页 > 其它

【10月23日】机器学习实战(一)KNN算法:手写识别系统

2017-10-24 09:30 323 查看
k-近邻算法怕是最简单的机器学习的分类算法了。简单的说,k-近邻算法采用测量不同特征值之间的距离方法进行分类。

源码+实验数据地址:https://github.com/MoonTreee/machine_learning

其优点:精度高、对异常值不敏感、无数据输入假定;
缺点:计算复杂度高、空间复杂度高;and 需要大量的标注数据

适用数据范围:数值型和标称型。
本文基于k-近邻算法完成一个对字符的识别(本质是一个分类问题),为了简单起见,构造的系统只能识别阿拉伯数字0-9(相关的测试集和训练集数据见github)。源数据已经使用图像处理软件处理成32像素x32像素的黑白图像。为方便处理,以文本格式进行保存。

算法本身也不是很复杂,下面直接上代码。需要注意的地方已经在代码块中标注。import numpy as np
from os import listdir
import operator

# 图像矩阵转换为二进制向量
# 本例中读取文本文件的前32行和前32列,即32x32的矩阵,转换为1x1024的向量
def img2vector(filename):
return_vector = np.zeros((1, 1024))
fr = open(filename)
for i in range(32):
line = fr.readline()
for j in range(32):
return_vector[0, 32 * i + j] = int(line[j])
return return_vector

# knn算法:
# in_X 用于分类的输入向量
# data 训练样本集
# labels 标签向量
# k 选择最近邻的数量
def knnClassify(in_X, data, labels, k):
data_size = data.shape[0]
diff_mat = np.tile(in_X, (data_size, 1)) - data
sq_diff = diff_mat ** 2
sq_distance = sq_diff.sum(axis=1)
distance = sq_distance ** 0.5
sorted_dist = distance.argsort()
class_count = {}
for i in range(k):
vote_label = labels[sorted_dist[i]]
class_count[vote_label] = class_count.get(vote_label, 0) + 1
sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
return sorted_class_count[0][0]

# 手写数字识别
def handwritingTest():
hw_labels = []
training_list = listdir("trainingDigits")
num_files = len(training_list)
training = np.zeros((num_files, 1024))
for i in range(num_files):
# 文件名 0_1.txt,从文件名中解析分类数字,此例为0
file = training_list[i]
file_string = file.split(".")[0]
number = int(file_string.split("_")[0])
hw_labels.append(number)
training[i, :] = img2vector("trainingDigits/%s" % file)
testing_list = listdir('testDigits')
error_count = 0.0
num_test = len(testing_list)
for i in range(num_test):
t_file = testing_list[i]
t_file_string = t_file.split('.')[0]
t_number = int(t_file_string.strip('_')[0])
t_vector = img2vector('testDigits/%s' % t_file)
result = knnClassify(t_vector, training, hw_labels, 3)
if result != t_number:
error_count += 1
print("分类结果: %d , 实际值: %d" % (result, t_number))
print("\n 识别错误的数目:%d" % error_count)
print("\n 错误率: %f" % (error_count/float(t_number)))

if __name__ == '__main__':
handwritingTest()


实验的结果如下:



可见,其精准度还是不错的,正确率达到98.8%。但是,knn是基本实例的学习,使用算法时我们必须有接近实际数据的训练样本数据。knn必须保存所有的数据集,如果训练的数据集很大,需要大量的存储空间。此外,由于必须对数据集中的每个数据计算距离值,也非常耗时。
另一个缺陷是它无法给出任何数据的基础信息,因此也无法知晓平均实例样本或者典型实例的特征(该算法,将所有实例同等看待)。下一篇博客讨论决策树的算法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: