Python3 机器学习实战自我讲解(二) K-近邻法-海伦约会-手写字体识别
2018-02-04 14:24
537 查看
第二章 k近邻法
2.1 概念
2.1.1 k近邻法简介
k近邻法(k-nearest neighbor, k-NN)是1967年由Cover T和Hart P提出的一种基本分类与回归方法。它的工作原理是:存在一个样本数据集合,也称作为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据后,将新的数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
K近邻算法 优 点 :精度高、对异常值不敏感、无数据输入假定。 缺点:计算复杂度高、空间复杂度高。 适用数据范围:数值型和标称型
举个例子,我们来使用k近邻法来分类爱情片和动作片。有人曾统计过很多电影的打斗镜头和接吻镜头,那么如何确定一部没看过的电影是爱情片还是动作片呢?我们可以使用k-nn来解决这个问题。
电影名称 | 打斗镜头 | 接吻镜头 | 电影类型 |
---|---|---|---|
California Man | 3 | 104 | 爱情片 |
He’s Not Really into Dudes | 2 | 100 | 爱情片 |
Robo Slayer 3000 | 99 | 5 | 动作片 |
Amped ll | 98 | 2 | 动作片 |
? | 18 | 90 | 未知 |
现在我们如何判断该电影的类型呢?当然是通过最近邻居来判断啦~如何判断邻居的距离呢,首先我们需要定义距离。
2.1.2 距离度量
我们一般运用欧氏距离:∥AB||=(x1−x2)2+(y1−y2)2−−−−−−−−−−−−−−−−−−√‖AB||=(x1−x2)2+(y1−y2)2
这样我们可以得到
电影名称 | 与未知电影的距离 |
---|---|
California Man | 20.5 |
He’s Not Really into Dudes | 18.7 |
Robo Slayer 3000 | 117.4 |
Amped ll | 118.9 |
k-近邻算法的一般流程:
(1)收集数据:可以使用任何方法。
(2)准备数据:距离计算所需要的数值,最好是结构化的数据格式。
(3)分析数据:可以使用任何方法。
(4)训练算法:此步骤不适用于k近邻算法。
(5)测试算法:计算错误率。
(6)使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k -近邻算法判定输
入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。
2.1.3 实战环节
python3实现:# -*- coding: UTF-8 -*- import numpy as np #数据集,标签 dataSet=np.array([[3,104],[2,100],[99,5],[98,2]]) labels=['爱情片','爱情片','动作片','动作片'] def classy(inx,dataSet,labels): diffMat=inx-dataSet distanceMat=np.sqrt(np.sum(diffMat**2,axis=1)) sorted_distanceMat=np.argsort(distanceMat) classylabel=labels[sorted_distanceMat[0]] return classylabel label=classy([18,90],dataSet,labels) print("电影类型为:{0:s}".format(label))
可以看到,分类结果根据我们的”经验”,是正确的
接下来我们来挑战更有难度的。
def classify0(inX, dataSet, labels, k): diffMat = inX- dataSet #python的广播机制 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) #python2 使用classCount.iteritems() return sortedClassCount[0][0] #选择k个距离最小的中票数最多的
2.2 海伦约会
2.2.1 k-近邻算法实战之约会网站配对效果判定
上一小结学习了简单的k-近邻算法的实现方法,但是这并不是完整的k-近邻算法流程,k-近邻算法的一般流程:收集数据:可以使用爬虫进行数据的收集,也可以使用第三方提供的免费或收费的数据。一般来讲,数据放在txt文本文件中,按照一定的格式进行存储,便于解析及处理。
准备数据:使用Python解析、预处理数据。
分析数据:可以使用很多方法对数据进行分析,例如使用Matplotlib将数据可视化。
测试算法:计算错误率。
使用算法:错误率在可接受范围内,就可以运行k-近邻算法进行分类。
已经了解了k-近邻算法的一般流程,下面开始进入实战内容。
2.2.2 实战背景
海伦女士一直使用在线约会网站寻找适合自己的约会对象。尽管约会网站会推荐不同的任选,但她并不是喜欢每一个人。经过一番总结,她发现自己交往过的人可以进行如下分类:不喜欢的人
魅力一般的人
极具魅力的人
海伦收集约会数据已经有了一段时间,她把这些数据存放在文本文件datingTestSet.txt中,每个样本数据占据一行,总共有1000行。
数据集下方下载:
https://github.com/ZChengming/datingTestSet
海伦收集的样本数据主要包含以下3种特征:
每年获得的飞行常客里程数
玩视频游戏所消耗时间百分比
每周消费的冰淇淋公升数
打开txt文本文件,数据格式如图2.1所示。
2.2.3 准备数据:从文本文件中解析数据
于是我们要写一个函数来将文本文件里的信息转化为矩阵信息,话不多说动手!!#得到文件行数,创建矩阵,创建标签向量 def file2matrix(filename): f = open(filename) arrayOfLines=f.readlines() numberOfLines = len(arrayOfLines) #get the number of lines in the file returnMat = zeros((numberOfLines,3)) #prepare matrix to return classLabelVector = [] #prepare labels return index = 0 for line in arrayOfLines: listFromLine = line.split('\t') returnMat[index,:] = listFromLine[0:3] classLabelVector.append(int(listFromLine[-1])) index += 1 return returnMat,classLabelVector
我们检查一下数据内容,没有问题。
2.2.4 归一化特征
如果我们不归一化特征那么就会使结果偏向数值较大的特征,显然是不正确的。样本 | 玩游戏所耗时间百分比 | 每年获得的飞行常用里程数 | 每周消费的冰淇淋公升数 | 样本分类 |
---|---|---|---|---|
1 | 0.8 | 400 | 0.5 | 1 |
2 | 12 | 134000 | 0.9 | 3 |
3 | 0 | 20000 | 1.1 | 2 |
4 | 67 | 32000 | 0.1 | 2 |
在处理这种不同取值范围的特征值时,我们通常采用的方法是将数值归一化,如将取值范围处理为0到1或者-1到1之间。下面的公式可以将任意取值范围的特征值转化为0到1区间内的值
归一化特征的公式如下:
newvalue=(oldvalue−minvalue)/(maxvalue−minvalue)newvalue=(oldvalue−minvalue)/(maxvalue−minvalue)
def autoNorm(dataSet): minValues=dataSet.min(axis=0) #按行求最小值 maxValues=dataSet.max(axis=0) #按行求最大值 ranges=maxValues-minValues normDataSet=(dataSet-minValues)/ranges #python的广播机制 return normDataSet,ranges,minValues dataMat,labels=file2matrix("datingTestSet2.txt")
检查一下,没有问题,都在0-1之间。
2.2.5 分类器针对约会网站的测试代码
def datingClassTest(): hoRatio=0.1 #留百分之10作为测试数据 datingDataMat,datingLabels=file2matrix("datingTestSet2.txt") normMat,ranges,minValues=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("预测结果:{0},实际结果:{1}".format(classifierResult,datingLabels[i])) if(classifierResult!=datingLabels[i]): errorCount+=1.0 print("正确率为:{0:f}".format(1.0-errorCount/float(numTestVecs)))
正确率高达百分之95!
2.2.6 最后一步使用算法
def classifyPerson(): resultList=['不感兴趣','有那么一丢丢意思','很感兴趣'] percentTats=float(input("每天多少小时玩游戏?")) #如果是python2请使用raw_input ffMiles=float(input("每年飞多少公里数?")) iceCream=float(input("每年吃多少公升冰激凌?")) datingDataMat,datingLabels=file2matrix('datingTestSet2.txt') normMat,ranges,minValues=autoNorm(datingDataMat) inArr=array([percentTats,ffMiles,iceCream]) classifierResult=classify0(inArr,datingDataMat,datingLabels,3) print("海伦对他:{}".format(resultList[classifierResult-1]))
2.3 手写体识别实战
思考机器学习六步走:
收集数据:下载
准备数据:编写函数classify0()
分析数据:查看是否有缺漏
训练算法:KNN不需要
测试算法:提取部分作为测试样本
使用算法:有兴趣有空可以尝试
2.3.1 准备数据:将图像转化为向量
下载数据
https://github.com/ZChengming/-handwritingdata
目录trainingDigits中包含了大约2000个例子,每个例子如下图所示,每个数字大约有200个样本,目录testDigits中包含大约900个测试数据。我们使用目录trainingDigits中的数据训练分类器,使用目录testDigits中的数据测试分类器效果。
首先我们要将图像格式化处理为一个向量。代码如下:
def img2vector(filename): """ 将图像转为向量 图像32*32转为向量1*1024 输入文件名 输出向量 """ returnMat=zeros((1,1024)) f=open(filename) for i in range(32): line_str=f.readline() for j in range(32): returnMat[0,32*i+j]=int(line_str[i]) return returnMat
有了特征向量后,我们就能够进行预测啦!
类似之前的约会预测,话不多说直接上代码:
正确率高达98.9%
2.4 总结
KNN算法
给一个训练数据集和一个新的实例,在训练数据集中找出与这个新实例最近的k个训练实例,然后统计最近的k个训练实例中所属类别计数最多的那个类,就是新实例的类
三要素:
k值的选择
距离的度量(常见的距离度量有欧式距离,马氏距离等)
分类决策规则 (多数表决规则)
k值的选择
k值越小表明模型越复杂,更加容易过拟合
但是k值越大,模型越简单,如果k=N的时候就表明无论什么点都是训练集中类别最多的那个类
所以一般k会取一个较小的值,然后用过交叉验证来确定
这里所谓的交叉验证就是将样本划分一部分出来为预测样本,比如95%训练,5%预测,然后k分别取1,2,3,4,5之类的,进行预测,计算最后的分类误差,选择误差最小的k
KNN的回归
在找到最近的k个实例之后,可以计算这k个实例的平均值作为预测值。或者还可以给这k个实例添加一个权重再求平均值,这个权重与度量距离成反比(越近权重越大)。
优缺点:
KNN算法的优点:
思想简单,理论成熟,既可以用来做分类也可以用来做回归;
可用于非线性分类;
训练时间复杂度为O(n);
准确度高,对数据没有假设,对outlier不敏感;
缺点:
计算量大;
样本不平衡问题(即有些类别的样本数量很多,而其它样本的数量很少);
需要大量的内存;
有空再补充。。。
相关文章推荐
- 机器学习实战(①)——KNN算法改进约会网站的配对效果和手写字识别系统
- Python3 机器学习实战自我讲解(一)机器学习基础
- 机器学习python实战之手写数字识别
- Python机器学习实战之kNN手写识别系统
- 【机器学习实战-kNN:手写识别】python3实现-书本知识【3】
- 机器学习实战之k-近邻算法(6)---手写数字识别系统(0-9识别)
- [置顶] 【python keras实战】利用VGG卷积神经网络进行手写字体识别
- Tensorflow实战(一)(MNIST手写字体识别TensorFlow实现)
- 机器学习实战之程序清单1-kNN(手写数字识别系统)
- Error Back Propagation in BPNeuralNetwork及实现手写字体识别python版
- 【机器学习实战-kNN:约会网站约友分类】python3实现-书本知识【2】
- 机器学习-神经网络-手写字体识别
- 【机器学习实战-python3】k-近邻算法
- 【机器学习】k-近邻算法应用之手写数字识别
- 机器学习(三):逻辑回归应用_手写数字识别_OneVsAll_Python
- 机器学习(四):BP神经网络_手写数字识别_Python
- 机器学习——k-近邻算法(手写字识别)
- 机器学习-实战-入门-MNIST手写数字识别
- 机器学习实战笔记-K近邻算法3(手写识别系统)
- 机器学习三人行(系列四)----手写数字识别实战(附代码)