机器学习算法篇之KNN图像识别分类器构建

Posted 三心小皮匠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了机器学习算法篇之KNN图像识别分类器构建相关的知识,希望对你有一定的参考价值。

导论:在上一篇文章“机器学习篇之KNN近邻分类识别算法案例分析--红酒品质分类”文章中,我们了解了K-近邻分类算法的原理并成功地构建了一个分类器去识别红酒种类。我们已经知道K-NN算法是通过将未知的数据点与训练集中已知的数据进行比较,来对未知数据点进行分类。这种比较的依据是什么?我们知道主要是使用距离函数或相似性特征来进行度量。而距离函数相比于相似性特征更容易理解和实现,因此我们可以发现很多种距离函数其实都可以被用在KNN算法中,不仅仅我们之前提到的曼哈顿距离和欧式距离。我们还知道KNN算法中的一个最最重要的关键点就是“K”的选取,从训练集中选中K个距离最近的标签,统计每个标签得票数,得票数最高的那个标签即是未知数据点所属类别。为了进一步展示KNN算法简单又高效的优良特性,我们今天为大家展示KNN算法在图像识别上的优秀表现。


K-近邻图像分类

K-近邻图像分类算法其实也非常简单,可以说是目前图像分类算法中最为简单的分了算法。正如我们导论中描述的那样,未知数据点的分类依赖于它与其他特征向量之间的距离。因此,我们只需要将标签与每个图像相关联,我们就能够判断呢图像的实际类别,并且预测效果还十分不错。

为了直观地阐述KNN-图像分类算法的原理,我们以下面几个图示来展示。

对于图像中的3中不同颜色的数据点,我们从直观上可以判断两个红色点之间的距离要远远小于蓝色点到红色点之间的距离。此时,我们已经理解了k-NN算法的原理。我们知道它依赖于特征向量之间的距离来进行分类。而且我们知道它需要距离度量/相似度函数来计算这些距离。对于距离公式,我们有很多选择,这里我们仍然使用欧式距离。


有了距离公式,接下来该如何用在图像识别上呢?

这其实就是图像识别的要点了,我们都知道在上一篇红酒识别中,我们使用红酒中所含的化学元素作为特征变量,这些变量全是数字特征,所以我们使用起来非常方便。但是图像好像不是这样,这是一幅幅图,不是一列列数字,我们如何才能将它们识别出来呢?

然而事实其实没有那么复杂,表面看起来是一张张的图片,但是每张图片都有属于它自己的数字特征,比如每个数字的特征(如HOG,Zernike Moments等)原始灰度,像素强度等。


KNN图像分类器

了解了这么多,我们将要一步步来构造K-近邻分类器的手写识别系统。我们所使用的数据来自于“UCI人工智能与机器学习中心”。


KNN算法实现手写识别系统

    为了简单起见,这里构造的系统只能识别数字0-9,需要识别的数字已经使用图形处理软件,处理成具有相同的色彩和大小

    尽管采用文本格式存储图像不能有效的利用内存空间,但是为了方便理解,我们还是将图像转换成文本格式。


准备数据:将图像转换为测试向量

    我们将把一个32*32的二进制图像矩阵转化为181024的向量,首先编写一个函数imgvector,将图像转化为向量,

    该函数创建一个1*1024的Numpy数组,然后打开给定的文件,循环读出文件的前32行,并将每行的头32个字符值存储在numpy数组中,最后返回数组。



def img2vector(filename):

    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


import KNN

reload(KNN)

testVector = KNN.img2vector('testDigits/0_16.txt')

testVector[0,100:200]



# 使用K-近邻算法识别手写数字


from os import listdir

def handwritingClassTest():

    hwLabels = []

    trainingFileList = listdir('trainingDigits')

    m = len(trainingFileList)

    trainingMat = zeros((m,1024))

    for i in range(m):

        fileNameStr = trainingFileList[i]

        fileStr = fileNameStr.split(' ')[0]

        classNumStr = int(fileStr.split(' ')[0])

        hwLabels.append(classNumStr)

        trainingMat[i,:] = img2vector('trainingDigits /%s' % fileNameStr)

    testFileList = listdir('testDigits')

    errorCount = 0.0

    mTest = len(testFileList[i])

    for i in range(mTest):

        fileNameStr = testFileList[i]

        fileStr = fileNameStr.split('.')[0]

        classNumStr = int(fileStr.split('_')[0])

        vectorUnderTest = img2vector('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

    print 'the total number of errors is: %d' % errorCount

    print 'the totla error rate is: %f' % (errorCount/float(mTest))

KNN.handwritingClassTest()



k-近邻算法识别手写数字数据集,错误率为1.16%,改变变量k的值、修改函数。handwriting_classTest随机选取训练样本,改变训练样本的数目都会对k-近邻算法的错误率产生影响。

实际使用这个算法时,算法执行的效率并不高,因为算法需要为每个测试向量做2000次距离计算,每个距离计算包括1024个维度浮点运算,总计要执行900次。

此外,我们还需要为测试向量准备2MB的存储空间。是否存在一种算法减少存储空间和计算时间地开销呢?k决策树就是k-近邻算法的优化版本,可以大量节省计算开销。


本章小结

(1)k-近邻算法是分类数据最简单和最有效的算法,通过两个例子讲述了如何使用k-近邻算法构造分类器。

(2)k-近邻算法是基于实例的学习,使用算法时我们必须有接近实际数据的训练样本数据,k-近邻算法必须保存全部数据集,

(3)如果训练数据集很大,必须使用大量的存储空间。此外,由于必须对数据集中的每个数据计算距离值,实际使用时可能非常耗时。

(4)k-近邻算法的另一个缺陷是它无法给出任何数据的基础结构信息,因此我们无法知晓平均实例样本和典型实例样本具有什么特征。








以上是关于机器学习算法篇之KNN图像识别分类器构建的主要内容,如果未能解决你的问题,请参考以下文章

机器学习KNN算法实现手写板字迹识别

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

图像识别之KNN算法的理解与应用

机器学习-KNN分类器

转:机器学习算法原理解析 - 分类

机器学习 sklearn 监督学习 分类算法 KNN K-NearestNeighbor