手记

K-NN算法的简单实现

机器学习第七天 K-NN算法的简单实现

数据包下载地址:
https://www.xiehaoo.com/media/record/pinke/2018/08/2.KNN.zip

KNN使用场景

电影可以按照题材分类,那么如何区分 动作片 和 爱情片 呢?

动作片:打斗次数更多
爱情片:亲吻次数更多
基于电影中的亲吻、打斗出现的次数,使用 k-近邻算法构造程序,就可以自动划分电影的题材类型。


现在根据上面我们得到的样本集中所有电影与未知电影的距离,按照距离递增排序,可以找到 k 个距离最近的电影。
假定 k=3,则三个最靠近的电影依次是, He's Not Really into Dudes 、 Beautiful Woman 和 California Man。
knn 算法按照距离最近的三部电影的类型,决定未知电影的类型,而这三部电影全是爱情片,因此我们判定未知电影是爱情片。

KNN开发流程

收集数据:任何方法
准备数据:距离计算所需要的数值,最好是结构化的数据格式
分析数据:任何方法
训练算法:此步骤不适用于KNN
测试算法:计算错误率
使用算法:输入样本数据和结构化的输出结果,然后运行KNN算法判断输入数据分类属于哪个分类,最后对计算出的分类执行后续处理

KNN算法特点

优点:精度高、对异常值不敏感、无数据输入假定
缺点:计算复杂度高、空间复杂度高
适用数据范围:数值型和标称型

KNN是最简单的机器学习算法,没有之一

KNN算法伪代码:

"""
对于每一个在数据集中的数据点:
    计算目标的数据点(需要分类的数据点)与该数据点的距离
    将距离排序:从小到大
    选取前K个最短距离
    选取这K个中最多的分类类别
    返回该类别来作为目标数据点的预测值
"""def classify0(inX, dataSet, labels, k):
    """
    距离度量 度量公式为欧氏距离
    inX                                  图像文本转化的向量
    dataSet  <class 'numpy.ndarray'>     矩阵的长度
    labels                               存储0~9对应的index位置
    k                                       
    """
    # >>print(type(dataSet))
    #   <class 'numpy.ndarray'>
    # shape函数是numpy.core.fromnumeric中的函数,它的功能是读取矩阵的长度,比如shape[0]就是读取矩阵第一维度的长度。
    dataSetSize = dataSet.shape[0]    # 原型:numpy.tile(A,reps)
    # tile共有2个参数,A指待输入数组,reps则决定A重复的次数。整个函数用于重复数组A来构建新的数组。
    diffMat = tile(inX, (dataSetSize, 1)) - dataSet
    sqDiffMat = diffMat ** 2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances ** 0.5

    # 将距离排序:从小到大
    sortedDistIndicies = distances.argsort()    # 选取前K个最短距离, 选取这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]

KNN项目案例:手写数字识别系统

项目概述

构造一个能识别数字 0 到 9 的基于 KNN 分类器的手写数字识别系统。

需要识别的数字是存储在文本文件中的具有相同的色彩和大小:宽高是 32 像素 * 32 像素的黑白图像。

开发流程

收集数据:提供文本文件
准备数据:编写函数 img2vector,将图像格式转换为分类器使用的向量格式
分析数据:在python命令提示符中检查数据,确保它符合要求
训练算法:此步骤不适用于KNN
测试算法:编写函数使用提供的部分数据集作为测试样本,测试样本与非测试样本的区别在于测试样本是已经完成分类的数据,如果预测分类与实际类别不同,则标记为一个错误

第一步:收集数据:提供文本文件

第二步:准备数据,导入依赖包

#将图像文本数据转为向量from numpy import zerosfrom os import listdirfrom numpy import zeros, tileimport operatordef 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

在python命令行中输入下列命令测试img2vector函数,然后与文本编辑器打开的文件进行比较:

testVector = img2vector('/Users/xiehao/Desktop/MachineLearning-master/input/2.KNN/testDigits/0_0.txt')>>print(testVector[0,0:32])
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  1.  1.  0.  0.  0. 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]>>print(testVector[0,32:64])
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  1.  1.  1.  1.  1.  1. 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]

文本原件


0_0.txt

训练算法:此步骤不适用于KNN

因为测试数据每一次都要与全量的训练数据进行比较,所以这个过程是没有必要的。

测试算法:编写函数使用提供的部分数据集作为测试样本,如果预测分类与实际类别不同,则标记为一个错误

def handwritingClassTest():
    # 1. 导入训练数据
    hwLabels = []
    trainingFileList = listdir(        '/Users/xiehao/Desktop/MachineLearning-master/input/2.KNN/trainingDigits/')  # load the training set
    m = len(trainingFileList)
    print(m)
    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(            '/Users/xiehao/Desktop/MachineLearning-master/input/2.KNN/trainingDigits/%s' % fileNameStr)    # 2. 导入测试数据
    testFileList = listdir(        '/Users/xiehao/Desktop/MachineLearning-master/input/2.KNN/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(            '/Users/xiehao/Desktop/MachineLearning-master/input/2.KNN/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: 4, the real answer is: 4the classifier came back with: 4, the real answer is: 4the classifier came back with: 3, the real answer is: 3the classifier came back with: 9, the real answer is: 9the classifier came back with: 0, the real answer is: 0
                              ........
the classifier came back with: 3, the real answer is: 3the classifier came back with: 3, the real answer is: 3the total number of errors is: 11the total error rate is: 0.011628

可以看到1934个样本只有11个错误,分类准确率99.43%,还是很可以的

Github原项目地址https://github.com/apachecn/MachineLearning
原是用python2写的,我用python3做了一些修改,明天一步一步解析识别的实现,同时实现另一个分类项目

             

作者:raphah
链接:https://www.jianshu.com/p/13d5cb16ef2e


1人推荐
随时随地看视频
慕课网APP