zoukankan      html  css  js  c++  java
  • 【机器学习算法基础+实战系列】KNN算法

    k 近邻法(K-nearest neighbor)是一种基本的分类方法

    基本思路:

    给定一个训练数据集,对于新的输入实例,在训练数据集中找到与该实例最邻近的k个实例,这k个实例多数属于某个类别,就把输入实例分为这个类。

    算法:

    输入:训练数据集 (T={(x_{1},y_{1}),(x_{2},y_{2}),...,(x_{n},y_{n})}) 其中 (x_{i}) 是训练集实例的特征向量(features vectors),(y_{i}) 是训练集实例的类别,(i=1,2,3,cdotcdotcdot,N) (N 代表的是训练集实例的数量)
    输出:训练数据集实例的列别(y)

    模型:

    三个基本要素:距离度量(欧几里得距离),k值的选择,分类决策规则(多数表决 )

    • 距离度量:首先特征向量是(n)维,(x_{i})是训练数据集中的特征向量,(x_{j})是输入实例的特征向量。
      其中(x_{i}=(x_{i}^{(1)},x_{i}^{(2)},...,x_{i}^{(n)}), x_{j}=(x_{j}^{(1)},x_{j}^{(2)},...,x_{j}^{(n)})).
      两者之间的距离定义为:(L_{p}(x_{i},x_{j})=(sum_{t=1}^{n}{|x_{i}^{(t)}-x_{j}^{(t)}|^{p}})^{1/p}).
      在这里(pgeq1), 当(p=2)时,我们称之为欧氏距离(Euclidean distance),即(L_{p}(x_{i},x_{j})=(sum_{t=1}^{n}{|x_{i}^{(t)}-x_{j}^{(t)}|^{2}})^{1/2});
      当p=1 时,我们称之为曼哈顿距离(Manhattan distance)即(L_{p}(x_{i},x_{j})=sum_{t=1}^{n}{|x_{i}^{(t)}-x_{j}^{(t)}|}). 使用不同的距离度量方法会产生不同的结果。
    • k值得选择问题:会采取交叉验证的方法选择合适k值
    • 分类决策规则:多数表决

    在电影分类中的KNN算法

    import numpy as np
    import operator #运算符模块
    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
    
    group,labels=createDataSet()
    
    def classify0(inx, dataSet, labels, k):
        dataSetSize = dataSet.shape[0]
        diffMat = np.tile(inx, (dataSetSize,1)) - dataSet # tile 
        sqDiffMat = diffMat ** 2 #**乘方
        sqDistances = sqDiffMat.sum(axis=1)
        distances = sqDistances ** 0.5
        sortedDistIndicies = distances.argsort()# argsort
        classCount={}#dic
        for i in range(k):
            voteIlabel = labels[sortedDistIndicies[i]]
            classCount[voteIlabel] = classCount.get(voteIlabel,0)+1 #get
        sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) # sorted &items()
        return sortedClassCount[0][0]
    
    classify0([0,0],group,labels,3)
    

    在这里我们是自己实现了一个KNN的分类器,我们也可以使用sklearn 中的KNeighborsClassifier 去直接分类,参考这里中的实例

    对代码中的基础知识进行总结:

    shape( ):numpy

    >>> C = np.array([[1,1],[1,2],[1,3],[1,4]])
    >>> C.shape()  
    >>> (4,2)  
    >>> C.shape[0]  
    >>> 4  
    >>> C.shape[1]  
    >>> 2
    

    tile( ): 重复某个数组(numpy)

    >>>A=[1,2,3]
    >>>np.tile(A,3)
    >>>array([1, 2, 3, 1, 2, 3, 1, 2, 3])
    >>>np.tile(A,(3,1))
    >>>array([[1, 2, 3],
           [1, 2, 3],
           [1, 2, 3]])
    >>>np.tile(A,(3,2))
    >>>array([[1, 2, 3, 1, 2, 3],
           [1, 2, 3, 1, 2, 3],
           [1, 2, 3, 1, 2, 3]])
    

    argsort( )

    • 对于一维数组来讲:
    >>>x=np.array([3,1,2])
    >>>np.argsort(x)
    >>>array([1,2,0])  #把索引从小到大列了出来
    
    >>>np.argsort(-x) #按照降序排列
    >>>array([0,2,1])
    
    
    >>>x[np.argsort(x)] #重新排序之后的数组
    >>>array([1,2,3])
    
    • 对于二维数组来说
    >>> x=np.array([[0,3],[2,2]])
    >>>np.argsort(x,axis=0) #按列排序
    >>> array([[0, 1],
               [1, 0]])
               
    >>>np.argsort(x,axis=1)#按行排序
    >>>array([[0, 1],
               [0, 1]])
               
    

    Dictionary get( ):

    dict.get(key,default=None) 字典的get()函数返回指定键的值,如果键或者值不存在,返回默认值

    sorted( ):

    • sort 和 sorted 的区别

    sort 是应用在list上的方法,sorted是可以对所有可迭代的对象进行排序操作的函数
    sort是作用在列表本身,改变原列表 sorted是生成一个新的可迭代的对象

    • sorted用法
      sorted(iterable, key=None, reverse=False)
      对由tuple组成的list排序:
    >>> students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
    #使用key函数
    >>> sorted(students, key=lambda student : student[2])   # sort by age 
    >>>[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]  #返回由tuple组成的list
    
    #用 operator 函数来加快速度
    >>> sorted(students, key=itemgetter(2))  
    
    
    #用 operator 函数进行多级排序 
    
    >>> sorted(students, key=itemgetter(1,2))  # sort by grade then by age 
    >>>[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]  
    
    
    对由字典排序 ,返回由tuple组成的List,不再是字典
    >>> d = {'data1':3, 'data2':1, 'data3':2, 'data4':4}  
    >>> sorted(d.items(), key=itemgetter(1), reverse=True)  
    >>>[('data4', 4), ('data1', 3), ('data3', 2), ('data2', 1)]  
    

    items( )
    dict.items():

    >>>dict = {'Google': 'www.google.com', 'Runoob': 'www.runoob.com', 'taobao': 'www.taobao.com'}
    >>>dict.items()
    >>>dict_items([('Google', 'www.google.com'), ('Runoob', 'www.runoob.com'), ('taobao', 'www.taobao.com')]) #返回的是一个列表
    

    在约会网站使用KNN算法

    #对TXT文件中的数据进行处理
    import numpy as np
    def file2matrix(filename):
        fr = open(filename)#打开某个文件
        arrayOLines = fr.readlines()
        numberOfLines = len(arrayOLines)
        returnMat = np.zeros((numberOfLines,3))
        classLabelVector = []
        index = 0
        for line in arrayOLines:
            line = line.strip() #
            listFromLine = line.split('	') #
            returnMat[index,:] = listFromLine[0:3]
            classLabelVector.append(int(listFromLine[-1])) #
            index +=1
        return returnMat,classLabelVector
    datingDataMat, datingLabels = file2matrix('datingTestSet.txt')   
    

    read( ) & readline( ) & readlines( ):

    >>>f=open('test_read()&readlines().txt')
    >>>f.read()
    >>>'Monday 
    Tuesday 
    Wednesday
    Thursday
    Friday
    Saturaday
    Sunday'   #一次性读取文本中全部的内容,以字符串的形式返回结果
    
    >>>f.readline() 
    >>>'Monday
    '     #只读取文本第一行的内容,以字符串的形式返回结果
    
    >>> f.readlines() 
    >>>['Tuesday
    ', 'Wednesday
    ', 'Thursday
    ', 'Friday
    ', 'Saturday
    ', 'Sunday
    ']    #读取文本所有内容,并且以数列的格式返回结果,一般配合for in使用
    
    

    strip( ):
    strip() 用于移除字符串头尾指定的字符,默认为空格

    >>>str = "0000000     Runoob  0000000"; 
    >>>print str.strip( '0' );  # 去除首尾字符 0
     
     
    >>>str2 = "   Runoob      ";   # 去除首尾空格
    >>>print str2.strip();
    >>>     Runoob
    >>>Runoob
    

    split( ):

    >>>str = "Line1-abcdef 
    Line2-abc 
    Line4-abcd";
    >>>print (str.split( ));
    >>>print (str.split(' ', 1 ));
    
    >>>['Line1-abcdef', 'Line2-abc', 'Line4-abcd']
    >>>['Line1-abcdef', '
    Line2-abc 
    Line4-abcd']
    
    

    归一化特征值
    在K-means的方法中,我们采取的是欧几里得距离。我们观察特征值的大小发现不同特征值在数值上差别很大,这就导致某一个特征值发生一点变化之后,导致欧几里得距离发生很大的变化,所以为了避免这种情况的出现我们决定归一化数据。

    def autoNorm(dataSet):
        minVals = dataSet.min(0)
        maxVals = dataSet.max(0)
        ranges = maxVals - minVals
        normDataSet = np.zeros(np.shape(dataSet))
        m = dataSet.shape[0]
        normDataSet = dataSet - np.tile(minVals, (m,1))
        normDataSet = normDataSet/np.tile(ranges,(m,1))
        return normDataSet, ranges, minVals
    
    normMat,ranges,minVals = autoNorm(datingDataMat)
    normMat
    

    min( ):numpy

    >>>a=np.array([[1,5,3],[4,2,6]])
    >>>print(a.min()) #无参数,所有值中的最小值
    >>>1
    >>>print(a.min(0))#axis=0,每列中的最小值
    >>>[1 2 4]
    >>>print(a.min(1))#axis=1,每行中的最小值
    >>>[1 2]
    

    测试代码

    def datingClassTest():
        hoRatio = 0.1
        datingDataMat, datingLabels = file2matrix('datingTestSet.txt')
        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
        print('the total error rate is : %f ' % (errorCount/float(numTestVecs)))  
    
    datingClassTest()
    

    构建完整的可用系统

    def classifyperson():
        resultList = ['not at all','in small doses','in large doses']
        percenTats = float(input('percentage of time spent playing video games?'))
        ffMiles = float(input('frequent flier miles earned per year?'))
        iceCream= float(input('liters of ice cream consumed per year?'))
        datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
        normMat,ranges,minVals= autoNorm(datingDataMat)
        inArr = np.array([ffMiles,percenTats,iceCream])
        classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
        print('you will probbably like this person: ',resultList[classifierResult -1]) 
        
    classifyperson()
    
  • 相关阅读:
    4-17 文字图片绘制
    4-16 矩形圆形任意多边形绘制
    4-15 线段绘制
    4-14 图像特效小结
    4-13 油画特效
    4-12 颜色映射
    4-11 浮雕效果
    Linux文本截取命令cut​笔记
    45张令程序员泪流满面的趣图
    45张令程序员泪流满面的趣图
  • 原文地址:https://www.cnblogs.com/lzida9223/p/8345424.html
Copyright © 2011-2022 走看看