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


总结


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

目录
相关文章
|
2月前
|
算法 搜索推荐 JavaScript
基于python智能推荐算法的全屋定制系统
本研究聚焦基于智能推荐算法的全屋定制平台网站设计,旨在解决消费者在个性化定制中面临的选择难题。通过整合Django、Vue、Python与MySQL等技术,构建集家装设计、材料推荐、家具搭配于一体的一站式智能服务平台,提升用户体验与行业数字化水平。
|
3月前
|
存储 算法 调度
【复现】【遗传算法】考虑储能和可再生能源消纳责任制的售电公司购售电策略(Python代码实现)
【复现】【遗传算法】考虑储能和可再生能源消纳责任制的售电公司购售电策略(Python代码实现)
198 26
|
3月前
|
监控 数据可视化 数据挖掘
Python Rich库使用指南:打造更美观的命令行应用
Rich库是Python的终端美化利器,支持彩色文本、智能表格、动态进度条和语法高亮,大幅提升命令行应用的可视化效果与用户体验。
240 0
|
2月前
|
机器学习/深度学习 数据采集 人工智能
【机器学习算法篇】K-近邻算法
K近邻(KNN)是一种基于“物以类聚”思想的监督学习算法,通过计算样本间距离,选取最近K个邻居投票决定类别。支持多种距离度量,如欧式、曼哈顿、余弦相似度等,适用于分类与回归任务。结合Scikit-learn可高效实现,需合理选择K值并进行数据预处理,常用于鸢尾花分类等经典案例。(238字)
|
3月前
|
机器学习/深度学习 算法 安全
【强化学习应用(八)】基于Q-learning的无人机物流路径规划研究(Python代码实现)
【强化学习应用(八)】基于Q-learning的无人机物流路径规划研究(Python代码实现)
230 6
|
3月前
|
机器学习/深度学习 编解码 算法
【机器人路径规划】基于迪杰斯特拉算法(Dijkstra)的机器人路径规划(Python代码实现)
【机器人路径规划】基于迪杰斯特拉算法(Dijkstra)的机器人路径规划(Python代码实现)
340 4
|
3月前
|
机器学习/深度学习 算法 机器人
【机器人路径规划】基于A*算法的机器人路径规划研究(Python代码实现)
【机器人路径规划】基于A*算法的机器人路径规划研究(Python代码实现)
500 4
|
3月前
|
算法 机器人 定位技术
【机器人路径规划】基于流场寻路算法(Flow Field Pathfinding)的机器人路径规划(Python代码实现)
【机器人路径规划】基于流场寻路算法(Flow Field Pathfinding)的机器人路径规划(Python代码实现)
184 4
|
3月前
|
机器学习/深度学习 算法 机器人
【机器人路径规划】基于深度优先搜索(Depth-First-Search,DFS)算法的机器人路径规划(Python代码实现)
【机器人路径规划】基于深度优先搜索(Depth-First-Search,DFS)算法的机器人路径规划(Python代码实现)
266 3
|
3月前
|
机器学习/深度学习 算法 机器人
【机器人路径规划】基于D*算法的机器人路径规划(Python代码实现)
【机器人路径规划】基于D*算法的机器人路径规划(Python代码实现)
197 0

推荐镜像

更多