Machine Learning————KNN

本文深入解析KNN算法原理,涵盖numpy与matplotlib应用,详细解释如何将数据转化为特征向量,实现自动规范化处理,以及如何评估算法准确性。并通过约会对象分类与手写识别系统实例,展示KNN在实际场景中的应用。

机器学习资源
以上是可下载源代码的地方,里面有着机器学习的源代码和数据,从中可以找到KNN的相关资料。但需要做一些改动。因为原来的代码是基于python2.x,但我们现在用的都是python3.x,有些代码不适用了 。比如dict.iteritems应该改为dict.items,还有print函数用法也有着小小改动,所以要在python3.x上调试会有语法错误,所以要修改一下。

在进行机器学习之前 需要掌握两个包———numpy和matplotlib,这个自行百度或者去哔哩哔哩找课程自学,他俩相当于一个matlab,以向量或矩阵的形式进行运算。如果是idle需要另外下载numpy和matplotlib,在cmd中用pip 安装即可,不过python3.8好像弄不到matplotlib(这个我也不清楚,我的解决方案是下载了一个python3.7。。。)还有matplotlib内存大一些,有可能出现readtimeouterror(就是下载时间过长导致的错误),由于pip下载需要去外网官网下载,下载速度被限流了,推荐清华大学的换源方式。

这次KNN需要掌握的是numpy中函数array,argsort和tile等;matplotlib需要了解最基本的画图要素,比如figure,ax等要素,并且还要学会散点图,推荐自行百度或者哔哩哔哩吧。还会import operator,用到了operator.itemgetter。自己百度一下这些,再来看代码。。。

现在我来介绍一下KNN原理:
KNN是把特征组成一个向量,有些已知的特征与标签的关系,把要测量的待测特征化成向量,把该向量与已知的向量依次求欧氏距离,取距离最近的k个向量看其标签,k个向量中标签最多的即为该要测量的特征的标签,从而形成分类的目的。

def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = tile(inX, (dataSetSize,1)) - dataSet
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances**0.5
    sortedDistIndicies = distances.argsort()     
    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核心算法,inX是测量目标的特征向量,dataSet是已知数据组成的特征向量库,labels是与数据库中的特征向量一一对应的标签,k是我们要取的邻近范围(我们一般取奇数)。
classify0是通过四个参数,得到函数机器classify的inX的标签,当然这个结果很可能是错误的,后面会有错误率的判断。

def autoNorm(dataSet):
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet - tile(minVals, (m,1))
    normDataSet = normDataSet/tile(ranges, (m,1))   #element wise divide
    return normDataSet, ranges, minVals#three outputs!

autonorm字面意思就是自动规划,由于特征向量的单位比例不一样,所以需要重新规划特征向量,让几个特征尽可能的处于同一个权重下,不然可能会有某一个特征极大的影响结果,或者会有特征被忽略。

def file2matrix(filename):
    fr = open(filename)
    numberOfLines = len(fr.readlines())         #get the number of lines in the file
    returnMat = zeros((numberOfLines,3))        #prepare matrix to return
    classLabelVector = []                       #prepare labels return   
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index,:] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat,classLabelVector

由于我们得到的数据不可能是正好的特征向量,比如下图这种,数据都不是对齐的,全是不整齐的空格,数据文件还是txt格式的,就需要我们用到以上的函数file2matrix(),也很形象2就是英语的to 所以file-to-matrix就形成了我们要的特征向量。
在这里插入图片描述

def datingClassTest():
    hoRatio = 0.50      #hold out 10%
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')       #load data setfrom file
    normMat, ranges, minVals = autoNorm(datingDataMat)
    m = normMat.shape[0]
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        print ("the classifier came back with: %d, the real answer is: %d"% (classifierResult, datingLabels[i]))
        if (classifierResult != datingLabels[i]): errorCount += 1.0
    print ("the total error rate is: %f" % (errorCount/float(numTestVecs)))
    print(errorCount)

这个函数把刚才讲的三个函数连接起来了,把datingTestSet2.txt里面的数据矩阵化,然后取了一半数据当作dataSet数据库来,而对另外一半数据逐一进行classify标签化,然后对比他真的标签,从而得到错误个数和错误率,达到训练的效果,以达到机器学习的效果。

import matplotlib.pyplot as py
fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))

以上代码可实现对datingDataMat的第二列数据和第三列数据进行散点分布,并且用后面的15.0*array(datingLabels)的依次对应的标签把使散点图上的点呈现不同的状态以达到区分的目的,使得散点图一目了然,清晰看出目标在什么分类下。

Peter Harrington写的《Machine Learning in Action》中说了约会的例子。他把约会对象分成三类:不喜欢的人,魅力一般的人和极具魅力的人。他把人的特征分为三个特征:每年获得的飞行常客里程数,玩视频游戏所耗时间百分比,和每周消费的冰激凌公斤数。以这个题为例子,飞行里程数肯定是几百几千这种大数字,而玩视频游戏所耗时间百分比是小于等于1的小数,若没有进行autonorm这一步,则欧氏距离一定被飞行里程数所主导,从而让我们忽略了玩视频游戏所耗时间的百分比这一重要因素。

此外该书还有一个例子就是 手写识别系统。它的作用是把手写的数字识别出来并输出,但由于每个人字体习惯都不同,所以很难存在一模一样的数字,所以使用KNN算法来计算最接近的欧氏距离就比较先进且人性化。但还有一个问题那就是手写的数字是二维图像,如何变成特征向量呢?这时候需要把图像格式化处理为一个向量。我们将32×32的二进制图像转换为1×1024的向量

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

以下为手写识别系统的代码

def handwritingClassTest():
    hwLabels = []
    trainingFileList = listdir('trainingDigits')           #load the training set
    m = len(trainingFileList)
    trainingMat = zeros((m,1024))
    for i in range(m):
        fileNameStr = trainingFileList[i]
        fileStr = fileNameStr.split('.')[0]     #take off .txt
        classNumStr = int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
    testFileList = listdir('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('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)))

KNN算法是分类数据最简单最有效的算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值