K-临近算法

本篇文章主要内容:

  • k-临近分类算法概述
  • 从文本文件中解析和导入数据 
  • 使用Matplotlib创建扩散图
  • 归一化数据

一、k-临近算法概述

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

工作原理:

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

我们使用欧式距离公式,来计算两个向量点A(x1,y1)与B(x2,y2)之间的距离:


优缺点:

             优点:精度高、对异常值不敏感

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

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

k-临近算法核心内容伪代码如下:

对未知类别属性的数据集中的每个点依次执行以下操作:

           1.计算已知类别数据集中的点与当前点之间的距离

           2.按照距离递增次序排序

           3.选取与当前点距离最小的k个点

           4.确定前k个点所在类别的出现频率

           5.返回前k个点出现频率最高的类别作为当前点的预测分类

二、归一化数据

        在分析数据的过程中,我们很容易发现,因为不同特征的量纲(单位)的不同,不同特征的数据有很大差值,这样对计算结果的影响很大,显然,在运用欧氏距离公式时差值最大的属性对计算结果影响最大。在处理这种不同不同取值范围的特征值时,我们通常采用的方法是将数值归一化,下面的公式可以将任意取值范围的特征值映射到0到1区间内:

                                                       


示例:在约会网站上使用k-临近算法


步骤:

  • 收集数据:提供文本文件
  • 准备数据:使用python解析文本文件
  • 分析数据:使用matplotlib画二维扩散图
  • 设计算法:运用欧式距离公式设计k-临近算法
  • 测试算法:如果预测结果与实际不同,则标记为一个错误
  • 使用算法:产生简单的命令行程序,可以输入一些特征数据以判断对方是否是自己喜欢的类型

具体代码运行如下:

导入numpy库

import numpy as np

读取数据

def filematrix(filename):      #将待处理数据改变为可以接受的格式
    fr=open(filename)           #打开文件
    numberOfLines=len(fr.readlines())     #得到文件的行数   readlines()函数,逐行读取整个文件
    returnMat=np.zeros((numberOfLines,3))     #返回的Numpy零矩阵,numberOfLines行,3列
    #return=np.array(returnMat)
    fr=open(filename)
    classLabelVector=[]    #创建返回的numpy矩阵
    index=0     #计数
    for line in fr.readlines():  #依次读取文件的第一行
        line=line.strip()   #s.strip(rm),当rm空时,默认删除空白符(包括‘\n’,'\r','\t','')
        listFromLine=line.split('\t')  #使用s.split(str=“”,num=string,cout(str))将字符串根据‘\t’分隔符进行切片
        returnMat[index,:]=listFromLine[0:3]  #将数据前三列提取出来,存放到returnMat的Numpy矩阵中,也就是特征矩阵
        classLabelVector.append(int(listFromLine[-1]))#根据文本中标记的喜欢程度进行分类,1代表不喜欢,2代表魅力一般,3代表及具魅力
        index=index+1
    return returnMat,classLabelVector

分析数据

import matplotlib
import matplotlib.pyplot as plt
fig=plt.figure()        #建立一个画布
ax=fig.add_subplot(111)         #在画布中建立图表,fig.add_subplot()函数。画布分割成1行1列,图像
ax.scatter(datingDataMat[:,1],datingDataMat[:,2],10*np.array(datingLabels),10*np.array(datingLabels))  ##第二列和第三列数据,
plt.show()

输出分析结果图(不同的颜色代表不同的特征)


归一化数据

def autoNorm(dataSet):
    minVals=dataSet.min(0)   #每一列的最小值
    maxVals=dataSet.max(0)   #每一列的最大值
    ranges=maxVals-minVals
    normDataSet=np.zeros(np.shape(dataSet))   #shape(dataSet)返回dataSet
    m=dataSet.shape[0]   #返回dataSet的行数
    normDataSet=dataSet-np.tile(minVals,(m,1))   #原dataSet数据矩阵最小值
    normDataSet=normDataSet/np.tile(ranges,(m,1))#矩阵除法
    return normDataSet,ranges,minVals

设计k-临近算法

def classify(inX,dataSet,labels,k):
    dataSetSize=dataSet.shape[0]
    diffMat=np.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]

测试算法

import operator
def datingClassTest():                            #定义函数,进行分类测试
    hoRatio=0.10                                  #10%作为测试集
    datingDataMat,datingLabels=filematrix('datingTestSet2.txt')     #打开数据,
    normMat,ranges,minVals=autoNorm(datingDataMat)                 #调用函数进行数据归一化
    m=normMat.shape[0]                            #获得行数,即总数量
    numTestVecs=int(m*hoRatio)                   #取10%测试数据的个数,变成int类型
    errorCount=0.0                           #错误计数
    for i in range(numTestVecs):
        classifierResult=classify(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3) 
        #取出前10%行作为测试集,后面的作为训练集,标签与数据范围相同,K=3
        print("the classifier came back with:%d,the real answer is:%d"%(classifierResult,datingLabels[i]))
        #classifierResult分类测试计算出的值,datingLabels[i]真实值
        if(classifierResult!=datingLabels[i]): 
            errorCount+=1.0          #预测值与真实值不同时,错误数+1
        print("the total error rate is:%f"%(errorCount/float(numTestVecs)))
        print(errorCount)
datingClassTest() 

最终输出的错误率与错误个数:


使用算法

def classifyPerson():
    resultList=['一点也不受欢迎','比较受欢迎','极具魅力']
    ffMiles=float(input("每年飞行里程大约有多少?"))
    percentTats=float(input("玩游戏的时间百分比是多少?"))
    iceCream=float(input("每年会消耗点多少公升的冰淇淋?"))
    datingDataMat,datingLabels=filematrix('datingTestSet2.txt')
    normMat,ranges,minVals=autoNorm(datingDataMat)
    inArr=np.array([ffMiles,percentTats,iceCream])
    classifierResult=classify((inArr-minVals)/ranges,normMat,datingLabels,3)
    print("你可能是这种人:",resultList[classifierResult-1])
classifyPerson()

输出结果:





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值