Ivan
  • 首页
  • 友链
  • 留言
  • 关于

K-nearest neighbor

Ivan 发布于 2022-03-31

  • 📒 Machine Learning
  • 📒 Classification
  • 🏷️ Python
  • 🏷️ Machine Learning
  • 🏷️ kNN

k-近邻算法

本章内容
k-近邻分类算法
从文本文件中解析和导入数据
使用Matplotlib创建扩散图
归一化数值

K-近邻(k-Nearest Neighbor,KNN),是一种常用于分类的算法,是有成熟理论支撑的、较为简单的经典机器学习算法之一。本文主要讲解如何在实际环境中应用k-近邻分类算法,同时涉及如何使用Python工具和相关机器学习术语,算法原理详见数据挖掘十大算法–K近邻算法。

Github代码获取

https://github.com/Ivan020121/Machine-Learning/tree/main/K-nearest%20neighbor%20algorithm

k-近邻算法概述

简单地说,k-近邻算法采用测量不同特征值之间的距离方法进行分类。

k-近邻算法
优点:精度高、对异常值不敏感、无数据输入假定。
缺点:计算复杂度高、空间复杂度高。
适用数据范围:数值型和标称型。

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

k-近邻算法的一般流程
(1) 收集数据:可以使用任何方法
(2) 准备数据:距离计算所需要的数值,最好是结构化的数据格式。
(3) 分析数据:可以使用任何方法。
(4) 训练算法:此步骤不适用于k-近邻算法。
(5) 测试算法:计算错误率。
(6) 使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。

准备:使用Python导入数据

首先,创建名为kNN.py的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


k-近邻算法:带有4个数据点的简单例子
在上面的代码中,我们导入了两个模块:一个是科学计算包NumPy,第二个是运算符模块,k-近邻算法执行排序操作时将使用这个模块提供的函数,后面我们将进一步介绍。

实施kNN分类算法

k-近邻算法的伪代码
对未知类别属性的数据集中的每个点依次执行以下操作:
(1) 计算已知类别数据集中的点与当前点之间的距离;
(2) 按照距离递增次序排序;
(3) 选取与当前点距离最小的k个点;
(4) 确定前k个点所在类别的出现频率;
(5) 返回前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]

classify0()函数有4个参数输入:用于分类的输入向量是inX,输入的训练样本集为dataSet,标签向量为labels,最后的参数k表示用于选择最近邻居的数目,其中标签向量的元素数目和矩阵dataSet的行数相同。

示例:使用k-近邻算法改进约会网站的配对效果

示例:在约会网站上使用k-近邻算法
(1) 收集数据:提供文本文件。
(2) 准备数据:使用Python解析文本文件。
(3) 分析数据:使用Matplotlib画二维扩散图。
(4) 训练算法:此步骤不适应与k-近邻算法
(5) 测试算法:使用海伦提供的部分数据作为测试样本。
(6) 使用算法:产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方是否为自己喜欢的类型。

准备数据:从文本文件中解析式数据

数据文本文件:datingTestSet2.txt.样本主要包含以下3种数据:

每年获得的飞行常客里程数
玩视频游戏所消耗时间百分比
每周消费的冰淇淋公升数

在kNN.py中创建名为file2matrix的函数,以此来处理输入格式问题。

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

分析数据:使用Matplotlib创建散点图

下面就用Python工具来图形化展示数据内容,以便辨识出一些数据模式。

import matplotlib
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:, 0], datingDataMat[:, 1], 15.0*array(datingLabels), 15.0*array(datingLabels))
plt.show()


约会数据散点图

准备数据:归一化数值

在量纲不一而对比标准统一的时候需要做归一化,数据归一化的目的是为了把不同来源的数据统一到一个参考系下,这样比较起来才有意义。

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

测试算法:作为完整程序验证分类器

为了测试分类器效果,在kNN.py文件中创建datingClassTest。

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)

示例:手写识别系统

k-近邻分类器的手写识别系统。

示例:使用k-近邻分类器的手写识别系统
(1) 收集数据:提供文本文件。
(2) 编写img2vector(),将图像格式转换为向量格式。
(3) 分析数据:检查数据。
(4) 训练算法:此步骤不适用于k-近邻算法
(5) 预测分类并与实际分类对比。
(6) 使用算法:完成数字识别系统。

准备数据:将图像转换为测试向量

数据目录:trainingDigits testDigits

函数img2vector将图像格式化处理为一个1×1024的向量,将上述代码输入到kNN.py文件中。

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

测试算法:用k-近邻分类器的识别手写数字

自包含函数handwritingClassTest()是测试分类器的代码,将其写入kNN.py文件中。

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)))

小结

k-近邻算法是分类数据最简单最有效的算法,是基于实例的学习,使用算法时我们必须有接近实际数据的训练样本数据。k-近邻算法必须保存全部数据集,如果训练数据集的很大,必须使用大量的存储空间。此外,由于必须对数据集中的每个数据计算距离值,实际使用时可能非常耗时。


🤯本文作者:Ivan
🔗本文链接:https://ivan020121.github.io/2022/03/31/kNN/
🔁版权声明:本站所有文章除特别声明外,均采用©BY-NC-SA许可协议。转载请注明出处!

Decision tree

Newer

Markdown

Older
Ivan

Ivan

学无止境

7
3
11
TOC
  1. 1. Github代码获取
  2. 2. k-近邻算法概述
    1. 2.1. 准备:使用Python导入数据
    2. 2.2. 实施kNN分类算法
  3. 3. 示例:使用k-近邻算法改进约会网站的配对效果
    1. 3.1. 准备数据:从文本文件中解析式数据
    2. 3.2. 分析数据:使用Matplotlib创建散点图
    3. 3.3. 准备数据:归一化数值
    4. 3.4. 测试算法:作为完整程序验证分类器
  4. 4. 示例:手写识别系统
    1. 4.1. 准备数据:将图像转换为测试向量
    2. 4.2. 测试算法:用k-近邻分类器的识别手写数字
  5. 5. 小结
NOTICE

我的动力来自盲目和愚钝。

CATEGORYS
  • Machine Learning (3)
  • Classification (3)
  • 学习笔记 (2)
TAGS
Anaconda Decision tree Linux Machine Learning Markdown MongoDB Naive bayes Python Server VSCode kNN

© 2022 Ivan

Powered by Hexo Theme - flex-block

🌞 浅色 🌛 深色 🤖️ 自动