k-近邻算法(KNN)详解及python实现和应用

简介: k-近邻算法(KNN)详解及python实现和应用

一、KNN算法概述


工作原理:存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都纯在标签,就每一个样本都有一个标签与之对应。输入没带标签的新数据之后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签,然后给新数据该标签。我们只选择样本数据集中前k个最相似的数据,最后选择k个最相似数据中出现次数最多的分类,作为新数据的分类。


光看文字理解显然不够深刻,来看看图片。


2020100419505293.png

假定新加入了一个绿正方形,现在我们要判定它是属于三角形还是属于圆形。首先根据先看距离正方形最近的图形有哪些,根据它们离正方形的距离进行排序,再根据确定的k值进行划分,选出离目标最近的k个图形,然后判定在k个里面哪个图形占多数,占多数的则把该目标归为哪一类。


这样应该很好理解,也说明了KNN算法的结果很大程度取决于K的选择,其中K通常是不大于20的整数。KNN算法中,所选择的邻居都是已经正确分类的对象。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。


二、距离度量


因为在各种不同的环境下采用knn算法,度量变量距离也有许多种不同的算法。免了对象之间的匹配问题。在KNN算法中一般采用的是欧氏距离或曼哈顿距离:


欧氏距离(二维):

20201004200432434.png

曼哈顿距离(二维):

20201004200511957.png


三、实现算法


首先算法一般流程

.收集数据->处理数据(标准化)->分析数据->训练算法->测试算法->使用算法


20201015190711128.jpg



先创建数据导入块

import numpy as np
import operator
from matplotlib import pyplot as plt
#创建数据集
def createrDataSet():
    group = np.array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels = ['A','A','B','B']
    return group,labels

20201004220710821.png


类似这种效果,如何开始写入knn算法


20201015191020143.jpg

from numpy import *
import operator
#创建数据集
def createrDataSet():
    group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels = ['A','A','B','B']
    return group,labels
ture = 1
#inX:输入向量; dataSet:训练样本集; labels:标签向量 k=最近邻居个数; 其中标签元素数目和矩阵dataSet的行数相同。
def classify0(inX,dataSet,labels,k):
    dataSetSize = dataSet.shape[0] #行数
    #计算欧式距离
    diffMat = tile(inX,(dataSetSize,1))-dataSet #扩展dataSet行,分别相减,形成(x1-x2)矩阵
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances**0.5
    sortedDistIndicies = distances.argsort()#从小到大排序,获得索引值(下标)
    #选择距离最小的k个点
    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=ture)
    return sortedClassCount[0][0]

具体实现过程已经在代码中标识出来了。

我们可以通过简单的测试。

import KNN
from numpy import *
dataSet,labels = KNN.createrDataSet()
inX = array([0,0.3])
k = 3
output = KNN.classify0(inX,dataSet,labels,k)
print("测试数据为:",inX,"分类结果为:",output)

20201004221203785.png

PS.按照机器学习实战的那本来敲代码的话可能会遇到'dict' object has no attribute 'iteritems'。

原因:iteritems是为python2环境中dict的函数。在python3报错,将iteritems改为items即可。


四、实战练习


练习当然是我们的海伦约会实例,也是最常见拿来练手的例子了。


海伦女士一直使用在线约会网站寻找适合自己的约会对象。尽管约会网站会推荐不同的人选,但她并不是喜欢每一个人。经过一番总结,她发现自己交往过的人可以进行如下分类:


不喜欢的人

魅力一般的人

极具魅力的人

首先准备数据,海伦收集的样本数据主要包含以下3种特征:


每年获得的飞行常客里程数

玩视频游戏所消耗时间百分比

每周消费的冰淇淋公升数


1.转换数据


将文本记录转换为Numpy解析程序

#处理数据格式
#输入文件名字符串,输出为训练样本矩阵和类标签
def file2matrix(filename):
    fr = open(filename)
    arrayOLines = fr.readlines()#得到文件行数
    numberOfLines = len(arrayOLines)
    returnMat = zeros((numberOfLines,3))#得到与之对应行数,3列的0填充矩阵
    classLabelVector = []
    index = 0
    for line in arrayOLines:
        line = line.strip()#截取所有回车字符
        listFromLine = line.split('\t')#按tap格式分割
        returnMat[index,:] = listFromLine[0:3]#从头开始填充
        classLabelVector.append((listFromLine[-1]))#将标签保留
        index += 1
# datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
# print(datingDateMat,datingLabels)
from collections import Counter
##将列表的最后一列由字符串转化为数字,便于以后的计算
    dictClassLabel = Counter(classLabelVector)
    classLabel = []
    kind = list(dictClassLabel)
    for item in classLabelVector:
        if item == kind[0]:
            item = 1
        elif item == kind[1]:
            item = 2
        else:
            item = 3
        classLabel.append(item)
    return returnMat,classLabel#####将文本中的数据导入到列表


我们可以看到数据

20201005201650370.png

2.分析数据


我们可以使用Matplotlib创建散点图

import matplotlib
import matplotlib.pyplot as plt
#绘制散点图
fig = plt.figure()
ax = fig.add_subplot(111)#分割为1行1列第1块
ax.scatter(datingDataMat[:,1], datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))
plt.show()


这里对比一下‘玩视频游戏所消耗时间百分比’和‘每周消费的冰淇淋公升数’

很明显

image.png

image.png


数据还没有处理好看不出什么效果。


3.数据归一化


因为根据knn采用的为欧式距离,在数据属性权重相同的情况下,数字差值最大的属性对计算结果影响最大,所以我们必须使用数据归一化避免相比差值过大严重影响计算结果。


那么接下来我们进行数据归一化,考虑到使用Min-Max标准可能如果max和min不稳定,很容易使得归一化结果不稳定,使得后续使用效果也不稳定。所以我们采用Z-score标准化。数据预处理归一化详细解释


from sklearn.preprocessing import StandardScaler
def autoNorm(dataSet):
    sc = StandardScaler()
    normDataSet =sc.fit_transform(datingDataMat)
    mean = sc.mean_
    std = sqrt(sc.var_)
    return normDataSet,mean,std

很明显归一化的数据很易于分析:

20201005204050108.png


4.测试算法


接下来开始评估我们算法的可靠性,通常我们只提供已有数据的90%作为训练样本训练分类器,而使用其余的10%数据去测试分类器。一开始想使用线性回归的

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y,
                                                    test_size=0.1,
                                                    random_state=0)

发现只能二值计算,有点尴尬,不知道大家有什么好的方法来划分数据集,安装书上的方法属实是最原始的划分方法。

def datingClassTest():
    #将返回的特征矩阵和分类向量分别存储到datingDataMat和datingLabels中
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    #取所有数据的百分之十
    hoRatio = 0.10
    #数据归一化,返回归一化后的矩阵,数据范围,数据最小值
    normMat= autoNorm(datingDataMat)
    #获得normMat的行数
    m = normMat.shape[0]
    #百分之十的测试数据的个数
    numTestVecs = int(m * hoRatio)
    #分类错误计数
    errorCount = 0.0
    for i in range(numTestVecs):
        #前numTestVecs个数据作为测试集,后m-numTestVecs个数据作为训练集
        classifierResult = KNN.classify0(normMat[i,:], normMat[numTestVecs:m,:],
            datingLabels[numTestVecs:m], 4)
        print("分类结果:%s\t真实类别:%d" % (classifierResult, datingLabels[i]))
        if classifierResult != datingLabels[i]:
            errorCount += 1.0
    print("错误率:%f%%" % (errorCount / float(numTestVecs) * 100))

20201005205523273.png


这是没简化标签时候截的图,后面优化了一下便于计算

20201005205637187.png


5.使用算法


经过测试我们的knn算法还算不错,现在我们可以编写一个窗口来使用这个分类器了:

def classifyPerson():
    #输出结果
    resultList = ['讨厌','有些喜欢','非常喜欢']
    #三维特征用户输入
    precentTats = float(input("玩视频游戏所耗时间百分比:"))
    ffMiles = float(input("每年获得的飞行常客里程数:"))
    iceCream = float(input("每周消费的冰激淋公升数:"))
    #打开的文件名
    filename = "datingTestSet2.txt"
    #打开并处理数据
    datingDataMat, datingLabels = file2matrix(filename)
    #训练集归一化
    normMat, mean, std = autoNorm(datingDataMat)
    #生成NumPy数组,测试集
    inArr = array([ffMiles, precentTats, iceCream])
    #测试集归一化
    norminArr = (inArr - mean) / std
    #返回分类结果
    classifierResult =KNN.classify0(norminArr, normMat, datingLabels, 3)
    #打印结果
    print("你可能%s这个人" % (resultList[classifierResult-1]))
classifyPerson()

附上我理想女友的数据

20201005211253267.png


确实有点喜欢哈哈哈

20201015202712493.png


总结


具体算法应该很好理解,要使用起来也不难,很好掌握的一个算法,就是在不同的环境下要考虑该如何改进再使用。下一篇开始学习决策树了。

目录
相关文章
|
8天前
|
机器学习/深度学习 数据采集 自然语言处理
理解并应用机器学习算法:神经网络深度解析
【5月更文挑战第15天】本文深入解析了神经网络的基本原理和关键组成,包括神经元、层、权重、偏置及损失函数。介绍了神经网络在图像识别、NLP等领域的应用,并涵盖了从数据预处理、选择网络结构到训练与评估的实践流程。理解并掌握这些知识,有助于更好地运用神经网络解决实际问题。随着技术发展,神经网络未来潜力无限。
|
3天前
|
算法 Java
并发垃圾回收算法对于大规模服务器应用的优势
并发垃圾回收算法对于大规模服务器应用的优势
|
2天前
|
存储 算法 安全
Python编程实验六:面向对象应用
Python编程实验六:面向对象应用
18 1
|
3天前
|
缓存 API 数据库
构建高效Python Web应用:Flask框架与RESTful API设计原则
【5月更文挑战第20天】 在现代Web开发中,构建一个轻量级且高效的后端服务至关重要。本文将深入探讨如何使用Python的Flask框架结合RESTful API设计原则来创建可扩展和易于维护的Web应用程序。我们将通过分析Flask的核心特性,以及如何利用它来实现资源的合理划分、接口的版本控制和请求处理优化等,来指导读者打造高性能的API服务。文中不仅提供了理论指导,还包括了实践案例,旨在帮助开发者提升开发效率,并增强应用的稳定性和用户体验。
|
3天前
|
机器学习/深度学习 人工智能 算法
食物识别系统Python+深度学习人工智能+TensorFlow+卷积神经网络算法模型
食物识别系统采用TensorFlow的ResNet50模型,训练了包含11类食物的数据集,生成高精度H5模型。系统整合Django框架,提供网页平台,用户可上传图片进行食物识别。效果图片展示成功识别各类食物。[查看演示视频、代码及安装指南](https://www.yuque.com/ziwu/yygu3z/yhd6a7vai4o9iuys?singleDoc#)。项目利用深度学习的卷积神经网络(CNN),其局部感受野和权重共享机制适于图像识别,广泛应用于医疗图像分析等领域。示例代码展示了一个使用TensorFlow训练的简单CNN模型,用于MNIST手写数字识别。
18 3
|
3天前
|
算法 Python
Python中实现图论算法
Python中实现图论算法 “【5月更文挑战第20天】”
13 3
|
5天前
|
网络协议 Python
Python 网络编程实战:构建高效的网络应用
【5月更文挑战第18天】Python在数字化时代成为构建网络应用的热门语言,因其简洁的语法和强大功能。本文介绍了网络编程基础知识,包括TCP和UDP套接字,强调异步编程、数据压缩和连接池的关键作用。提供了一个简单的TCP服务器和客户端代码示例,并提及优化与改进方向,鼓励读者通过实践提升网络应用性能。
23 6
|
5天前
|
算法 搜索推荐 Java
滚雪球学Java(33):数组算法大揭秘:应用案例实战分享
【5月更文挑战第8天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
32 8
滚雪球学Java(33):数组算法大揭秘:应用案例实战分享
|
5天前
|
数据可视化 数据挖掘 数据处理
Python中的数据可视化技术及应用
数据可视化是数据分析中至关重要的一环,而Python作为一种强大的编程语言,提供了丰富的数据可视化工具和库。本文将介绍Python中常用的数据可视化技术及其在实际应用中的案例,帮助读者更好地理解和运用数据可视化技术。
|
5天前
|
缓存 Python
Python中的装饰器应用及实践
Python中的装饰器是一种强大的编程工具,它可以在不更改原函数代码的情况下,对函数进行扩展和修改。本文将介绍装饰器的基本概念,探讨其在Python开发中的实际应用,并结合示例代码进行详细解析。