本文已参与「新人创作礼」活动,一起开启掘金创作之路。
\
接触机器学习时间不长,最先接触的就是比较基础的KNN算法和手写数字识别,正好《机器学习实战》这本书第二章又讲到了手写数字识别,就写一些自己的心得体会,同时也要感谢同学的热心帮助。最先接触时,对KNN,Kmeans还不够深入了解,慢慢的才知道,KNN是有监督学习和Kmeans是无监督学习的区别。废话不多说,KNN算法又叫K-近邻算法,其分类思想是测量不同特征值之间的距离从而进行分类。K近邻的原理其实很好理解,通过距离度量,找到与我们给出的数据点最近的K(一般为单数整数)个数据点,通过类似于“投票法”的机制,选择这K个数据点中出现次数最多的标签值作为我们给出数据点的标签。一般而言,不同的K和不同的距离计算公式会影响分类的结果,我们这里距离多用欧氏距离来计算。
相比于Sklearn库调库而言,《机器学习实战》一书给出了KNN的具体实现方法,能够更好地理解KNN算法,看一遍具体实现方法,再调用库函数实现一次,可以加深印象,理解的更透彻。下面是书上给出的具体实现代码。
import operator
import numpy as np
def createDataSet():
group = np.array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
labels = ['A','A','B','B']
return group,labels
def classify0(inX,dataSet,labels,k):
#计算距离,运用欧式公式
"""
:params:inX 待分类数据点
dataSet:训练集
label:训练集标签
k:近邻数
:return:排序后出现次数最多的类别标签
"""
dataSetSize = dataSet.shape[0]
diffMat = np.tile(inX, (dataSetSize,1)) - dataSet
sqDiffMat = diffMat**2
sqDistance = sqDiffMat.sum(axis=1)
distance = sqDistance**0.5
#选择距离最小的点
sortedDistancies = distance.argsort()#按顺序返回索引值
classCount = {}
for i in range(k):
voteIlabel= labels[sortedDistancies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
#排序
sortedClassCount = sorted(classCount.items(),
key = operator.itemgetter(1),reverse = True)
return sortedClassCount[0][0]
group,labels = createDataSet()
test_num = classify0([0,0],group,labels,3)
上面的代码大致描述了一个简单的KNN实现过程,可以对一个简单的二维数剧进行分类,主要的实现过程就是计算inX(给出点)与已知的训练集的点的距离,然后按照距离递增次序排序,按照给出的参数k=3提取距离最近的三个点,然后根据三个点中出现次数最多的标签值预测给出点inX。手写数字识别与这个简单例子的实现方式其实相同,只不过手写数学的数字信息维度比这个维数多一些,我们经常会不同像素的图片,例如32x32,这样我们就一次需要计算1024个点,而随着像素的增加,计算量会更多,不过这个暂时不是我们考虑的问题。下面是我从Sklearn库中调用函数实现的手写数字识别。
先看一下数据长什么样子。
正在上传…重新上传取消
首先是导入Sklearn库的K近邻算法和交叉验证里的数据集分类方法,然后导入numpy库,打开原始数据。
#手写数字识别
import numpy as np
from sklearn import neighbors
from sklearn.cross_validation import ShuffleSplit
'''数据读入'''
data = []
labels = []
filename = 'ZipCode.txt'
with open (filename) as f:
for line in f:
tokens = line.strip().split(' ')
data.append([float(tk) for tk in tokens[1:]])
labels.append(float(tokens[0]))
原始数据是一张张16x16像素的手写数字图片,通过灰度化处理,我们得到了每个像素点的灰度值,每个数字对应一个257x1的数字信息,第一个数字(索引0)为图片表示的数字值,其余256(16x16)个数字为每个像素点的灰度,通过读写操作,我们得到了数据集data和数据集标签labels,接下来将数据集按照一定比例分为训练集与测试集并计算预测准确率。
def knnrightratiotest(data,labels,n=1,test_ratio = 0.1):
'''K近邻算法正确率测试'''
x = np.array(data)
y = np.array(labels)
result = np.zeros((10,10))
'''进行n次k近邻算法测试'''
'''拆分训练数据与测试数据'''
ss = ShuffleSplit(len(data),n_iter = n, test_size = test_ratio)
for train_index,test_index in ss:
x_train, x_test = x[train_index,:], x[test_index,:]
y_train, y_test = y[train_index], y[test_index]
'''训练KNN分类器'''
clf = neighbors.KNeighborsClassifier(algorithm = 'auto')
clf.fit(x_train, y_train)
'''测试结果'''
answer = clf.predict(x_test)
for i in range(len(answer)):
result[int(answer[i]),int(y_test[i])] += 1
return result
这里我们定义了一个KNN分类器,data是手写数字的灰度信息,labels是数字信息对应的label值,按照训练集:测试集=9:1进行数据打乱排序然后训练数据,并对测试集进行预测,返回一个result的10x10矩阵,记录着训练集每个数字的分类结果。下面就是得到的result矩阵,对角线的数字代表预测正确,而其他位置的数字代表预测错误,接下来我们通过分析result来得出最后的预测准确率。
正在上传…重新上传取消
def analysis(result):
'''摘取总测试分类样本数,总预测分类样本数,正确分类样本数'''
y_test = np.array([np.sum(result,axis=0)],dtype = np.int32)
y_predict = np.array([np.sum(result,axis=1)],dtype = np.int32)
y_right = np.array([[result[i,i] for i in range(10)]],dtype = np.int32)
'''计算总和'''
y_test = np.append(y_test,[[np.sum(y_test)]],axis =1)
y_predict = np.append(y_predict,[[np.sum(y_predict)]],axis=1)
y_right = np.append(y_right,[[np.sum(y_right)]],axis=1)
y_error = y_test-y_right
'''计算正确率与错误率'''
rightratio = y_right/y_test
errorratio = y_error/y_test
'''汇总记录'''
values = [y_test,y_predict,y_right,y_test,rightratio,errorratio]
names = ['y_test','y_predict','y_right','y_test','rightratio','errorratio']
analysis = np.array([['name/label',0,1,2,3,4,5,6,7,8,9,'total']])
for i in range(len(names)):
'''添加名字'''
name = np.append([[names[i]]],values[i],axis = 1)
analysis = np.append(analysis,name,axis = 0)
return analysis
定义了analysis函数对result矩阵进行准确率分析,对每一列分析,可以得到单独数字的预测正确率,而将对角线的数字求和除以总的预测数则可以得到总的正确率,通过基本的np.array操作,便可得到最后的正确率分析表anylysis。
正在上传…重新上传取消
总结:
总的来说,手写数字识别就是将图片信息处理为数字信息,通过一定的数字处理过程返回图片信息,而这个数字处理过程就是KNN算法,通过比较数字信息之间的‘间隔’对数字实现预测分类。在KNN处理数字信息的基础上,也能够更好的适应更大的数字矩阵信息,前些日子处理了1024x1024的图片信息,也感觉和这个图像数字矩阵异曲同工,总之KNN作为一个最先接触的方法,虽然简单,但是对今后也有一些帮助和启迪。以上就是看完第二章的一些想法,一些地方表达的不好,也请大家多多指正~
关于sklearn可以看这个网站:sklearn.apachecn.org/
\