• 机器学习python实战----k近邻算法


      前一周学习了一些理论的知识,虽然懂了原理,但感觉真要写起代码来还是摸不着头脑,所以接下来的几天都打算在代码方面下一番功夫。由于接触python不久,且能力有限,难免有些错误的或者理解不到位的地方,希望读者不吝指正!

    K-近邻算法(k-NN)的基本原理:存在一个样本数据集合,也叫训练样本集,并且样本集中的每个数据都存在标签,就是我们知道每个数据与所属分类的对应关系。输入没有标签的新数据后,我们将新数据的特征跟样本集中每个数据对应的特征进行比较,选择特征最相似的(最近邻)的分类标签认为是新数据的标签。一般来说我们只选择样本数据集中前k个最相似的数据,这就是k-近邻的出处。

      接下来我们进入代码实战,首先用一个简单的kNN的例子来上手:

    第一步,我们创建一个小的数据集,python代码如下。这是带有标签的四个数据点

    from numpy import *
    import operator
    
    def createDataSet():
        group = 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):
        dataSetSize = dataSet.shape[0] #.shape[0]表示dataSet的行数
        diffMat = tile(Inx,(dataSetSize,1))-dataSet #某个点与数据集中点的x和y的坐标差
        sqdiffmat = diffMat**2
        sumdiffmat = sqdiffmat.sum(axis=1) #对sqdiffmat的行求和即(x-x1)^2+(y-y1)^2
        dis = sumdiffmat**0.5  #求平方根即距离
        sortdis = dis.argsort()
        classDict = {}  #定义一个存储字典
        for i in range(k):   
            keylabels = labels[sortdis[i]] 
            classDict[keylabels] = classDict.get(keylabels,0)+1
        sortclassDict = sorted(classDict.items(),key = operator.itemgetter(1),reverse = True)
                           #.items()方法是将classDict这个存储字典转化为list,operator.itemgetter(1)是按classDict的第一项排序
                           #reverse = True表示降序排列即从大到小
        return sortclassDict[0][0]

     这个函数classify0有四个输入参数,Inx表示分类的输入向量,dataSet表示训练数据集,labels表示标签向量,k表示取前k个最相似(最相近)的向量。这个函数是计算输入向量与训练数据集的欧式距离,然后对距离进行排序并选择前k个最小的距离,对这些类别进行统计,返回类别多的标签作为新数据的标签。classDict是定义的一个空的存储字典,.argsort()函数是对距离进行排序并返回从小到大排列的序号,注意,这里返回的序号就是已经排列好的(从小到大),所以在后面取sortdis[i]的时候就是前k个最小距离了。这个问题要注意一下,我这里想了很久才想明白,所以有必要提醒一下。之后的sorted()函数是按统计的标签数的多少降序排列,所以sortclassDict[0][0]就是统计标签数最多的类别了。

    有了这两个程序我们就可以进行测试啦,结果如图,测试(1,1)这点属于'A'类

    做完这个小例子,接下来我们就要对文件数据进行操作,首先需要从文本中解析数据,这样的一个文本dataSet_kNN.txt中存在1000行、4列数据,前三列为特征向量,最后一列为标签。我们需要将特征向量和标签分开放入两个矩阵中,代码如下:

    def file2mat(filename):
        fr = open(filename)
        listoffile = fr.readlines()   #一次性读取文本的所有内容并以list形式返回
        numoflines = len(listoffile)  #得到文件的行数
        newfacMat = zeros((numoflines,3))#创建一个行数*3的零矩阵
        newclassVec = []             #创建一个类的向量
        index=0
        for line in listoffile:
            line = line.strip()  #strip函数用来截断所有的回车符
            listfromline = line.split('	')#以'	'进行分割
            newfacMat[index,:] = listfromline[0:3]
            newclassVec.append(int(listfromline[-1]))
            index+=1
        return newfacMat,newclassVec

    一些函数的功能我注释出来了,可以自己先new一个短的txt文件去测试这些函数,确保功能正常。运行结果如下:

    我们可以根据特征向量画出散点图,这里是特征向量第0列和第1列。

    下面进行数据的归一化。这里就是我们之前在理论部分说的归一化是一个道理,不能让特征向量之间的差值太大而影响我们的结果,所以要进行归一化,公式也跟之前一样:newValue=(value-min)/(max-min)。代码如下:

    def autoNorm(dataSet):
        valueMax = dataSet.max(0)
        valueMin = dataSet.min(0)
        Value_range = valueMax-valueMin
        normdataSet = zeros(shape(dataSet))
        m = dataSet.shape[0]
        normdataSet = dataSet-tile(valueMin,(m,1))
        normdataSet = normdataSet/tile(Value_range,(m,1))
        return normdataSet,Value_range,valueMin

    到这里我们的kNN算法需要的函数就完了,下面介绍一个评价该算法的方法。这里将样本数据分为训练数据集和测试数据集(8:2),错误率定义为 预测错误的总数/测试样本总数

    def datingSetTest():
        h = 0.2
        newfacMat,newclassVec = file2mat(r'dataSet_kNN.txt')
        normMat,value_range,value_min = autoNorm(newfacMat)
        m = normMat.shape[0]
        numTestData = int(m*h)  #测试向量的总数
        error_cnt=0
        for i in range(numTestData):
            result = classify0(normMat[i,:],normMat[numTestData:m,:],newclassVec[numTestData:m],5)
            print('the result is %d,the real answer is %d
    '%(result,newclassVec[i]))
            if result!=newclassVec[i]:
                error_cnt+=1
        print('the error rate is %f
    '%(error_cnt/float(numTestData)))

    前百分之二十的数据作为测试样本,当然这里的测试样本是需要随机选取的,由于文本文件中就是随机的,我们这里取前20%,剩下的作为训练样本。k取5。如果预测的标签跟实际的标签不符合,就令预测错误的总数+1。

    结果为

    这里的错误率为8.6%。

    k-NN算法到这里就介绍的差不多了,说简单也不简单,说复杂好像也没多少步骤,最关键的是自己要去想,要去做,才能更好的掌握!

    这里贴上代码及文本文件的下载链接 http://pan.baidu.com/s/1o7Pi9JG

  • 相关阅读:
    day 49
    day 48
    day 46
    IOC和DI到底是什么?
    堆排序算法
    快速排序算法
    java中try-catch-finally中的return语句
    归并排序算法
    选择排序算法
    冒泡排序算法
  • 原文地址:https://www.cnblogs.com/kl2blog/p/7745245.html
Copyright © 2020-2023  润新知