美文网首页
机器学习:KNN(K 近邻)分类算法

机器学习:KNN(K 近邻)分类算法

作者: moon_light_ | 来源:发表于2020-02-12 00:57 被阅读0次

    kNN 算法不需要经过算法训练,属于懒惰学习,需要训练的属于急切学习
    kNN 是最简单的分类算法

    优点:精度高、对异常值不敏感、无数据输入假定
    缺点:计算复杂度高、空间复杂度高

    工作原理:

    • 输入没有标签的新数据后,将新数据的每个特征与样本集中每个数据对应的特征进行比较,然后算法提取样本集中 k 个特征最相似的数据(最近邻)的分类标签
    • 通过距离矩阵计算相似度(距离):比如 (1, 2, 0, 1) 与 (7, 6, 9, 4) 的距离
        \small d = \sqrt{(7-1)^{2} + (6-2)^{2} + (9-0)^{2} + (4-1)^{2}}
    • 通常 k 是不大于 20 的整数,选择 k 个最相似数据中出现次数最多的分类,作为新数据的分类
    # coding=utf-8
    import numpy as np
    import operator as op
    
    
    # KNN 分类算法
    def classify(inX, dataSet, labels, k):
        """
        inX     - 要预测的特征值矩阵,是一个 (1, n) 的 numpy 矩阵,n 是特征的数量
        dataSet - 样本的特征值矩阵,是一个 (r, n) 的 numpy 矩阵,r 是样本数量,n 是特征的数量
        labels  - 样本的标签,是一个长度为 r 的列表
        k       - 取最近的 k 个样本
        """
    
        # 取样本的数量
        dataSetSize = dataSet.shape[0]
    
        # tile 将 inX 按 (dataSetSize, 1) 平铺,结果是 (r, n) 矩阵,矩阵的每列都是 inX,然后和样本矩阵相减
        # 得到 diffMat 是 inX 的每个特征值和所有样本的差
        diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
    
        # sum(axis=1) 指按第二个下标求和,即
        #     sqDiffMat[0][0] + sqDiffMat[0][1] + sqDiffMat[0][2] + ...... + sqDiffMat[0][n-1]
        #     sqDiffMat[1][0] + sqDiffMat[1][1] + sqDiffMat[0][2] + ...... + sqDiffMat[1][n-1]
        # 得到一个 (r, 1) 矩阵
        # 再开根,得到 inX 和每个样本的距离
        sqDiffMat = diffMat**2
        sqDistances = sqDiffMat.sum(axis=1)
        distances = sqDistances**0.5
    
        # 对距离按从小到大排序,并返回索引值,即 distances[sortedDistIndex[0]] 是 distances 的最小值
        sortedDistIndex = distances.argsort()
    
        classCount = {}
        # 取距离最近的 k 个样本
        for i in range(k):
            # 取样本的标签值
            votedLabel = labels[sortedDistIndex[i]]
            # 统计每个标签值的数量
            classCount[votedLabel] = classCount.get(votedLabel, 0) + 1
    
        # classCount.iteritems 得到为迭代器
        # op.itemgetter(1) 取每个数据的第二个域的值,即 label 的次数
        # 从大到小排序
        sortedClassCount = sorted(classCount.iteritems(), key=op.itemgetter(1), reverse=True)
    
        # 返回距离最近的 k 个样本中出现次数最多的标签值
        return sortedClassCount[0][0]
    
    
    # 从文件中取样本数据
    def readDataFromFile(filename, featureNumber):
        """
        文件的每一行是一条数据,最后一列是标签,其余列是特征值,共 fieldNumber 个特征
        """
        numberOfLines = 0
        with open(filename) as f:
            # 统计行数,数据量太大时 len(f.readlines()) 可能无法工作,所以采用循环的方式
            while True:
                tempBuffer = f.read(8192 * 1024)
                if not tempBuffer:
                    numberOfLines = numberOfLines + 1
                    break
                numberOfLines += tempBuffer.count('\n')
    
        # 特征值矩阵
        featureMat = np.zeros((numberOfLines, featureNumber))
        # 标签列表
        classLabelVector = []
    
        with open(filename) as f:
            index = 0
            while True:
                line = f.readline()
                if line:
                    line = line.strip()
                    fields = line.split('\t')
                    featureMat[index, :] = fields[0:featureNumber]
                    classLabelVector.append(int(fields[featureNumber]))
                    index += 1
                else:
                    break
    
        return featureMat, classLabelVector
    
    
    # 归一化数据
    def normalize(dataSet):
        # dataSet.min(0) 按第一个下标求最小值,即求
        #   min(dataSet[0][0], dataSet[1][0], dataSet[2][0], ..., dataSet[m][0])
        #   min(dataSet[0][1], dataSet[1][1], dataSet[2][1], ..., dataSet[m][1])
        # 结果是求每列,即每个特征值的最大和最小值
        minVals = dataSet.min(0)
        maxVals = dataSet.max(0)
    
        # 最大值和最小值的差
        ranges = maxVals - minVals
    
        # np.tile(minVals, (m, 1)) 复制 m 个 minVals,方便矩阵的计算
        # 归一化 newValue = (oldValue - min)/(max - min) 将所有数据转换到 (0, 1)
        m = dataSet.shape[0]
        normDataSet = dataSet - np.tile(minVals, (m, 1))
        normDataSet = normDataSet/np.tile(ranges, (m, 1))
    
        return normDataSet
    
    
    # 测试
    def classifyTest():
        # 10% 的数据作测试集,90% 的数据作样本集
        ratio = 0.10
    
        # 读数据
        featureNumber = 10
        featureMat, classLabelVector = readDataFromFile('kNN.txt', featureNumber)
    
        # 归一化
        normDataSet = normalize(featureMat)
    
        # 数据量
        m = normDataSet.shape[0]
    
        # 测试集大小
        numTest = int(m * ratio)
    
        errorCount = 0
        for i in range(numTest):
            result = classify(normDataSet[i, :], normDataSet[numTest:m, :], classLabelVector[numTest:], featureNumber)
            if result != classLabelVector[i]:
                errorCount += 1
    
            print "predict result: %d, real answer is: %d" % (result, classLabelVector[i])
    
        print "error count: %d, total: %d" % (errorCount, numTest)
        print "the total error rate is: %f" % (errorCount / float(numTest))
    
    



    相关文章

      网友评论

          本文标题:机器学习:KNN(K 近邻)分类算法

          本文链接:https://www.haomeiwen.com/subject/fexqfhtx.html