k-近邻算法

GeaFlow图计算快速上手之K-hop算法 K-hop算法是一种基于图论的算法,用于寻找一个起点通过K次以内跳跃能够到达的节点,也就是从起点出发,找出K层内与之关联的节点。K-hop算法广泛应用于好友推荐、影响力预测和关系发现等场景。K-hop算法本质上是一种广度优先搜索(BFS)算法,通过从起点开始不断向外扩散的方式来计算每一个节点到起点的跳跃数。 阅读详情

1. 算法概述:是一种基本分类和回归的算法。k近邻法的输入为实例的特征向量,对应于特征空间的点;输出为实例的类别,可以取多类。k近邻法假设给定一个训练数据集,其中的实例类别已定。分类时,对新的实例,根据其k个最近邻的训练实例的类别,通过多数表决等方式进行预测。因此,k近邻不具有显示的学习过程。k近邻实际上是利用训练数据集对特征向量空间进行划分,并作为其分类的“模型”。k值的选择、距离度量及分类决策规则是k近邻法的三个基本要素。k-近邻法于1968年由Cover和Hart提出。(简单的说就是:给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的k个实例,在这k个实例的多数都属于某个类,就把这个新的输入实例分为这个类。)

k近邻算法

输入:训练数据集

                                      T=\left\{(x_1,y_1),(x_2,y_2),...(x_N,y_N) \right \}

其中,x_i\in X\subseteq R^{n}为实例的特征向量,y_{i}\in Y=\left \{ c_1,c_2,..., c_K\right \}为实例的类别,i=1,2,...,N;实例特征向量x;

输出:实例x所属的类y。

(1)根据给定的距离度量,在训练数据集T中找到与x最近邻的k个点,涵盖这k个点的x的邻域记作N_k(x);

(2)在N_k(x)中根据分类决策规则(如多数表决)决定x的类别y:

                                     y=arg \max_{c_{j}} \sum_{x_{i}\in N_k(x)}I(y_{i}=c_{j}),\quad i=1,2,...,K (1.1)

式(1.1)中,I 为指示函数,即当y_i=c_j时 I为1,否则I为0。

k近邻法的情况是k=1的情况,称为最近邻算法。对于输入的实例点(特征向量)x,最近邻法将训练数据集中与x最近邻点的类作为x的类。

\Rightarrowk近邻没有显示学习的过程

 

2 k近邻模型

k近邻模型对应于对特征空间的划分。模型由三个基本要素组成:距离度量、k值选择和分类决策规则

2.1 模型

k近邻算法中,当训练集、距离度量(如欧式距离)、k值及分类决策规则(如多数表决)确定后,对于任何一个新的输入实例,它所属的类唯一地确定。这相当于根据上述要素将特征空间划分为一些子空间,确定子空间里的每个点所属的类。

特征空间中,对每个训练实例点x_{i},距离该点比其他点更近的所有点组成一个区域,叫做单元。每个训练实例点都拥有一个单元,所有训练实例点的单元构成对特征空间的一个划分。最近邻法将实例x_{i}的类y_{i}作为其单元中所有点的类标记。这样,每个单元的实例点的类别是确实的。

2.2 距离度量

特征空间中两个实例点的距离是两个实例点相似程度的反映。k近邻模型的特征一般是n维实数向量空间R^{n}。使用的距离是欧式距离,但也可以是其他距离,如更一般的L_{p}距离或Minkowski距离。

设特征空间X是n维实例向量空间R^{n},x_{i},x_{j}\in X,x_{i}=(x_{i}^{(1)},x_{i}^{(2)},...,x_{i}^{(n)})^{T},x_{j}=(x_{j}^{(1)},x_{j}^{(2)},...,x_{j}^{(n)})^{T},x_{i},x_{j}的L_{p}距离定义为 

                                                           L_{p}(x_{i},x_{j})=\left (\sum_{l=1}^{n}\left | x_{i}^{(l)}-x_{j}^{(l)} \right |^{p} \right )^{\frac{1}{p}} \quad \quad (2.1)

这里p\geq 1,当p=2时,称为欧式距离,即

                                                          L_{2}(x_{i},x_{j})=\left (\sum_{l=1}^{n}\left | x_{i}^{(l)}-x_{j}^{(l)} \right |^{2} \right )^{\frac{1}{2}} \quad \quad (2.2)

当p=1时,称为曼哈顿距离,即

                                                         L_{1}(x_{i},x_{j})=\sum_{l=1}^{n}\left | x_{i}^{(l)}-x_{j}^{(l)} \right | \quad \quad (2.3)

当p=\infty时,它是各个坐标距离的最大值,即

                                                        L_{\infty}(x_{i},x_{j})=\max_{l}\left | x_{i}^{(l)}-x_{j}^{(l)} \right | \quad \quad (2.4)

如图所示,给出了二维空间中p取不同值时,与原点的L_{p}距离为1   (L_{p}=1)  的点图形。

例1:已知二维空间的3个点x_1=(1,1)^{T},x_2=(5,1)^{T},...,x_3=(4,4)^{T},试求在p 取不同值时,L_{p}距离下的x_{1}的最近邻点。

解答过程如下:

2.3 k值的选择

k值的选择会对k近邻法的结果产生重大影响

如果选择较小的k值,就相当于用较小的领域的训练实例进行选择,“学习”的近似误差会减小,只有与输入实例较近的(相似的)训练实例才会对预测结果起作用。但缺点是“学习”的估计误差会增大,预测结果会对近邻的实例点非常敏感。如果邻近的实例点恰巧是噪声,预测就会出错。换句话说,k值的减小就意味着整体模型变得复杂,容易发生过拟合。

如果选择较大的K值,就相当于用较大领域中的训练实例进行预测。其优点是可以减少学习的估计误差,但缺点是近似误差会增大。这时与输入实例较远的训练实例也会对预测作用,使预测发生错误。k值的增大意味着整体模型变得简单。

在应用中,k值一般取一个比较小的数值,通常采用交叉验证法来选取最优的k值。

2.4 分类决策规则

k近邻法中的分类决策规则往往是多数表决,即由输入实例的k个邻近的训练实例中的多数类决定输入实例的类。

多数表决规则有如下解释:如果分类的损失函数为0-1损失函数,分类函数为

                                                      f:R^{n}\rightarrow \left \{ c_1,c_2,...c_k \right \}

那么误分类的概率是:

                                                     p(Y\neq f(x))=1-p(Y=f(x))

对给定的实例x\in X,其最近邻的k个训练实例点构成集合N_k(x)。如果涵盖N_k(x)的区域的类别是c_{j},那么误分类率是

                                                     \frac{1}{k}\sum _{x_{i}\in N_{k}(x)}I(y_{i}\neq c_{j})=1-\frac{1}{k}\sum _{x_{i}\in N_{k}(x)}I(y_{i}= c_{j})

要使误分类率最小即经验风险最小,就要使\sum_{x_{i}\in N_{k}(x)}I(y_{i}=c_{j}) 最大,所以采取多数表决规则等价于经验风险最小化。

 

3. k近邻的实现:kd树

实现k近邻法时,主要考虑的是如何对训练数据进行快速k-近邻搜索。k近邻算法最简单的实现方法是线性扫描。这时要计算输入实例与每个训练实例的距离。当训练集很大时,计算非常耗时,这种方法是不可行的。

为了提高k近邻搜索的效率,可以考虑使用特殊的结构存储训练数据,以减少计算距离的次数。

3.1构造kd树

kd树是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。kd树是二叉树,表示对k维空间的一个划分。构造kd树相当于不断地用垂直于坐标轴的超平面将k维空间切分,构成一系列的k维超矩形区域。kd树的每个结点对应一个k维超平面区域。

构造kd树的方法如下:构造根结点,使得根结点对应于k维空间中包含所有实例点的超矩形曲区域;通过下面的递归方法,不断地对k维空间进行切分,生成子结点。在超矩形区域(结点)上选择一个坐标轴和在此坐标上的一个切分点,确定一个超平面,这个超平面通过选定的切分点并垂直于选定的坐标轴,将当前超矩形区域切分为左右两个子区域(子结点);这时,实例被分为两个子区域。这个过程直到子区域内没有实例时终止。在此过程中,将实例保存在相应的结点上。

通常,依次选择坐标轴对空间切分,选择训练实例点在选定坐标轴上的中位数为切分点,这样得到的kd树是平衡的。注意,平衡的kd树搜索时的效率未必是最优的。

构建kd树的算法:

输入:k维空间数据集T=\left \{ x_1,x_2,...,x_N \right \},

其中x_i=(x_i^{(1)},x_i^{(2)},...,x_i^{(k)})^{T},i=1,2,...N;

输出:kd树

(1)开始:构造根结点,根结点对应于包含于T的k维空间的超矩形区域。

选择x^{(1)}为坐标轴,以T中所有实例的x^{(1)}坐标的中位数为切分点,将根结点对应的超矩形区域切分为两个子区域,切分由通过切分点并与坐标轴x^{(1)}垂直的超平面实现。由根结点的生成深度为1的左、右子结点,左子结点对应坐标x^{(1)}小于切分点的子区域,右子结点对应于坐标x^{(1)}大于切分点的子区域。

将落在切分超平面上的实例点保存在跟结点。

(2)重复:对深度为j的结点,选择x^{(l)}为切分的坐标轴,l=j(mod \quad k)+1,以该结点的区域中所有实例的x^{(l)}坐标的中位数为切分点,将该结点对应的超平面矩形区域切分为两个子区域,切分由通过切分点并与坐标轴x^{(l)}垂直的超平面实现。

由该结点生成深度为j+1的左、右子结点:左子结点对应坐标x^{(l)}小于切分点的子区域,右子结点对应坐标x^{(l)}大于切分点的子区域。

将落在切分超平面上的实例点保存在该结点。

(3)直到两个子区域没有实例存在时停止,从而形成kd树的区域划分。

例2. 给定一个二维空间的数据集:

                      T=\left \{ (2,3)^{T},(5,4)^{T},(9,6) ^{T},(4,7)^{T},(8,1)^{T},(7,2)^{T}\right \}

构造一个平衡kd树。

  

3.2 搜索kd树

可以看到,利用kd可以省去对大部分数据点的搜索,从而减少搜索的计算量,这里以最近邻为例加以叙述。同样的方法可以应用到k近邻中。

给定一个目标点,搜索其最近邻。首先找到包含目标点的叶结点;然后从该叶结点出发,依次回退到父结点;不断查找与目标点最邻近的结点,当确定不可能存在更接近的结点时停止。这样搜索就限制在空间的局部区域上,效率大大提高。

包含目标点的叶结点对应包含目标点的最小超矩形区域。以此叶结点的实例点作为当前的最近点。目标点的最近邻一定在以目标点为中点并通过当前最近点的超球体的内部。然后返回当前结点的父结点,如果父结点的另一子结点的超矩形区域与超球体相交,那么在相交的区域内寻找与目标点更近的实例点。如果存在这样的点,将此点作为新的当前最近点。算法转到更上一级的父结点,继续上述过程。如果父结点的另一子结点的超矩形区域与超球体不相交,或不存在比当前最近点更近的点,则停止搜索。

最近邻搜索算法

输入:已构造的kd树;目标点x;

输出:x 的最近邻。

(1)在kd树中找到包含目标点的x的叶结点:从根结点出发,递归地向下访问kd树。若目标点 x 当前维的坐标小于切分点的坐标,则移动到左子结点,否则移动到右子结点。直到子结点为叶结点为止。

(2)以此叶结点为“当前最近点”;

(3)递归地向上回退,在每个结点进行以下操作:

(a)如果该结点保存的实例点比当前最近点距离目标点更近,则以该实例点为“当前最近点”;

(b)当前最近点一定存在于该结点一个子结点对应的区域。检查该子结点的父结点的另一个子结点对应的区域是否有更近的点。具体地,检查另一个子结点对应的区域是否与以目标点为球心、以目标点与“当前最近点”间的距离为半径的超球体相交。

如果相交,可能在另一个子结点对应的区域内存在距目标点更近的点,移动到另一个子结点。接着,递归地进行最近邻搜索;

如果不相交,向上回退。

(4)当回退到根结点时,搜索结束,最后的“当前最近点”即为x的最近邻点。

注:如果实例点的随机分布的,kd树搜索的平均计算复杂度是O(logN),这里N是训练实例数。kd数更适用于训练实例数远大于空间维数时的k近邻搜索。当空间维数接近训练实例数时,它的效率会迅速下降,几乎接近线性扫描。

例3 给定一个如图所示的kd树,根结点为A,其子结点为B,C等。树上共存储7个实例点;另有一个输入目标实例点S,求S的最近邻。

解:

①在kd树中找到包含点S的叶结点D,以D作为暂时的近似最近邻,真正最近邻一定要在以点S为中心通过D的圆内部。

②然后返回D的父结点B,在点B的另一子结点F的区域内搜索最近邻。结点F的区域与圆不相交,故而不可能有最近邻点。

③继续返回上一级父结点A,在结点A的另一个子结点C区域内搜索最近邻。结点C区域与圆相交;该区域在圆内有实例点E,且点E离S的距离比点D更近,成为新的最近邻近似;

④最后得到点E是点S的最近邻点。

 

 

4. 特点介绍

优点:精度高、对异常值不敏感、无数据输入假定;

缺点:计算复杂度高、空间复杂度高;

适用数据范围:数值型和标称型。

(1)数值型:数值型目标变量可以从无限的数值集合中取,比如2,4,10,20,40……,主要用在回归分析中;

(2)标称型:标称型目标变量的结果只从有限数值集合中获取,比如0,1,主要用在分类中。

5. 算法的一般流程:

(1)收集数据:可以使用任何方法;

(2)准备数据:距离计算所需要的数值,最好是结构化的数据格式;

(3)分析数据:可以使用任何方法;

(4)训练算法:此步骤不适用于K-近邻算法;

(5)测试算法:计算错误率;

(6)使用算法:首先需要输入样本数据和结构化的输入结果,然后运行K-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。

案例一:约会网站分类系统

第一步:实践KNN分类算法代码如下

def classify0(intX,dataSet,labels,k):
    dataSetSize=dataSet.shape[0] #表示数据集的大小
    '''距离计算'''
    diffMat=tile(intX,(dataSetSize,1))-dataSet #当前点和训练集中的对应元素相减
    sqDiffMat=diffMat**2 #当前点和训练集中的对应元素相减的值上面添加平方
    sqDistance=sqDiffMat.sum(axis=1) #将相减的值的平方累加
    distances=sqDistance**0.5 #求出当前点与数据集中每个点的距离
    sortedDistIndices=distances.argsort() #将distances的值从小到大排列,提取其对应的索引
    classCount={}
    for i in range(k):
        voteIlabel=labels[sortedDistIndices[i]] #确定前k个距离最小的元素所在的类别
        classCount[voteIlabel]=classCount.get(voteIlabel,0)+1 #通过字典的形式,统计前k个距离最小的元素所在的类别出现的频率
    '''classCount.items()将字典classCount分解为元组列表
       operator.itemgetter(1)按照第二个元素的次序对元组进行排序
       reverse=True表示降序,即从大到小排列'''
    sortedclasscount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    return sortedclasscount[0][0]

第二步:从文本文件中解析数据

def file2matrix(filename):
    fr=open(filename)
    #readlines()用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由Python 的 for... in ... 结构进行处理
    arrayOLines=fr.readlines()
    numberOfLines=len(arrayOLines) #文件行数
    returnMat=zeros((numberOfLines,3)) #创建返回的numpy矩阵
    classLabel=[]
    index=0
    for line in arrayOLines:
        line=line.strip() #清楚所有的回车字符
        listFromLine=line.split('\t') #使用'\t'将每行分割成元素列表
        returnMat[index,:]=listFromLine[0:3] #选取前三个文件存储到特征矩阵中
        classLabel.append(int(listFromLine[-1])) #将标签存储到列表classLabel
        index+=1
    return returnMat,classLabel

第三步:使用matlotlib创建散点图

import matplotlib.pyplot as plt

print(array(datingDataLabels))
plt.style.use('ggplot')
fig=plt.figure()
ax=fig.add_subplot(111)
#ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*array(datingDataLabels),15.0*array(datingDataLabels))
ax.scatter(datingDataMat[:,0],datingDataMat[:,1],15.0*array(datingDataLabels),0.2*array(datingDataLabels))
#plt.xlabel('玩视频游戏所耗时间百分比')
#plt.ylabel('每周所消费的冰淇淋公升数')
plt.xlabel('每年获取的飞行常客里程数')
plt.ylabel('玩视频游戏所耗时间百分比')
plt.legend(loc='best')
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
plt.show()

第四步,对数据进行归一化

'''考虑到每年获取的飞行常客里程数远大于其他特征数,在这里使用数值归一化进行处理'''
def autoNorm(dataSet):
    minvalue=dataSet.min(0) #获取列中的最小值
    maxvalue=dataSet.max(0) #获取列中的最大值
    ranges=maxvalue-minvalue #最大值与最小值的差
    m=dataSet.shape[0] #表示行数
    HandleDataSet=dataSet-tile(minvalue,(m,1)) #表示归一化的分母
    normDataSet=HandleDataSet/tile(ranges,(m,1)) #归一化的结果
    return normDataSet,ranges,minvalue

第五步:分类器针对约会网站进行测试

def datingClassTest():
    hoRatio=0.10
    datingDataMat,datingLabels=file2matrix(r'F:\python\machinelearninginaction\Ch02\datingTestSet2.txt')
    normMat,ranges,minvalues=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)   #classify0()中的第一个元素表示测试数据,第二个元素表示分类器的训练数据
        print('the classifier came back with:{0}, the real answer is:{1}'.format(classifierResult,datingLabels[i]))
        if (classifierResult!=datingLabels[i]):
            errorCount+=1.0
    print('the total error rate is:{0}'.format(errorCount/float(numTestVecs)))

第六步:对人进行分类

def classifyperson():
    result_list=['not at all','in small doses','in large doses']
    percentTats=float(input("percentage of time spent playing video games?"))
    ffMiles=float(input("frequent flier miles earned per year?"))
    iceCream=float(input("liters of ice cream consumed per year?"))
    datingDataMat,datingLabels=file2matrix(r'F:\python\machinelearninginaction\Ch02\datingTestSet2.txt')
    normMat,ranges,minvalues=autoNorm(datingDataMat)
    inArr=array([ffMiles,percentTats,iceCream])
    classifierResult=classify0((inArr-minvalues)/ranges,normMat,datingLabels,3)
    print("You will probably like this personL: {}".format(result_list[classifierResult-1]))

构建完整的可用系统:

#!/usr/bin/env python3
#coding=utf-8
import pandas as pd
from numpy import *
import operator
import matplotlib.pyplot as plt
import os

'''(1)计算已知类别数据集中的点与当前点之间的距离
   (2)按照距离递增次序排列
   (3)选取与当前点距离最小的K个点
   (4)确定前K个点所在类别的出现频率
   (5)返回前K个点出现频率最高的类别作为当前点的预测分类'''
#使用k-近邻构建分类器
def classify0(intX,dataSet,labels,k):
    dataSetSize=dataSet.shape[0] #表示数据集的大小
    '''距离计算'''
    diffMat=tile(intX,(dataSetSize,1))-dataSet #当前点和训练集中的对应元素相减
    sqDiffMat=diffMat**2 #当前点和训练集中的对应元素相减的值上面添加平方
    sqDistance=sqDiffMat.sum(axis=1) #将相减的值的平方累加
    distances=sqDistance**0.5 #求出当前点与数据集中每个点的距离
    sortedDistIndices=distances.argsort() #将distances的值从小到大排列,提取其对应的索引
    classCount={}
    for i in range(k):
        voteIlabel=labels[sortedDistIndices[i]] #确定前k个距离最小的元素所在的类别
        classCount[voteIlabel]=classCount.get(voteIlabel,0)+1 #通过字典的形式,统计前k个距离最小的元素所在的类别出现的频率
    '''classCount.items()将字典classCount分解为元组列表
       operator.itemgetter(1)按照第二个元素的次序对元组进行排序
       reverse=True表示降序,即从大到小排列'''
    sortedclasscount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    return sortedclasscount[0][0]

'''将文本记录转换为Numpy的解析程序'''
def file2matrix(filename):
    fr=open(filename)
    #readlines()用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由Python 的 for... in ... 结构进行处理
    arrayOLines=fr.readlines()
    numberOfLines=len(arrayOLines) #文件行数
    returnMat=zeros((numberOfLines,3)) #创建返回的numpy矩阵
    classLabel=[]
    index=0
    for line in arrayOLines:
        line=line.strip() #清楚所有的回车字符
        listFromLine=line.split('\t') #使用'\t'将每行分割成元素列表
        returnMat[index,:]=listFromLine[0:3] #选取前三个文件存储到特征矩阵中
        classLabel.append(int(listFromLine[-1])) #将标签存储到列表classLabel
        index+=1
    return returnMat,classLabel

#datingDataMat,datingDataLabels=file2matrix(r'F:\python\machinelearninginaction\Ch02\datingTestSet2.txt')
"""
print(array(datingDataLabels))
plt.style.use('ggplot')
fig=plt.figure()
ax=fig.add_subplot(111)
#ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*array(datingDataLabels),15.0*array(datingDataLabels))
ax.scatter(datingDataMat[:,0],datingDataMat[:,1],15.0*array(datingDataLabels),0.2*array(datingDataLabels))
#plt.xlabel('玩视频游戏所耗时间百分比')
#plt.ylabel('每周所消费的冰淇淋公升数')
plt.xlabel('每年获取的飞行常客里程数')
plt.ylabel('玩视频游戏所耗时间百分比')
plt.legend(loc='best')
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
plt.show()
"""

'''考虑到每年获取的飞行常客里程数远大于其他特征数,在这里使用数值归一化进行处理'''
def autoNorm(dataSet):
    minvalue=dataSet.min(0) #获取列中的最小值
    maxvalue=dataSet.max(0) #获取列中的最大值
    ranges=maxvalue-minvalue #最大值与最小值的差
    m=dataSet.shape[0] #表示行数
    HandleDataSet=dataSet-tile(minvalue,(m,1)) #表示归一化的分母
    normDataSet=HandleDataSet/tile(ranges,(m,1)) #归一化的结果
    return normDataSet,ranges,minvalue

'''用分类器针对约会网站进行测试'''
def datingClassTest():
    hoRatio=0.10
    datingDataMat,datingLabels=file2matrix(r'F:\python\machinelearninginaction\Ch02\datingTestSet2.txt')
    normMat,ranges,minvalues=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)   #classify0()中的第一个元素表示测试数据,第二个元素表示分类器的训练数据
        print('the classifier came back with:{0}, the real answer is:{1}'.format(classifierResult,datingLabels[i]))
        if (classifierResult!=datingLabels[i]):
            errorCount+=1.0
    print('the total error rate is:{0}'.format(errorCount/float(numTestVecs)))

'''对人进行分类'''
def classifyperson():
    result_list=['not at all','in small doses','in large doses']
    percentTats=float(input("percentage of time spent playing video games?"))
    ffMiles=float(input("frequent flier miles earned per year?"))
    iceCream=float(input("liters of ice cream consumed per year?"))
    datingDataMat,datingLabels=file2matrix(r'F:\python\machinelearninginaction\Ch02\datingTestSet2.txt')
    normMat,ranges,minvalues=autoNorm(datingDataMat)
    inArr=array([ffMiles,percentTats,iceCream])
    classifierResult=classify0((inArr-minvalues)/ranges,normMat,datingLabels,3)
    print("You will probably like this personL: {}".format(result_list[classifierResult-1]))

案例二:手写识别系统

第一步:将图像转化成测试向量

def img2vetor(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-近邻算法识别手写数字

def handwritingClassTest():
    hwLabels=[]
    trainingFileList=os.listdir(r'F:\python\machinelearninginaction\Ch02\trainingDigits') #返回指定的文件夹包含的文件或文件夹的名字的列表
    m=len(trainingFileList)
    trainingMat=zeros((m,1024))
    for i in range(m):
        fileNameStr1=trainingFileList[i]
        fileStr1=fileNameStr1.split('.')[0]
        classNumStr1=int(fileStr1.split('_')[0])
        hwLabels.append(classNumStr1)
        trainingMat[i,:]=img2vetor(r'F:\python\machinelearninginaction\Ch02\trainingDigits\%s'%fileNameStr1)
    testFileList=os.listdir(r'F:\python\machinelearninginaction\Ch02\testDigits')
    errorCount=0.0
    mtest=len(testFileList)
    for i in range(mtest):
        fileNameStr2=testFileList[i]
        fileStr2=fileNameStr2.split('.')[0]
        classNumStr2=int(fileStr2.split('_')[0])
        vectorUnderTest=img2vetor(r'F:\python\machinelearninginaction\Ch02\testDigits\%s'%fileNameStr2)
        classifierResult=classify0(vectorUnderTest,trainingMat,hwLabels,3)
        print("the classifierResult came back with: {0}, the real answer is: {1}".format(classifierResult,classNumStr2))
        if (classifierResult!=classNumStr2):
            errorCount+=1.0
    print("\nthe total number of errors is:{}".format(int(errorCount)))
    print("\nthe total rate is:{}".format(errorCount/float(mtest)))

完整代码:

  1. #!/usr/bin/env python3
  2. #coding=utf-8
  3. import pandas as pd
  4. from numpy import *
  5. import operator
  6. import matplotlib.pyplot as plt
  7. import os
  8. '''(1)计算已知类别数据集中的点与当前点之间的距离
  9.    (2)按照距离递增次序排列
  10.    (3)选取与当前点距离最小的K个点
  11.    (4)确定前K个点所在类别的出现频率
  12.    (5)返回前K个点出现频率最高的类别作为当前点的预测分类'''
  13. #使用k-近邻构建分类器
  14. def classify0(intX,dataSet,labels,k):
  15.     dataSetSize=dataSet.shape[0] #表示数据集的大小
  16.     '''距离计算'''
  17.     diffMat=tile(intX,(dataSetSize,1))-dataSet #当前点和训练集中的对应元素相减
  18.     sqDiffMat=diffMat**2 #当前点和训练集中的对应元素相减的值上面添加平方
  19.     sqDistance=sqDiffMat.sum(axis=1) #将相减的值的平方累加
  20.     distances=sqDistance**0.5 #求出当前点与数据集中每个点的距离
  21.     sortedDistIndices=distances.argsort() #将distances的值从小到大排列,提取其对应的索引
  22.     classCount={}
  23.     for i in range(k):
  24.         voteIlabel=labels[sortedDistIndices[i]] #确定前k个距离最小的元素所在的类别
  25.         classCount[voteIlabel]=classCount.get(voteIlabel,0)+1 #通过字典的形式,统计前k个距离最小的元素所在的类别出现的频率
  26.     '''classCount.items()将字典classCount分解为元组列表
  27.        operator.itemgetter(1)按照第二个元素的次序对元组进行排序
  28.        reverse=True表示降序,即从大到小排列'''
  29.     sortedclasscount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
  30.     return sortedclasscount[0][0]
  31. '''将图像转换为测试向量'''
  32. def img2vetor(filename):
  33.     returnVect=zeros((1,1024))
  34.     fr=open(filename)
  35.     for i in range(32):
  36.         lineStr=fr.readline()  #每次读取文件的一行
  37.         for j in range(32):
  38.             returnVect[0,32*i+j]=int(lineStr[j])
  39.     return returnVect
  40. def handwritingClassTest():
  41.     hwLabels=[]
  42.     trainingFileList=os.listdir(r'F:\python\machinelearninginaction\Ch02\trainingDigits') #返回指定的文件夹包含的文件或文件夹的名字的列表
  43.     m=len(trainingFileList)
  44.     trainingMat=zeros((m,1024))
  45.     for i in range(m):
  46.         fileNameStr1=trainingFileList[i]
  47.         fileStr1=fileNameStr1.split('.')[0]
  48.         classNumStr1=int(fileStr1.split('_')[0])
  49.         hwLabels.append(classNumStr1)
  50.         trainingMat[i,:]=img2vetor(r'F:\python\machinelearninginaction\Ch02\trainingDigits\%s'%fileNameStr1)
  51.     testFileList=os.listdir(r'F:\python\machinelearninginaction\Ch02\testDigits')
  52.     errorCount=0.0
  53.     mtest=len(testFileList)
  54.     for i in range(mtest):
  55.         fileNameStr2=testFileList[i]
  56.         fileStr2=fileNameStr2.split('.')[0]
  57.         classNumStr2=int(fileStr2.split('_')[0])
  58.         vectorUnderTest=img2vetor(r'F:\python\machinelearninginaction\Ch02\testDigits\%s'%fileNameStr2)
  59.         classifierResult=classify0(vectorUnderTest,trainingMat,hwLabels,3)
  60.         print("the classifierResult came back with: {0}, the real answer is: {1}".format(classifierResult,classNumStr2))
  61.         if (classifierResult!=classNumStr2):
  62.             errorCount+=1.0
  63.     print("\nthe total number of errors is:{}".format(int(errorCount)))
  64.     print("\nthe total rate is:{}".format(errorCount/float(mtest)))
  65. handwritingClassTest()
【机器学习】K-近邻算法(KNN)全面解析 K-近邻算法(K-Nearest Neighbors, KNN)是一种基于实例的学习方法,属于监督学习范畴。它的工作原理简单直观:给定一个训练数据集,对新的输入实例,KNN算法通过计算其与训练集中每个实例的距离,找出距离最近的K个邻居,然后根据这些邻居的类别(对于分类任务)或值(对于回归任务)来预测新实例的类别或值。KNN因其简单高效和无需训练过程的特点,在众多领域中得到广泛应用,如模式识别、推荐系统、图像分类等。KNN算法的核心思想是“物以类聚”,即相似的数据应有相似的输出。 阅读详情

相关推荐

K近邻算法(KNN)的概述与实现

KNN是一种简单但功能强大的算法,适用于分类和回归任务。然而,其计算成本和对K值的敏感性使其在处理大规模数据集或高维数据时存在一定的局限性。随着数据规模的增加,优化KNN的计算速度和性能成为一个值得探索的方向。你是否有使用KNN算法进行项目的经验?在实践中你会选择什么样的距离度量方法?欢迎分享你的看法和经验!

m0_62710548的博客 2246

K-近邻算法(KNN)

​ K近邻(K-Nearest Neighbor, KNN)是一种最经典和最简单的*有监督学习*方法之一

Running Snail 6万+

11、K近邻算法(KNN)

本文首先介绍了KNN算法的直观理解、算法三大要素、优缺点,并说明了如何实现KNN算法,最后讲解了sklearn中的KNN使用。

m0_56642803的博客 1212

K-近邻算法

学习笔记

PCGuo999的博客 2万+

K近邻算法(knn)及R实现

K近邻算法,即K-Nearest Neighbor algorithm,简称KNN算法,单从名字来猜想,可以简单粗暴的认为是:K个最近的邻居,当K=1时,算法便成了最近邻算法,即寻找最近的那个邻居。为何要找邻居?打个比方来说,假设你来到一个陌生的村庄,现在你要找到与你有着相似特征的人群融入他们,所谓入伙。     用官方的话来说,所谓K近邻算法,即是给定一个训练数据集,对新的输入实例,在训练

古韦的专栏 5900

K-邻近算法(kNN)python3.X

k-邻近算法(kNN)学习笔记 机器学习主要任务 在机器学习(Machine Learning)的主要任务就是实现数据的分类,通过给算法输入大量已分类的数据作为算法训练集,使机器能够找到特征与目标变量之间的关系,对未知特征的数据做出正确的判断,这就是分类。机器学习的另外一个重要的任务就是回归,用来预测数值型数据。 kNN(K-邻近算法)概念 k-邻近算法是给算法一个训练样本集,每个样本集都给出了

NanoScale_livelife的博客 903

算法——k-近邻算法

对k-近邻算法的详细学习,包括k-近邻算法流程,k值选取,kd树,k-近邻算法的python代码,k-近邻算法的优缺点总结。

m0_66890670的博客 4713

K-近邻算法(KNN)

欧几里得距离二维:​。

if_Echo_else的博客 1765

K-邻近算法(KNN)

1. KNN 算法原理 k-近邻算法(k-Nearest Neighbour algorithm)的工作原理:给定一个已知标签类别的训练数据集,输入没有标签的新数据后,在训练数据集中找到与新数据最邻近的 k 个实例,如果这 k 个实例的多数属于某个类别,那么新数据就属于这个类别。即由那些离新数据最近的 k 个实例来投票决定新数据归为哪一类。 最邻近分类算法是数据挖掘分类(classificat...

wangprince2017 1万+

机器学习笔记九:K近邻算法(KNN)

KNN原理和实战

谢小小XH 7248

K 邻近算法(k-Nearest Neighbor,KNN)

文章目录一、前置假设二、K近邻法基本思想三、K近邻法的三个要素1. K 值的选择2. 距离的度量3. 分类决策的规则四、特征归一化五、对异常值敏感六、参考 一、前置假设 输入空间:χ⊆Rn\chi \subseteq R^nχ⊆Rn 训练集:T=[(x1,y1),(x2,y2),⋯ ,(xN,yN)]T=[(x_1, y_1), (x_2, y_2), \cdots,...

642

K近邻算法(k-nearest neighbor,KNN)

K近邻算法(k-nearest neighbor,KNN) 经过一周昏天黑地的加班之后,终于到了周末,又感觉到生活如此美好,遂提笔写一写KNN,这个也许是机器学习众多算法中思想最为简单直白的算法了,其分类思想,总结起来就一句话:近朱者赤,近墨者黑。当然,KNN也可以用于回归任务,在回归任务中,采用“平均法”,即把离预测样本最近的K个样本的label(连续值)取平均作为预测结果,也可以根据距离远近进...

天泽28的专栏 6257

K近邻算法(k-nearest neighbor, kNN)

K近邻算法(K-nearest neighbor, KNN) KNN是一种分类和回归方法。 KNN简介 KNN模型3要素 KNN优缺点 KNN应用 参考文献 KNN简介 KNN思想 给定一个训练集T={(x1,y1),(x2,y2),...,(xN,yN)}T={(x1,y1),(x2,y2),...,(xN,yN)}T=\left\{ (x_1,y_1), (x_2,y_...

今春一别难相逢 1242

k近邻算法K-Nearest Neighbors(KNN)

KNN算法的核心思想以及相关优化

2401_88885149的博客 1884

K-hop算法:GeaFlow图计算快速上手

在每一步中,我们从队列中取出当前节点,如果当前跳数等于K,则将该节点添加到K跳邻居列表中。然后,我们遍历当前节点的所有邻居节点,并将它们添加到队列中,同时更新跳数。这样,我们就可以逐层向外扩展,直到达到K跳为止。K-hop算法是一种基于图的遍历算法,用于查找给定节点的K跳邻居。K-hop算法可以在大规模的图中高效地寻找K跳邻居,提供了快速的图遍历能力。K-hop算法是一种用于图计算的快速算法,可以在图中寻找指定节点的K跳邻居。该函数接受一个图、一个起始节点和一个K值作为参数,并返回找到的K跳邻居节点列表。

PixelNinja的博客 448

C#调用Bartender打印标签,除了打印还能一键导出图片和PDF(附完整代码)

本文详细介绍了如何使用C#集成Bartender实现标签的多格式输出,包括打印、图片和PDF导出。通过完整的代码示例和实战技巧,帮助开发者解决分辨率适配、纸张尺寸控制等核心问题,提升工业自动化和物流管理中的标签处理效率。

weixin_31236101的博客 370

k-邻近算法kNN及其python实现

k-邻近算法kNN    邻近法kNN是1967年提出的一种基本分类与回归方法。kNN中输入测试数据和训练样本,然后计算测试数据到每个训练样本之间的距离,接着选出距离最小的k个样本,根据k个样本的类别投票决定。K个样本中占多数的类别即为测试数据的类别。 一.k-邻近算法的优缺点: 1.优点:简单好用,容易理解,精度高,理论成熟,既可以用来做分类也可以用来做回归、适合于多分类问题、可用

zonghengyuzhou的博客 970

基于OkHttp3+Retrofit2+RxJava3搭建响应式网络框架

本文介绍了一个基于OkHttp3+Retrofit3+RxJava3的响应式网络框架设计。该框架采用分层架构,OkHttp3负责底层网络请求,Retrofit3封装HTTP接口,RxJava3实现响应式流处理。核心亮点包括:1)高度解耦的分层设计;2)统一的异常处理和响应体封装;3)RxJava3实现线程切换和请求管理;4)MVVM架构适配,业务层只需关注数据逻辑。框架提供了完整的实现方案,包括全局配置、拦截器、响应转换、接口声明、仓库封装等组件,并支持生产环境扩展功能如Cookie持久化、Token刷新等

fuge2008的博客 873

K-近邻算法(KNN)

K-近邻算法(KNN)一、k近邻算法的基本概念原理和应用二、k近邻算法中k的选取以及特征归一化的重要性1.选取k值以及它的影响2.距离的度量3.特征归一化的必要性总结 一、k近邻算法的基本概念原理和应用 首先,K近邻算法是一种基本分类和回归方法。本篇文章只讨论分类问题的k近邻法。 K近邻算法,即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例,这K个实例的多数属于某个类,就把该输入实例分类到这个类中。(这就类似于现实生活中少数服从多数的思想)根据这个说法,咱们来看下引自维基

LkmLym的博客 1818

手把手教你学Simulink——基于Simulink的全双工无线通信仿真建模示例

目录手把手教你学Simulink——基于Simulink的全双工无线通信仿真建模示例一、背景介绍二、所需工具和环境三、步骤详解步骤1:创建Simulink模型步骤2:设计输入信号步骤3:添加调制模块步骤4:添加自干扰消除模块步骤5:添加AWGN信道步骤6:添加接收端处理步骤7:添加解调模块步骤8:计算误码率(BER)步骤9:添加显示模块步骤10:设置仿真参数步骤11:运行仿真并分析结果四、总结 全双工(Full-Duplex)无线通信技术允许在同一频段上同时进行数据的发送和接收,这与传统的半双工(Half-

MHD0815的博客 183

【Dify】PPT生成工具应用

本文介绍了一款自动化PPT生成工具,通过智能接口将文本内容高效转化为结构化演示文档。该系统采用三阶段工作流(内容输入、HTTP请求上传、文件输出),无需复杂操作即可生成专业PPT。工具适用于教学课件、产品发布、企业培训等场景,能显著提升内容表达效率,特别适合初学者快速制作演示材料。文章详细说明了核心节点、应用场景及开发资源,为文本到PPT的自动化转换提供了实用解决方案。

Mr数据杨 1221

K邻近算法(KNN,K-nearest Neighbors Algorithm)

之前看到一篇文章,方法部分提到了这个K邻近算法,正好自己不是很熟悉其原理,所以学习整理一下😑K邻近算法(K-nearest neighbors algorithm)是一种常用的机器学习算法,用于分类和回归问题。它基于一个简单的假设:与未知样本最相似的K个已标记样本的类别可以用来预测该未知样本的类别。在K邻近算法中,输入数据点被表示为n维空间中的向量,并且每个数据点都有一个对应的类别标签。计算距离:根据给定的距离度量方法(例如欧氏距离、曼哈顿距离等),计算未知样本与训练集中所有已标记样本之间的距离。

生信学习 1474

损失函数大汇总(五十三)(Boundary Loss附公式推导与代码)

摘要 Boundary Loss是一种针对图像分割任务的新型损失函数,特别适用于高度类别不平衡的细粒度分割场景。与传统的区域型损失(如Dice、交叉熵)不同,它通过计算预测边界与真实边界之间的距离来优化模型,更关注边界精度而非区域重叠。核心思想是利用距离图(distance map)将边界约束转化为区域积分形式,实现端到端训练。具体实现中,损失函数为预测概率与距离图的点积,梯度仅取决于距离图,具有明确的空间引导性。相比区域型损失,Boundary Loss能更好处理小目标、细长结构等边界敏感任务,可与Dic

悦学共鸣,温柔以待,汇聚光芒,共同成长 241
上一篇: 关于python连接mysql相关知识(2)
下一篇: 决策树
DM_learner
博客等级 码龄9年 21粉丝 23原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值