[题外话]近期申请了一个微信公众号:平凡程式人生。有兴趣的朋友可以关注,那里将会涉及更多机器学习、OpenCL+OpenCV以及图像处理方面的文章。


2.2   简单实例

为了验证前面实现的K近邻算法正确性,先设计一个简单实例。

该实例中,在code中调用函数createDataSet()创建了样本数据group及分类 labels,具体实现如下:

def createDataSet():group = array([[1.1, 1.1], [1.0, 1.2], [0.2, 0.4], [0.9, 0.1]]) #创建4x2的数组作为训练样本labels = ['A', 'A', 'B', 'B'] #4个训练样本所属类的标记return group, labels

然后调用模块kNN的函数kNN.knnClassify()对应测试样本[0.2, 0]进行分类测试,其分类结果为B,符合预期。具体实现如下:

group, labels = createDataSet() #创建训练样本和对应标记
realIndex = kNN.knnClassify([0.2, 0], group, labels, 3) #检测测试样本[0.2, 0]属于哪个类
print realIndex

为了清楚地看到训练样本各个类别的分类情况,可以调用matplotlib绘制了样本数据的散列图。具体实现如下:

#Matplotlib 里的常用类的包含关系为 Figure -> Axes -> (Line2D, Text, etc.)
#一个Figure对象可以包含多个子图(Axes),在matplotlib中用Axes对象表示一个绘图区域,可以理解为子图。
fig = plt.figure() #创建图表fig
ax = fig.add_subplot(1, 1, 1) #在图表fig中创建一个子图ax
#绘制散列图,前两个参数表示x轴和y轴所要显示的数据,s表示符号大小,c表示颜色,marker表示符号类型
#ax.scatter(group[:, 0], group[:, 1], s = 50, c = 'r', marker = 'o')
label = list(ones(2))+list(2*ones(2)) #定义4个元素的数组
#使用数组label中的值来改变s和c的值
ax.scatter(group[:, 0], group[:, 1], 15.0 * array(label), 15.0 * array(label), marker = 'o')
#设置坐标系x轴和y轴的上下限
ax.axis([0, 2, 0, 2])
ax.set_title('kNN_4_simple_group') #设置子图的的标题
plt.xlabel('x_value')
plt.ylabel('y_value')
plt.savefig("kNN_4_simple_group.pdf")
plt.show()

散列图的结果如下图所示。两个蓝色点为A类,黄色点为B类。测试样本[0.2, 0]应该为B类,这与K近邻算法的分类结果一致。

2.3   约会网站

这个实例中会对约会网站的用户信息进行分类,方便用户选择自己喜欢的约会对象。我们有1000个样本,存储在txt文件datingTestSet2.txt中。每个样本有4种信息,分别为:每年获得的飞行常客里程数、玩视频游戏所耗时间百分比、每周消费的冰淇淋公升数和样本分类。

由于样本数据存储在文本文件中,需要先从文件中读出样本数据。这里使用函数file2matrix(filename)来完成这项任务。打开文本文件,获取到样本个数,创建存储所有样本信息的二维数组returnMat,同时创建一个列表classLabelVector用来存储每个样本的分类信息。从文本文件中读取一行数据,将其分割,将前三项写入二维数组returnMat,最后一项写入classLabelVector。具体实现如下:

#从训练样本文件中读取样本信息,并将分类信息与其他数据分别存储在不同的数组中
def file2matrix(filename):fd = open(filename)numberOfLines = len(fd.readlines()) #获取文件中样本的数目#创建numberOfLinesx3的二维数组,并初始化为0;存储从文件中读取的样本信息的前三列returnMat = zeros((numberOfLines, 3)) classLabelVector = [] #定义存储样本类别的列表fd = open(filename) #重新打开文件,因为前面为了获取样本数目从文件中读取了所有样本,文件指针不在文件最前面index = 0for line in fd.readlines(): #从文件中循环读取每一行数据进行处理line = line.strip() #去掉这一行前面和后面的空格listFromLine = line.split('\t') #将数据按空格分割,本示例中将所读行数据分为4个独立数据returnMat[index, :] = listFromLine[0 : 3] #将前3个数据存储到returnMat数组中classLabelVector.append(int(listFromLine[-1])) #将最后一个数据,即第4个数据,转换成int类型后存储到classLabelVector最后面index += 1return returnMat, classLabelVector #returnMat存储样本前3列数据,classLabelVector存储样本对应的分类信息

由于样本中三个特征的单位不同,无法比较,需要将特征信息归一化。每个特征的归一化按照这个公式来完成:newValue = (oldValue - min) / (max - min)

函数autoNorm()的输入参数dataSet为Nx3的二维数组,存储着N个样本的特征值。通过函数min(0)/max(0)求得每一列,即每一种特征中最小值和最大值,然后算出特征范围差。创建与参数dataSet结构完全一样的数组并初始化为0,用来存储归一化结果。对二维数组dataSet中每一个减去该列的最小值,然后除以它们的特征范围差,完成归一化。

#对输入数组进行归一化数值处理,也叫特征缩放,用于将特征缩放到同一个范围内
#本例的缩放公式为: newValue = (oldValue - min) / (max - min)
def autoNorm(dataSet): #输入数组dataSet为Nx3的二维数组minVals = dataSet.min(0) #获取数组中每一列的最小值,minVals为1x3的数组;max(0)获取每一行的最小值maxVals = dataSet.max(0) #获取数组中每一列的最大值,maxVals为1x3的数组;max(1)获取每一行的最大值ranges = maxVals - minVals #获取特征范围差,ranges也是1x3的数组normDataSet = zeros(shape(dataSet)) #创建与dataSet的维数、类型完全一样的数组,并初始化为0,用于存储归一化后的结果m = dataSet.shape[0] #获取输入数组的行数#tile(minVals, (m, 1))创建mx1的数组,数组元素为1x3的最小值数组,其返回值为mx3的数组#从原始数组的各个元素中,减去对应列的最小值normDataSet = dataSet - tile(minVals, (m, 1))#tile(ranges, (m, 1))创建mx1的数组,数组元素为1x3的特征范围差,其返回值为mx3的数组#原始数组的各个元素除以对应列的特征范围差,完成归一化normDataSet = normDataSet / tile(ranges, (m, 1))return normDataSet, ranges, minVals #返回归一化后Nx3的数组、1x3的特征范围差数组和1x3的每列最小值数组

归一化后的数据就可以进行测试了。函数datingClassTest()完成测试工作。在该函数中,选择所有样本的前一半为测试样例,后一半为训练样例。先调用函数file2matrix()从样本文件datingTestSet2.txt中读出所有样例数据。然后调用函数autoNorm()对样例数据进行归一化。对测试样本从头到尾,调用函数kNN.knnClassify()依次判断其类别,然后跟真实的类别进行比对,记录错误情况,算出错误率。

#根据训练样本datingTestSet2.txt中数据对kNN分类算法进行测试
def datingClassTest():hoRatio = 0.50 #用于分割样本,将文件中获取的样本前面一半作为测试样例,后面一半作为训练样例#从样本文件datingTestSet2.txt中读取所有样例数据及分类信息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 = kNN.knnClassify(normMat[i, :], normMat[numTestVecs : m, :], datingLabels[numTestVecs : m], 3)#print "the classifier case back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i])if (classifierResult != datingLabels[i]): #如果分类结果与从文件中读取的值不一致,则判为分类错误errorCount += 1.0print "the classifier case back with: %d, the real answer is: %d, index: %d" % (classifierResult, datingLabels[i], i)print "the total error rate is: %f" % (errorCount / float(numTestVecs)) #打印出错误率print errorCount #返回错误次数

2.4  手写体识别

这里构建的手写识别系统只能识别数字0到9。需要识别的数字已经使用图形处理软件,处理成具有相同色彩和大小:宽高是32像素x32像素的黑白图像。尽管采用文本格式存储图像不能有效地利用内存空间,但是为了方便理解,我们还是将图像转换为文本格式。

该实例中有两个文件夹存储样本文件,目录trainingDigits中包含了大约2000个例子,每个数字大约有200个样本;目录testDigits中包含了大约900个测试数据。我们使用目录trainningDigits中的数据训练分类器,使用目录testDigits中的数据测试分类器的效果。

首先,需要读取样本文件,将其转换为1x1024的数组。在样本文件中存储了32行32列的数字,来模拟图像数据。函数img2vector(filename)从文本文件中读取其前32行,每一行读取32个字符,将其转换为整型数字,存储在1x1024的数组中。

#将文件中读取的数字字符转换为整型数字,存储在一维数组中
def img2vector(filename):returnVect = zeros((1, 1024)) #创建1x1024的一维数组,并初始化为0#打开文件从中读取32行数据,并将每一行的32个byte转化为整型数字fd = open(filename) for i in range(32):lineStr = fd.readline() #读取一行数据for j in range(32):returnVect[0, 32 * i + j] = int(lineStr[j]) #每个byte转换为整型数字return returnVect

函数handwritingClassTest()完成手写识别工作。它从训练样本目录trainingDigits读取所有的样本文件,从文件名称中解析出每个样本的类别,即0-9。然后打开文件,读取32x32的字符转换成1x1024的一维数组保存起来。

读取测试样本目录testDigits下的测试样本,同样获取样本的类别以及样本的内容。将测试样本从第一个开始,调用函数kNN.knnClassify()依次与训练样本进行分类测试。统计分类错误的情况,算出错误率。

def handwritingClassTest():hwLabels = [] #定义存储训练样本类别标记的列表变量#listdir(): 返回指定的文件夹包含的文件或文件夹的名字的列表。这个列表以字母顺序。 它不包括 '.' 和'..' 即使它在文件夹中。#目录trainingDigits下面存放着所有的训练样本文件,listdir获取这些文件名将其存储在列表变量trainingFileList中trainingFileList = listdir('trainingDigits')m = len(trainingFileList) #获取文件列表中的文件个数trainingMat = zeros((m, 1024)) #创建mx1024的二维数组且初始化为0,存储训练样本的内容;每个样本1024个bytefor i in range(m): #逐个从样本文件中读取内容转换成整型存储在二维数组trainingMat中fileNameStr = trainingFileList[i] #获取第i个样本的文件名0_3.txt,表示数字0的第3个样本文件fileStr = fileNameStr.split('.')[0] #获取样本文件名称0_3classNumStr = int(fileStr.split('_')[0]) #获取该样本对应的数字类别,即0hwLabels.append(classNumStr) #将样本的数字类别存储在列表变量hwLabels中#将文件trainingDigits/0_3.txt读取出来,并将其内容转换为整型数字存储在二维数组trainingMat第i个元素中trainingMat[i, :] = img2vector('trainingDigits/%s' % fileNameStr)testFileList = listdir('testDigits') #测试样本存放在testDigits目录下,获取测试样本的文件名列表errorCount = 0.0mTest = len(testFileList) #获取测试样本的个数for i in range(mTest): #对测试样本,逐个进行检测fileNameStr = testFileList[i] #获取第i个测试样本,如0_1.txtfileStr = fileNameStr.split('.')[0] #获取文件名0_1classNumStr = int(fileStr.split('_')[0]) #获取样本的数字类别0#将文件testDigits/0_1.txt读取出来,并将其内容转换为整型数字存储在1x1024的数组vectorUnderTest中vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)#将vectorUnderTest与之前的训练样本逐一进行比较,获取最近邻的3个样本,#返回这3个样本中类别最多的那个类别,作为该测试样本的类别classifierResult = kNN.knnClassify(vectorUnderTest, \trainingMat, hwLabels, 3)#print "the classifier came back with: %d, the real answer is: %d" \#      % (classifierResult, classNumStr)if (classifierResult != classNumStr): #如果返回类别与真实类别不一致,则增加错误数量errorCount += 1.0print "the classifier came back with: %d, the real answer is: %d" \% (classifierResult, classNumStr)print "\nthe total number of errors is: %d" % errorCount #打印出错误数量print "\nthe total error rate is: %f" % (errorCount / float(mTest)) #打印出错误率

3、小结

K近邻算法是分类数据最简单最有效的算法,这里通过三个例子讲述了如何使用K近邻算法构造分类器。K近邻算法是基于实例的学习,使用算法时我们必须有接近实际数据的训练样本数据。K近邻算法必须保存全部数据集,如果训练数据集很大,必须使用大量的存储空间。此外,由于必须对数据集中的每个数据计算距离值,实际使用时可能非常耗时。

本文中涉及的所有code可以访问如下目录获取:

https://github.com/stevewang0/MLInAction

(完)

写程序学ML:K近邻(KNN)算法原理及实现(二)相关推荐

  1. 写程序学ML:Logistic回归算法原理及实现(二)

    2.Logistic回归算法的实现 2.1   Logistic算法的实现 首先,我们实现梯度上升算法. Sigmoid函数的定义如下: #sigmoid函数的实现 def sigmoid(inX): ...

  2. 机器学习经典算法具体解释及Python实现--K近邻(KNN)算法

    (一)KNN依旧是一种监督学习算法 KNN(K Nearest Neighbors,K近邻 )算法是机器学习全部算法中理论最简单.最好理解的.KNN是一种基于实例的学习,通过计算新数据与训练数据特征值 ...

  3. Python+OpenCV:理解k近邻(kNN)算法(k-Nearest Neighbour (kNN) algorithm)

    Python+OpenCV:理解k近邻(kNN)算法(k-Nearest Neighbour (kNN) algorithm) 理论 kNN is one of the simplest classi ...

  4. k近邻算法_K近邻(knn)算法是如何完成分类的?

    摘要:K近邻算法是机器学习中的一个非常基础的算法.本文通过自生成数据,通过绘图的方式演示KNN算法的思路,让你不看数学公式就看了解什么是KNN算法. 关键词:KNN算法 1 生成一个二分类的数据集 本 ...

  5. ML之kNN:k最近邻kNN算法的简介、应用、经典案例之详细攻略

    ML之kNN:k最近邻kNN算法的简介.应用.经典案例之详细攻略 目录 kNN算法的简介 1.kNN思路过程 1.1.k的意义 1.2.kNN求最近距离案例解释原理-通过实际案例,探究kNN思路过程 ...

  6. 机器学习算法(7)——K近邻(KNN)、K-means、模糊c-均值聚类、DBSCAN与层次与谱聚类算法

    1.K-近邻算法(KNN)概述 (有监督算法,分类算法) 最简单最初级的分类器是将全部的训练数据所对应的类别都记录下来,当测试对象的属性和某个训练对象的属性完全匹配时,便可以对其进行分类.但是怎么可能 ...

  7. 【Python-ML】SKlearn库K近邻(KNN) 使用

    # -*- coding: utf-8 -*- ''' Created on 2018年1月15日 @author: Jason.F @summary: Scikit-Learn库K近邻分类算法 '' ...

  8. 机器学习——K近邻分类算法及python代码实现

    <机器学习:公式推导与代码实践>鲁伟著读书笔记. K近邻(K-nearest neighbor,K-NN)算法是一种经典的监督学习的分类方法.K近邻算法是依据新样本与k个与其相邻最近的样本 ...

  9. 机器学习100天(三十):030 K近邻分类算法-K值的选择

    机器学习100天,今天讲的是:K近邻分类算法-K值的选择. <机器学习100天>完整目录:目录 上一节我们讲了 K 折交叉验证的理论,下面我们将 K 折交叉验证算法应用到 K 近邻分类算法 ...

最新文章

  1. 抽象工厂模式 java实例 tclhaier_Unity常用的设计模式_工厂模式系列之抽象工厂模式...
  2. pfSense book之硬件配置指南
  3. win8安装mysql8_windows安装mysql8详解
  4. 面向对象编程02—装饰器、类方法、静态方、访问控制
  5. linux 系统监控、诊断工具之 top 详解
  6. iis windows phpstudy安装redis扩展
  7. android 搜索文件代码怎么写,android学习笔记(5)-一个搜索文件的APP(2)-搜索功能的实现...
  8. 【build your own xxx】实现你自己的bind函数
  9. python基础教程百度云-python从入门到精通视频教程百度云资源
  10. 怎样从外网访问自己的HTTP服务器
  11. bzoj 1409 Password
  12. Python中的staticmethod和classmethod
  13. HIPS软件的一些知识
  14. Linux磁盘分区及文件系统格式化和挂载
  15. JSON离线格式化工具HiJson
  16. 为什么小程序getUserInfo获取的微信名称是“微信用户“?2.10.4词库之后如何渲染微信名称,微信头像和获取个人信息?
  17. 怎么给div加背景图片
  18. 【课程·研】软件工程 | 结对编程:建造金字塔(1157)
  19. Vulkan_Shader—高级光照_阴影_原理
  20. 系统工程师学习(简单Linux命令应用)(一)

热门文章

  1. SVN版本管理与代码上线架构方案
  2. 你的工资是高了还是低了,薪资计算器会告诉你
  3. 面向CCF目录中的论文暴力爬取实现
  4. 《如何阅读一本书》--读书笔记
  5. 桌面点击计算机没反应怎么办,win10桌面点击没反应怎么办_win10电脑桌面鼠标点击没反应修复方法...
  6. python编程樱花盛开_武大樱花又盛开,用python画一棵樱花树
  7. ps怎么做计算机图标,【2人回答】PS怎么制作桌面图标?-3D溜溜网
  8. java数组循环_Java之循环结构及数组
  9. c语言地址和地址怎么比较大小,C语言地址对齐(转)-计算网络编程的结构大小...
  10. 医疗直播怎么做?直播前准备篇