【Machine Learning in Action】学习笔记——(2)k-近邻算法

【Machine Learning in Action】学习笔记——(2)k-近邻算法

​ 因为第一章完全是导入性质的,所以学习笔记从第二章开始.书本的源代码可以在www.manning.com/MachineLearninginAction中找到.

k-近邻算法概述

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

​ 例如我们现在有6个样本(1-6),每个样本有两个特征值(A,B),其中1~3是I分类,而4-6是II分类.

​ 为了确定样本7的分类,我们根据7的两个特征值计算出1~6号样本和7之间的距离,接着找到k个与样本7距离最小的样本.

​ 接着根据距离最近的k个样本的分类决定样本7的分类.

​ 例如我们取k=3,最近的三个样本分别是1,2,3.因此我们判断样本7为I分类.

K-近邻算法
优点:精度高、对异常值不敏感、无数据输入假定
缺点:计算复杂度高、空间复杂度高
适用数据范围:数值型和标称型

K-近邻算法的一般流程

(1)收集数据

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

(3)分析数据

(4)训练算法:不适用于k-近邻算法(那这个标题改成机器学习算法的一般流程比较合理)

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

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

使用python制造分类数据

​ 书本里是分成了两个文件,不过我就在一个notebook里进行了

from numpy import *
import operator

def creatDataSet():
    group=array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels=['A','A','B','B']
    return group,labels

group,labels=createDataSet()#给样本赋值,得到样本特征值组合以及对应的标签

实施KNN分类算法

def classify0(inX,dataSet,labels,k):
    #inX是想要对其分类的目标,dataSet是样本集,labels是样本集对应的目标
    dataSetSize=dataSet.shape[0]
    diffMat=tile(inX,(dataSetSize,1))-dataSet
    #先把inX复制dataSetSize次,构成和dataSet相同大小的矩阵,接着与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
        #记录k个样本中不同标签的出现次数
  sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
		#再将标签按照出现次数降序排列,返回出现次数最多的标签
    return sortedClassCount[0][0]

​ 接着我们来使用这个算法

classify0([0,0],group,labels,3)

​ 得到对[0,0]的分类结果,B.

如何测试分类器

​ 引入错误率:分类器给出错误结果的次数除以测试执行的总数.完美分类器的错误率为0.最差分类器的错误率为1.0.

示例1:使用k-近邻算法改进约会网站的配对效果

(1)收集数据:导入文本文档datingTestSet2.txt

(2)准备数据:使用Python解析文本文件

(3)分析数据:使用Matplotlib画二维扩散图

(4)训练算法:不适用于k-近邻算法

(5)测试算法:使用海伦提供的部分数据作为测试样本

(6)使用算法:产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方是否是自己喜欢的类型

准备数据:从文本文件中解析数据
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() #用strip函数去除每一行首尾的空白
        listFromLine=line.split('\t')
        returnMat[index,:]=listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index+=1
    return returnMat,classLabelVector

​ 接着使用上述函数

datingDataMat,datingLabels=file2matrix(r'./datingTestSet2.txt')

​ 简单检查一下数据内容

>>>datingDataMat
array([[4.0920000e+04, 8.3269760e+00, 9.5395200e-01],
       [1.4488000e+04, 7.1534690e+00, 1.6739040e+00],
       [2.6052000e+04, 1.4418710e+00, 8.0512400e-01],
       ...,
       [2.6575000e+04, 1.0650102e+01, 8.6662700e-01],
       [4.8111000e+04, 9.1345280e+00, 7.2804500e-01],
       [4.3757000e+04, 7.8826010e+00, 1.3324460e+00]])
分析数据:使用Matplotlib创建散点图
import matplotlib
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
#plt默认字体无法显示中文字符,这里设置成雅黑
fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(datingDataMat[:,1],datingDataMat[:,2])
plt.xlabel("玩游戏所耗时间百分比")
plt.ylabel("每周消费的冰淇淋公升数")
#使用第二三列数据,分别是"玩游戏所耗时间百分比"和"每周消费的冰淇淋公升数"
plt.show()

在这里插入图片描述

​ 由于没有使用样本分类的特征值,很难从图中看出任何有用的数据模式信息

​ 下面用不同色彩来表示不同样本分类,以便更好地理解数据信息,使用Matplotlib提供地scatter函数

fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))
plt.xlabel("玩游戏所耗时间百分比")
plt.ylabel("每周消费的冰淇淋公升数")
plt.show()

在这里插入图片描述

​ 再试着将矩阵第一列和第二列来展示数据

fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))
plt.ylabel("玩游戏所耗时间百分比")
plt.xlabel("每年获取的飞行常客里程数")
plt.show()

在这里插入图片描述

​ 不难看出用第一列和第二列数据能得到更好的展示效果

准备数据:归一化数值

​ 如果直接使用特征数值本身计算距离,数值差值大的属性对计算结果的影响更大.所以为了处理不同取值范围的特征值,我们将数据归一化处理,如将取值范围处理为0到1或者-1到1之间.
n e w V a l u e = ( o l d V a l u e − m i n ) / ( m a x − m i n ) newValue=(oldValue-min)/(max-min) newValue=(oldValuemin)/(maxmin)

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
normMat,ranges,minVals=autoNorm(datingDataMat)

fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(normMat[:,0],normMat[:,1],15.0*array(datingLabels),15.0*array(datingLabels))
plt.ylabel("玩游戏所耗时间百分比")
plt.xlabel("每年获取的飞行常客里程数")
plt.show()

在这里插入图片描述

测试算法
def datingClassTest():
    hoRatio = 0.10      #提取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 ("the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]))
        if (classifierResult != datingLabels[i]): errorCount += 1.0
    print ("the total error rate is: %f" % (errorCount/float(numTestVecs)))
    print (errorCount)

​ 得到错误率为0.05,还是相当不错的

使用算法:构建完整可用系统
def classifyPerson():
    resultList=["完全无感","有点心动","很有吸引力"]
    percentTats=float(input("每周游戏时间的比例?"))
    ffMiles=float(input("每年获取的飞行常客里程数?"))
    iceCream=float(input("每周消费的冰淇淋公升数?"))
    datingDataMat,datingLabels=file2matrix("datingTestSet2.txt")
    normMat, ranges, minVals = autoNorm(datingDataMat)
    inArr=array([ffMiles,percentTats,iceCream])
    classifierResult=classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
    print("你可能对这个人的好感度:",resultList[classifierResult-1])

classifyPerson函数为最终的预测函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值