机器学习实战(一):K-近邻算法(史上最全干货) 算法总结+案例实战

一、k-近邻算法

1. k-近邻法简介
k近邻法(k-nearest neighbor, k-NN)是1968年由Cover THart 提出的一种基本分类与回归方法。它的工作原理是:存在一个样本数据集合,也称作为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据后,将新的数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。

注意: k-近邻法不具有显式的学习过程,它实际上是利用训练数据集对特征向量空间进行划分,并作为其分类的“模型”.其中K值的选取、距离度量及分类决策规则是k近邻算法的三个基本要素。

2. k近邻算法的数学语言表达:

机器学习实战(一):K-近邻算法(史上最全干货) 算法总结+案例实战_第1张图片

3. k近邻算法中k值的选取标准:

机器学习实战(一):K-近邻算法(史上最全干货) 算法总结+案例实战_第2张图片

4. 在k近邻算法中的距离度量公式如下图所示:

机器学习实战(一):K-近邻算法(史上最全干货) 算法总结+案例实战_第3张图片

5. k-近邻算法中的分类决策规则
机器学习实战(一):K-近邻算法(史上最全干货) 算法总结+案例实战_第4张图片

6. K近邻算法的一般流程

  1. 计算已知类别数据集中的点与当前点之间的距离;
  2. 按照距离递增次序排序;
  3. 选取与当前点距离最小的k个点;
  4. 确定前k个点所在类别的出现频率;
  5. 返回前k个点出现频率最高的类别作为当前点的预测分类

二、k-近邻算法案列实战:实现电影分类

本次案例主要是使用k-近邻算法来对电影进行分类。这里我们主要将电影分为两种:爱情片和动作片。根据电影中出现的打斗和接吻镜头来进行判定。本案例所使用的距离度量为欧氏距离。

  1. 准备数据集
    机器学习实战(一):K-近邻算法(史上最全干货) 算法总结+案例实战_第5张图片
    结果显示:
    机器学习实战(一):K-近邻算法(史上最全干货) 算法总结+案例实战_第6张图片
  2. 根据欧式距离公式,计算距离,选择距离最小的前k个点。根据你输入的电影数据信息,程序返回分类结果。
    程序代码如下:
def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances**0.5
    sortedDistIndices = distances.argsort()
    classCount = {}
    for i in range(k):
        voteIlabel = labels[sortedDistIndices[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    #返回次数最多的类别,即所要分类的类别
    return sortedClassCount[0][0]
 
if __name__ == '__main__':
    #创建数据集
    group, labels = createDataSet()
    #对输入数据进行分类
    x = input("请输入测试数据:")
    xlist=x.split(" ")
    test = [int(xlist[i]) for i in range(len(xlist))]
    #kNN分类
    test_class = classify0(test, group, labels, 3)
    #打印分类结果
    print(test_class)

结果如下:
机器学习实战(一):K-近邻算法(史上最全干货) 算法总结+案例实战_第7张图片

三、k-近邻算法案例实战:手写数字识别系统

本节我们一步步地构造使用k-近邻分类器的手写识别系统。为了简单起见,这里构造的系统
只能识别数字0到9.需要识别的数字已经使用图形处理软件,处理成具有相同的色
彩和大小,其中宽高是32像素×32像素的黑白图像。尽管采用文本格式存储图像不能有效地利用内
存空间,但是为了方便理解,我们还是将图像转换为文本格式。
存储的数字文件格式为:数字的值_该数字的样本序号,如下图所示:
机器学习实战(一):K-近邻算法(史上最全干货) 算法总结+案例实战_第8张图片
数据集分为训练集和测试集,通过上述电影分类的方法,设计一个k-近邻算法分类器实现数字分类。其中数据集和实现代码下载地址:数据集下载

代码展示:

import numpy as np
import operator
from os import listdir

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={} 
    #选择距离最小的K个点
    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]
    
def img2vector(filename):
    returnVect = np.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 = np.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)))

识别结果如下所示:
机器学习实战(一):K-近邻算法(史上最全干货) 算法总结+案例实战_第9张图片

四、总结

kNN算法的优缺点
优点:

  • 简单好用,容易理解,精度高,理论成熟,既可以用来做分类也可以用来做回归;
  • 可用于数值型数据和离散型数据;
  • 训练时间复杂度为O(n);无数据输入假定;
  • 对异常值不敏感

缺点:

  • 计算复杂性高;空间复杂性高;
  • 样本不平衡问题(即有些类别的样本数量很多,而其它样本的数量很少);
  • 一般数值很大的时候不用这个,计算量太大。但是单个样本又不能太少,否则容易发生误分。
  • 最大的缺点是无法给出数据的内在含义。

参考资料:
本文中提到的电影分类、手写数字识别实例和数据集,均来自于《机器学习实战》的第二章k-近邻算法。
本文的算法理论部分,参考自《统计学习方法 李航》的第三章k近邻法以及《机器学习实战》的第二章k-近邻算法。

你可能感兴趣的:(机器学习,机器学习实战)