机器学习实践之K-近邻算法实践学习
关于本文说明,本人原博客地址位于http://blog.csdn.net/qq_37608890,本文来自笔者于2017年12月04日 22:54:26所撰写内容(http://blog.csdn.net/qq_37608890/article/details/78714664)。
本文根据最近学习机器学习书籍 网络文章的情况,特将一些学习思路做了归纳整理,详情如下.如有不当之处,请各位大拿多多指点,在此谢过.
一、k-近邻算法(k-Nearest Neighbor,KNN)概述
1、简言之,k-近邻算法采用测量不同特征值之间的距离方法进行分类。
2、工作原理
存在一个样本数据集合,也称为训练样本集,且样本集中每个数据都存在标签,也就是众所周知样本集中每一数据与所属分类的对应关系。输入没有标签的新数据以后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般情况下,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最终,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
3、k-近邻算法的一般流程
(1) 收集数据:可以使用任何方法。
(2) 准备数据: 距离计算所需要的数值,最好是结构化数据格式。
(3) 分析数据: 可以使用任何方法。
(4) 训练算法: 此步骤不适用K-近邻算法。
(5) 测试算法: 计算错误率。
(6) 使用算法: 首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。
4、相关特性
(1)优点: 精度高,对异常值不敏感、无输入假定。
(2)缺点: 计算复杂度高、空间复杂度高。
(3)适用数据范围: 数值型和标称型。
kNN是non-parametric分类器(不做分布形式的假设,直接从数据估计概率密度),是memory-based learning,不适用于高维数据(curse of dimension),算法复杂度高(可用KD树优化)。另外,k越小越容易过拟合,但是k很大会将分类精度(设想极限情况:k=1和k=N(样本数))。
二、k-近邻场景
我们知道,电影可以按题材分类,但题材本身是如何定义的?由谁来判定某部电影属于哪个题材?即同一题材的电影会具有哪些公共特征?这些都是在做电影分类时一定要搞清楚的问题。这里以动作片和爱情片为例做简要说明。动作片具有哪些公共特征,使得动作片之间非常相似,却明显有别于爱情片?动作片中也可能有接吻镜头,爱情片中也可能存在打斗镜头,所以,不能简单地依靠是否存在打斗或者接吻来判断一部电影的类型。但很明显的是,动作片中的打斗镜头更多、爱情片中的接吻次数更频繁,基于此类场景在一部电影中出现的次数可用来进行电影分类。
有人曾经统计过很多电影的打斗镜头和接吻镜头, 下方图1-1 给出了6部电影的打斗和接吻镜头。假如现在有一部从未看过的电影,你如何判断它属于动作片还是爱情片呢?
图1-1
首先,我们弄清楚这部未知电影中存在多少打斗镜头、多少接吻镜头,图1-1中问号位置是该未知电影出现的镜头数图示,具体见下方表1-1。
表1-1每部电影的打斗镜头数、接吻镜头数及电影评估类型
由图1-1和表1-1,可用将未知电影在图1-1的具体位置标出,利用欧式距离公式,计算出未知电影与样本集中其他电影之间的距离,相见下方表2-2所示。
表2-2 已知电影与未知电影之间的距离
由表2-2所示,显然,如果样本集中所有电影与未知电影之间的距离按照递增排序的话,可以得到k个距离最近的电影,这里假设k=2的话,则未知电影与电影He’s Not Really into Dudes,Beautiful Woman影片类型最为相似,判定未知电影属于爱情片。
三、示例:使用kNN算法优化约会网站的配对效果
特别提醒:有些教材或博客,在代码实现过程中,由于python2.x和python3.x的不同,在实际执行过程中出现语法错误,这里特做提醒,print语句将输出内容一律加上();另外,python3.0版本后用input替换了raw_input,请读者注意。
1、项目概述
海伦在使用约会网站寻找自己的约会对象。总结经验之后,她发现曾交往过的人分三种类型:
- 不喜欢的人
- 魅力一般的人
- 极具魅力的人
她期待:
- 工作日与魅力一般的人约会
- 周末与极具魅力的人约会
- 不喜欢的人则直接排除掉
2、 k-近邻算法开发实现流程
收集数据:提供文本文件
准备数据:使用 Python 解析文本文件
分析数据:使用 Matplotlib 画二维散点图
训练算法:此步骤不适用于 k-近邻算法
测试算法:使用海伦提供的部分数据作为测试样本。 测试样本和非测试样本的区别在于: 测试样本是已经完成分类的数据,如果预测分类与实际类别不同,则标记为一个错误。
使用算法:产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方是否为自己喜欢的类型。
3、 准备数据:从文本文件中解析数据
目前,海伦搜集来一些约会对象的数据,并把这些数据存放在文本文件 datingTestSet2.txt中,每个样本数据占据一行,总共有 1000 行。这些样本数据主要包含以下 3 种特征:
- 每年获得的飞行常客里程数
- 玩视频游戏所耗时间百分比
- 每周消费的冰淇淋公升数
而文本文件datingTestSet2.txt的数据格式如下:
- 40999 9.161978 1.110180 3
- 15823 0.991725 0.730979 2
- 35432 7.398380 0.684218 3
- 53711 12.149747 1.389088 3
- 64371 9.149678 0.874905 1
- 9289 9.666576 1.370330 2
准备数据:使用 Python 解析文本文件
将文本记录转换为 NumPy 的解析程序
- def file2matrix(filename):
- """
- Desc:
- 导入训练数据
- parameters:
- filename: 数据文件路径
- return:
- 数据矩阵 returnMat 和对应的类别 classLabelVector
- """
- fr = open(filename)
- numberOfLines = len(fr.readlines())
- returnMat = zeros((numberOfLines, 3)) # prepare matrix to return
- classLabelVector = [] # prepare labels return
- fr = open(filename)
- index = 0
- for line in fr.readlines():
- line = line.strip()
- listFromLine = line.split('\t')
- returnMat[index, :] = listFromLine[0:3]
- classLabelVector.append(int(listFromLine[-1]))
- index += 1
- return returnMat, classLabelVector
执行如下命令
- datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
- datingDataMat
得到
- array([[ 4.09200000e+04, 8.32697600e+00, 9.53952000e-01],
- [ 1.44880000e+04, 7.15346900e+00, 1.67390400e+00],
- [ 2.60520000e+04, 1.44187100e+00, 8.05124000e-01],
- ...,
- [ 6.88460000e+04, 9.97471500e+00, 6.69787000e-01],
- [ 2.65750000e+04, 1.06501020e+01, 8.66627000e-01],
- [ 4.81110000e+04, 9.13452800e+00, 7.28045000e-01]])
执行 datingLabels[0:20],得到
- [3, 2, 1, 1, 1, 1, 3, 3, 1, 3, 1, 1, 2, 1, 1, 1, 1, 1, 2, 3]
4、 分析数据:使用 Matplotlib 画二维散点图
- 执行如下代码
- import matplotlib
- import matplotlib.pyplot as plt
- fig = plt.figure()
- ax = fig.add_subplot(111)
- ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2], 15.0*array(datingLabels), 15.0*array(datingLabels))
- plt.show()
得到如下图
而下图中采用矩阵的第一和第三列属性得到很好的展示效果,清晰地标识了三个不同的样本分类区域,具有不同爱好的人其类别区域也不同。
5、 准备数据:归一化数值
归一化数据 (归一化是一个让权重变为统一的过程)
序号 | 玩视频游戏所耗时间百分比 | 每年获得的飞行常客里程数 | 每周消费的冰淇淋公升数 | 样本分类 |
---|---|---|---|---|
1 | 0.8 | 400 | 0.5 | 1 |
2 | 12 | 134 000 | 0.9 | 3 |
3 | 0 | 20 000 | 1.1 | 2 |
4 | 67 | 32 000 | 0.1 | 2 |
样本3和样本4的距离:
归一化特征值,消除特征之间量级不同导致的影响
归一化定义: 我是这样认为的,归一化就是要把你需要处理的数据经过处理后(通过某种算法)限制在你需要的一定范围内。首先归一化是为了后面数据处理的方便,其次是保正程序运行时收敛加快。 方法有如下:
线性函数转换,表达式如下:
y=(x-MinValue)/(MaxValue-MinValue)
说明:x、y分别为转换前、后的值,MaxValue、MinValue分别为样本的最大值和最小值。
对数函数转换,表达式如下:
y=log10(x)
说明:以10为底的对数函数转换。
如图:
反余切函数转换,表达式如下:
y=atan(x)*2/PI
如图:
式(1)将输入值换算为[-1,1]区间的值,在输出层用式(2)换算回初始值,其中和分别表示训练样本集中负荷的最大值和最小值。
在统计学中,归一化的具体作用是归纳统一样本的统计分布性。归一化在0-1之间是统计的概率分布,归一化在-1--+1之间是统计的坐标分布。
- def autoNorm(dataSet):
- """
- Desc:
- 归一化特征值,消除特征之间量级不同导致的影响
- parameter:
- dataSet: 数据集
- return:
- 归一化后的数据集 normDataSet. ranges和minVals即最小值与范围,并没有用到
- 归一化公式:
- Y = (X-Xmin)/(Xmax-Xmin)
- 其中的 min 和 max 分别是数据集中的最小特征值和最大特征值。该函数可以自动将数字特征值转化为0到1的区间。
- """
- 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)) # element wise divide
- return normDataSet, ranges, minVals
因为测试数据每一次都要与全量的训练数据进行比较,所以这个过程是没有必要的。
6 、 测试算法
作为完整程序验证分类器
使用海伦提供的部分数据作为测试样本。如果预测分类与实际类别不同,则标记为一个错误。
kNN 分类器针对约会网站的测试代码
- def datingClassTest():
- """
- Desc:
- 对约会网站的测试方法
- parameters:
- none
- return:
- 错误数
- """
- hoRatio = 0.1 # 测试范围,一部分测试一部分作为样本
- datingDataMat, datingLabels = file2matrix('datingTestSet2.txt') # load data setfrom file
- normMat, ranges, minVals = autoNorm(datingDataMat)
- m = normMat.shape[0]
- numTestVecs = int(m * hoRatio)
- print 'numTestVecs=', numTestVecs
- 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)
7、 使用算法:构建完整可用的系统
上面已经在数据上对分类器进行了测试,现在则可以使用这个分类器帮助海伦对于约会对象进行分类,即海伦在网站上找到某人并输入他的信息,该程序会给出她对对方喜欢程度的预测值.
- def clasdifyPerson():
- resultList = ['not at all', 'in small doses', 'in large doses']
- percentTats = float(raw_input("percentage of time spent playing video games ?"))
- ffMiles = float(raw_input("frequent filer miles earned per year?"))
- iceCream = float(raw_input("liters of ice cream consumed per year?"))
- datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
- normMat, ranges, minVals = autoNorm(datingDataMat)
- inArr = array([ffMils, percentTats, iceCream])
- classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels, 3)
- print ("You will probably like this person: ", resultList[classifierResult - 1])
实际运行效果如下:
- >>> kNN.classifyPerson()
- percentage of time spent playing video games?10
- frequent flier miles earned per year?10000
- liters of ice cream consumed per year?0.5
- You will probably like this person: in small doses
四、 项目案例2: 手写数字识别系统
1、 项目概述
构造一个能识别数字 0 到 9 的基于 KNN 分类器的手写数字识别系统。
需要识别的数字是存储在文本文件中的具有相同的色彩和大小:宽高是 32 像素 * 32 像素的黑白图像。
2、 开发流程
收集数据:提供文本文件。 准备数据:编写函数 img2vector(), 将图像格式转换为分类器使用的向量格式 分析数据:在 Python 命令提示符中检查数据,确保它符合要求 训练算法:此步骤不适用于 KNN 测试算法:编写函数使用提供的部分数据集作为测试样本,测试样本与非测试样本的 区别在于测试样本是已经完成分类的数据,如果预测分类与实际类别不同, 则标记为一个错误 使用算法:本例没有完成此步骤,若你感兴趣可以构建完整的应用程序,从图像中提取 数字,并完成数字识别,美国的邮件分拣系统就是一个实际运行的类似系统
收集数据: 提供文本文件
目录 trainingDigits中包含了大约 2000 个例子,每个例子内容如下图所示,每个数字大约有 200 个样本;目录 testDigits中包含了大约 900 个测试数据。
准备数据: 编写函数 img2vector(), 将图像文本数据转换为分类器使用的向量
将图像文本数据转换为向量
- def img2vector(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
分析数据:在 Python 命令提示符中检查数据,确保它符合要求
在 Python 命令行中输入下列命令测试 img2vector 函数,然后与文本编辑器打开的文件进行比较:
- >>> testVector = kNN.img2vector('testDigits/0_13.txt')
- >>> testVector[0,0:31]
- array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
- >>> testVector[0,31:63]
- array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
训练算法:此步骤不适用于 KNN
因为测试数据每一次都要与全量的训练数据进行比较,所以这个过程是没有必要的。
- def handwritingClassTest():
- hwLabels = []
- trainingFileList = listdir('trainingDigits') # load the training set
- m = len(trainingFileList)
- trainingMat = zeros((m, 1024))
- for i in range(m):
- fileNameStr = trainingFileList[i]
- fileStr = fileNameStr.split('.')[0] # take off .txt
- classNumStr = int(fileStr.split('_')[0])
- hwLabels.append(classNumStr)
- # 将 32*32的矩阵->1*1024的矩阵
- trainingMat[i, :] = img2vector('trainingDigits/%s' % fileNameStr)
- testFileList = listdir('testDigits') # iterate through the test set
- errorCount = 0.0
- mTest = len(testFileList)
- for i in range(mTest):
- fileNameStr = testFileList[i]
- fileStr = fileNameStr.split('.')[0] # take off .txt
- classNumStr = int(fileStr.split('_')[0])
- vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
- classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
- print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr)
- if (classifierResult != classNumStr): errorCount += 1.0
- print ("\nthe total number of errors is: %d" % errorCount)
- print ("\nthe total error rate is: %f" % (errorCount / float(mTest)))
使用算法:本例没有完成此步骤,若你感兴趣可以构建完整的应用程序,从图像中提取数字,并完成数字识别,美国的邮件分拣系统就是一个实际运行的类似系统
五、 K-近邻算法小结
截至目前,我们做一总结,k-近邻算法必须保存全部数据集,如果训练数据集很大,必须使用大量的存储空间.由于必须对数据集中的每个数据计算距离值,实际使用时可能非常耗时.此外,k-近邻还有以缺陷是它没办法给出任何数据的基础结构信息,也就无法得知平均实例样本和典型实例样本有哪些特征.而要解决这个问题,需要使用概率测量方法来处理.
k 近邻算法有 三个基本的要素:
k 值的选择
- k 值的选择会对 k 近邻算法的结果产生重大的影响。
- 如果选择较小的 k 值,就相当于用较小的邻域中的训练实例进行预测,“学习”的近似误差(approximation error)会减小,只有与输入实例较近的(相似的)训练实例才会对预测结果起作用。但缺点是“学习”的估计误差(estimation error)会增大,预测结果会对近邻的实例点非常敏感。如果邻近的实例点恰巧是噪声,预测就会出错。换句话说,k 值的减小就意味着整体模型变得复杂,容易发生过拟合。
- 如果选择较大的 k 值,就相当于用较大的邻域中的训练实例进行预测。其优点是可以减少学习的估计误差。但缺点是学习的近似误差会增大。这时与输入实例较远的(不相似的)训练实例也会对预测起作用,使预测发生错误。 k 值的增大就意味着整体的模型变得简单。
- 近似误差和估计误差,请看这里:https://www.zhihu.com/question/60793482
距离度量
- 特征空间中两个实例点的距离是两个实例点相似程度的反映。
- k 近邻模型的特征空间一般是 n 维实数向量空间
。使用的距离是欧氏距离,但也可以是其他距离,如更一般的
距离,或者 Minkowski 距离。
分类决策规则
- k 近邻算法中的分类决策规则往往是多数表决,即由输入实例的 k 个邻近的训练实例中的多数类决定输入实例的类。
机器学习实践之K-近邻算法实践学习的更多相关文章
- 机器学习03:K近邻算法
本文来自同步博客. P.S. 不知道怎么显示数学公式以及排版文章.所以如果觉得文章下面格式乱的话请自行跳转到上述链接.后续我将不再对数学公式进行截图,毕竟行内公式截图的话排版会很乱.看原博客地址会有更 ...
- 02机器学习实战之K近邻算法
第2章 k-近邻算法 KNN 概述 k-近邻(kNN, k-NearestNeighbor)算法是一种基本分类与回归方法,我们这里只讨论分类问题中的 k-近邻算法. 一句话总结:近朱者赤近墨者黑! k ...
- 机器学习实战笔记--k近邻算法
#encoding:utf-8 from numpy import * import operator import matplotlib import matplotlib.pyplot as pl ...
- 机器学习随笔01 - k近邻算法
算法名称: k近邻算法 (kNN: k-Nearest Neighbor) 问题提出: 根据已有对象的归类数据,给新对象(事物)归类. 核心思想: 将对象分解为特征,因为对象的特征决定了事对象的分类. ...
- 《机器学习实战》-k近邻算法
目录 K-近邻算法 k-近邻算法概述 解析和导入数据 使用 Python 导入数据 实施 kNN 分类算法 测试分类器 使用 k-近邻算法改进约会网站的配对效果 收集数据 准备数据:使用 Python ...
- 机器学习:1.K近邻算法
1.简单案例:预测男女,根据身高,体重,鞋码 import numpy as np import matplotlib import sklearn from skleran.neighbors im ...
- 《机器学习实战》——K近邻算法
三要素:距离度量.k值选择.分类决策 原理: (1) 输入点A,输入已知分类的数据集data (2) 求A与数据集中每个点的距离,归一化,并排序,选择距离最近的前K个点 (3) K个点进行投票,票数最 ...
- GridSearchCV网格搜索得到最佳超参数, 在K近邻算法中的应用
最近在学习机器学习中的K近邻算法, KNeighborsClassifier 看似简单实则里面有很多的参数配置, 这些参数直接影响到预测的准确率. 很自然的问题就是如何找到最优参数配置? 这就需要用到 ...
- 机器学习之K近邻算法(KNN)
机器学习之K近邻算法(KNN) 标签: python 算法 KNN 机械学习 苛求真理的欲望让我想要了解算法的本质,于是我开始了机械学习的算法之旅 from numpy import * import ...
随机推荐
- 离线缓存 manifest
程序的离线缓存由一个叫做manifest的文本文件控制,把需要离线缓存的文件列在里面即可,这个列表还可以控制需要缓存的情况,甚至当用户从缓存地址进入到没有缓存的地址应该显示什么 当浏览器下载解析了ma ...
- 几种移动app API调用认证方案浅析
最近做的金融项目,app调用的接口需要做一个身份认证,所以找了下目前API services验证的几种方式.之前翻译的一篇文章--[译]移动API安全终极指南中,主要提出了API服务调用验证的问题,通 ...
- Asp.Net MVC 使用 Ajax
Asp.Net MVC 使用 Ajax Ajax 简单来说Ajax是一个无需重新加载整个网页的情况下,可以更新局部页面或数据的技术(异步的发送接收数据,不会干扰当前页面). Ajax工作原理 Ajax ...
- robotframework自动化系列:新增流程
刚接手项目的时候,要求所有流程在上线之前必须确保正向操作是正确的:这个时候又有新的模块需要测试,所以引入自动化测试是非常有必要的!通过对比,尝试使用RF进行自动化的回归测试. 测试中最常见的操作就是增 ...
- 初识Java网络编程
事实上网络编程简单的理解就是两台计算机相互通讯数据而已,对于程序员而言,去掌握一种编程接口并使用一种编程模型相对就会显得简单的多了,Java SDK提供一些相对简单的Api来完成这些工作.Socket ...
- [转载] Storm:最火的流式处理框架
转载自http://www.cnblogs.com/langtianya/p/5199529.html 伴随着信息科技日新月异的发展,信息呈现出爆发式的膨胀,人们获取信息的途径也更加多样.更加便捷,同 ...
- pt-tcp-model
http://blog.9minutesnooze.com/analyzing-http-traffic-tcpdump-perconas-pttcpmodel/ #获取200k个packets tc ...
- 如何用while循环输出十行十列变色★☆
输出十行十列星星 k = 0 #设置一个终止变量 while k < 10: i = 0 #设置一个满十换行变量 while i < 10: print('★',end='') i += ...
- python从2.7升级到3.5 需要主要的问题
今天鼓足勇气把我们python从2.7升级到3.5.我用的是pycharm开发工具.升级过程遇到一些问题小结下: 1.右击项目: 找到左侧 project interpreter选项,配置项目开发环境 ...
- 理解MVC入门基础原理
今天,我将开启一个崭新的话题:ASP.NET MVC框架的探讨.首先,我们回顾一下ASP.NET Web Form技术与ASP.NET MVC的异同点,并展示各自在Web领域的优劣点.在讨论之前,我对 ...