机器学习之kNN分类算法

一.概述

k-近邻算法采用测量不同特征值的方法信息分类。模型三个基本要素为:距离度量、k值选择和分类决策规则
(1)距离度量:常用“欧式距离”表示两n维实数向量之间的距离。

这里写图片描述

(2)k值一般选取比较小的数值,通常采用交叉验证法来选取最优k值。
(3)k近邻模型的分类决策规则通常为多数表决规则,即由输入实例的k个临近的训练实例中的多数类决定输入实例的类。k个训练实例点组成的集合为Nk (x)。
误分类率:

这里写图片描述

误分类率最小即经验风险最小,就要使这里写图片描述最大,因此多数表决规则等价于经验风险最小化。

二.工作原理

(1)存在一个样本数据集合(训练样本集),并且其中每个数据都有标签(分类);
(2) 输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征比较,提取样本集中特征最相似数据(最近邻)的分类标签;
(3)选择样本数据集中前k个最相似的数据,通常k是不大于20的整数;
(4)最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。

三.优缺点及适用范围

(1)优点:精度高、对异常值不敏感、无数据输入假定
(2)缺点:计算复杂度高、空间复杂度高
(3)适用数据范围:整值型和标称型

四.一般流程

收集数据→准备数据→分析数据→训练算法→测试算法→使用算法

注意事项:
(1)准备数据最好为结构化数据格式;
(2)k-近邻算法不需要训练算法(无参);
(3)通过计算错误率来测试算法。

五.python代码实现

案例 利用K近邻算法改进约会网站的配对效果:

步骤如下:
对未知类别数据集中的每个点依次执行如下操作。
(1)计算已知类别数据集中点与当前点之间的距离;
(2)按照距离递增次序排序;
(3)选取与当前点距离最小的k个点;
(4)确定前k个点所在类别的出现频率;
(5)返回前k个点出现频率最高的类别作为当前点的预测分类。

第一步:编写clssify0()函数代码,使用k-近邻算法将每组数据划分到某个类中。

# 分类算法classify0,计算欧氏距离
def classify0(inX,dataSet,lables,k):
    #shape 返回行行列数,shape[0]是行数,表示有多少元组,shape[1]返回列
    dataSetSize=dataSet.shape[0]
    #tile复制inX,使其与dataset一样大小,二者之差形成一个差值矩阵
    diffMat=tile(inX,(dataSetSize,1))-dataSet
    sqDiffMat=diffMat**2
    sqDistances=sqDiffMat.sum(axis=1) #对差值矩阵按行进行求和
    distances=sqDistances**0.5
    #argsort()进行排序,返回从小到大索引值
    sortedDistances=distances.argsort()
    classCount={}#新建用于计数的空字典
    for i in range(k):
        votelable=lables[sortedDistances[i]] #获取前k个样本对应的类别标签
        #统计对应类别标签出现的次数,生成一个元组存储数据
        classCount[votelable]=classCount.get(votelable,0)+1
 #按照第二个元素进行降序排列,迭代器进行降序排序(类似冒泡) sortedClassCount=sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse=True)
   #返回出现次数最多的哪一个label的值
    return sortedClassCount[0][0]

第二步:编写file2matrix(filename)方法,读取txt文件中数据

#获取文件数据
def file2matrix(filename):
    fr=open(filename)
    arrayOLines=fr.readlines()
    numberOfLines=len(arrayOLines) #获得文件行数
    returnMat=zeros((numberOfLines,3)) #创建m行,n列的零矩阵
    classLabelVector=[]#创建类标签元组
    index=0
    for line in arrayOLines:
        line =line.strip()#截取所有的回车字符
        listFromLine=line.split('\t') #根据分隔符将每一行划分成元素列表
        #将取得的每一行的内容存储起来,选取前三个元素作为特征值
        returnMat[index,:]=listFromLine[0:3]
        #获取最后一个元素作为类标签
        classLabelVector.append(int(listFromLine[-1]))
        index +=1
    return returnMat,classLabelVector

第三步:对样本集数据进行两两特征分类,生成可视化散点图

注意事项:
(1)导入datingTestSet2.txt,前三列为属性特征值,最后一列(-1)为分类标签。
(2)#-- coding:utf-8 --声明代码,才会显示代码中的中文字符;
(3)需要对matplotlib中字体进行指定,才会在figure图表中显示中文。

#-*- coding: utf-8 -*-
import kNN
from numpy import *
import matplotlib
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题
fig = plt.figure()
# matplotlib中的图像函数,一行一列一维
ax = fig.add_subplot(111)
datingDataMat,datingLabels = kNN.file2matrix('datingTestSet2.txt')
ax.scatter(datingDataMat[:,0], datingDataMat[:,1],15.0*array(datingLabels), 15.0*array(datingLabels))
# ax.axis([-2,25,-0.2,2.0])
plt.ylabel(u'玩游戏耗时百分比')
plt.xlabel(u'每年获取的飞行常客里程数')
plt.show()

这里写图片描述

通过上图,可发现选取不同的属性值会得到不同的显示效果,相比第一张分类图,第二张图像更能区分不同特征对样本的分类。但是由于各属性数值范围大小的不同,对欧式距离计算结果影响的程度也不同,因此需要对各样本属性数据进行归一化特征值处理,将取值范围的特征值转化为0-1区间内的值。

这里写图片描述

第四步:对数据进行优化,进行归一化特征值处理

# 归一化特征值
def autoNorm(dataSet):
    minVals=dataSet.min(0)
    maxVals=dataSet.max(0)
    ranges=maxVals-minVals
    #创建与样本集一样大小的零矩阵
    normDataSet=zeros(shape(dataSet))
    m=dataSet.shape[0]
    #样本集中元素与最小值的差值
    normDataSet=dataSet-tile(minVals,(m,1))
    #归一化操作,数据相除
    normDataSet=normDataSet/tile(ranges,(m,1))
    return normDataSet,ranges,minVals

第五步:利用分类器对测试数据集进行测试,并计算错误率

# 分类器使用测试代码
def datingClassTest():
    #选取测试集数据比例
    hoRatio=0.10
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    normMat,ranges,minVals=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)
        print "dfa: %d,real: %d" %(classifierResult,datingLabels[i])
        if(classifierResult!=datingLabels[i]):errorCount+=1.0
    #计算错误率汇总
    print "somebat: %f" %(errorCount/float(numTestVecs))

通过测试集训练算法(测试集占样本比率0.1,k=3),可以得到错误率为5%,具备较好预测效果。实际中,可以通过调整测试集数据比率和k值得到不同的错误率来验证算法的效果。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值