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


总结


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

目录
相关文章
|
9天前
|
数据库 Python
Python 应用
Python 应用。
30 4
|
17天前
|
数据采集 存储 JSON
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第27天】本文介绍了Python网络爬虫Scrapy框架的实战应用与技巧。首先讲解了如何创建Scrapy项目、定义爬虫、处理JSON响应、设置User-Agent和代理,以及存储爬取的数据。通过具体示例,帮助读者掌握Scrapy的核心功能和使用方法,提升数据采集效率。
60 6
|
18天前
|
数据采集 数据安全/隐私保护 开发者
非阻塞 I/O:异步编程提升 Python 应用速度
非阻塞 I/O:异步编程提升 Python 应用速度
|
8天前
|
机器学习/深度学习 数据采集 数据可视化
Python在数据科学中的应用:从入门到实践
本文旨在为读者提供一个Python在数据科学领域应用的全面概览。我们将从Python的基础语法开始,逐步深入到数据处理、分析和可视化的高级技术。文章不仅涵盖了Python中常用的数据科学库,如NumPy、Pandas和Matplotlib,还探讨了机器学习库Scikit-learn的使用。通过实际案例分析,本文将展示如何利用Python进行数据清洗、特征工程、模型训练和结果评估。此外,我们还将探讨Python在大数据处理中的应用,以及如何通过集成学习和深度学习技术来提升数据分析的准确性和效率。
|
6天前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
垃圾识别分类系统。本系统采用Python作为主要编程语言,通过收集了5种常见的垃圾数据集('塑料', '玻璃', '纸张', '纸板', '金属'),然后基于TensorFlow搭建卷积神经网络算法模型,通过对图像数据集进行多轮迭代训练,最后得到一个识别精度较高的模型文件。然后使用Django搭建Web网页端可视化操作界面,实现用户在网页端上传一张垃圾图片识别其名称。
29 0
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
|
6天前
|
机器学习/深度学习 人工智能 算法
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
手写数字识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法。并通过对数据集进行训练,最后得到一个识别精度较高的模型。并基于Flask框架,开发网页端操作平台,实现用户上传一张图片识别其名称。
22 0
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
|
6天前
|
机器学习/深度学习 人工智能 算法
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
蔬菜识别系统,本系统使用Python作为主要编程语言,通过收集了8种常见的蔬菜图像数据集('土豆', '大白菜', '大葱', '莲藕', '菠菜', '西红柿', '韭菜', '黄瓜'),然后基于TensorFlow搭建卷积神经网络算法模型,通过多轮迭代训练最后得到一个识别精度较高的模型文件。在使用Django开发web网页端操作界面,实现用户上传一张蔬菜图片识别其名称。
26 0
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
|
10天前
|
机器学习/深度学习 JSON API
Python编程实战:构建一个简单的天气预报应用
Python编程实战:构建一个简单的天气预报应用
25 1
|
10天前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
28 2
|
18天前
|
数据可视化 开发者 Python
Python GUI开发:Tkinter与PyQt的实战应用与对比分析
【10月更文挑战第26天】本文介绍了Python中两种常用的GUI工具包——Tkinter和PyQt。Tkinter内置于Python标准库,适合初学者快速上手,提供基本的GUI组件和方法。PyQt基于Qt库,功能强大且灵活,适用于创建复杂的GUI应用程序。通过实战示例和对比分析,帮助开发者选择合适的工具包以满足项目需求。
63 7