模式识别和机器学习实战-K近邻算法(KNN)- Python实现 - 约会网站配对效果判断和手写数字识别
文章目录
- 前言
- 一、 k-近邻算法(KNN)
- 1.算法介绍
- 2.举个例子——电影分类
- 3.步骤描述
- 4.来了——代码实现
- 二、实战之约会网站配对效果判断
- 1.导入数据
- 2.分析数据
- 3.数据归一化
- 4. 测试算法→使用错误率来检测性能
- 5. 构建完整的系统
- 6.总结分析
- 三、实战之手写数字识别
- 1.准备数据
- 2.使用算法识别手写数字
- 3.改进
- 升华主题
前言
K-近邻算法(k-Nearest Neighbor algorithm),又称为KNN算法,是数据挖掘技术中最简单的方法,属于机器学习实践中的入门,这篇文章主要是用于上机操作。
先介绍和解释步骤,分段给出代码;最后再给出源码,只需修改一下文件路径即可运行(和py文件放在同一目录下)
而具体的文件和代码,在如下链接里:机器学习-KNN算法的python实现 - 数据集和源码
推荐使用Jupyter Notebook ,当然用pycharm也可以。
一、 k-近邻算法(KNN)
1.算法介绍
存在一个样本的数据集合,也称作训练样本集,样本集中每个数据存在标签,输入没有标签的新数据以后,将新数据的每个特征与样本集中的数据特征进行比较,找到与新数据的距离最近的k个“邻居”,如果这k个实例多属于某个类别新数据就属于这个类别。
通常在分类任务中用于投票法,而在回归任务中用平均法,有时候还可以根据距离的远近进行加权,距离越近的权重越大。
简单地说:离X最近的k个点决定X为哪一类
与其他机器学习算法的不同之处在于,KNN是一种 “懒惰学习(lazing learing)” 算法,没有显式的训练过程,仅仅在训练阶段把学习样本保存下来,训练的时间开销为 0,直到测试时才对样本进行处理 (原来机器也会摆烂…)
2.举个例子——电影分类
使用KNN算法 分类一个新的电影是爱情片还是动作片(非真实次数)
打斗镜头和接吻镜头就是电影的特征;电影属于爱情片还是动作片就是标签 (还有爱情动作片是吧)
而度量距离是使用 欧氏距离(二范数)
如图为在二维平面的分类结果,把新的电影归于爱情片
3.步骤描述
k-近邻算法的步骤:
(1)计算已知类别数据集中点与当前点的距离
(2)按照距离递增次序排序
(3)选取与当前点距离最小的k个点
(4)选取当前k个点所在类别的出现频率
(5)返回前k个点出现频率最高的类别作为当前的预测类别
4.来了——代码实现
from numpy import *
import operator
#导入数据
def createData():group=array([1.0,1.1],[1.0,1.0],[0.0,0.0],[0.0,0.1])labels=['A','A','B','B']return group,labels
# KNN分类算法
def classif(inx,dataset,labels,k):datasetsize=dataset.shape[0]diffmat=tile(inx,(datasetsize,1))-datasetDiffMat = diffmat**2sqDistances = DiffMat.sum(axis=1)distances=sqDistances**0.5sortedDistIndicies = distances.argsort() classcount={}for i in range(k):vote=labels[sortedDistIndicies[i]]classcount[vote]=classcount.get(vote,0)+1sortedclasscount =sorted(classcount.items(),key=operator.itemgetter(1),reverse=True)return sortedclasscount[0][0],classcount
# 运行代码
group,labels=createData()
a=classif([0,0],group,labels,3)
运行结果
二、实战之约会网站配对效果判断
1.导入数据
收集约会数据,将这些数据存放在文本文件 datingTestSet2.txt 中,总共1000行,包含三种特征:
每年的飞行里程数,玩游戏视频的时间百分比,每周冰淇淋公升数以及三个标签1,2,3分别表示不喜欢,一般喜欢,很喜欢
(很奇怪,找对象和玩游戏时间有关系我理解,但和飞行多少、吃多少冰激凌有半毛钱关系呀?)
但是这些特征数据想要分类,必须将数据的格式转化为可以接受的格式(例如数组),因此需要有个函数来进行转换
#用于导入数据的函数
def file2matrix(filename):fr = open(filename)array0Lines = fr.readlines()numberOfLines = len(array0Lines)returnMat = zeros((numberOfLines, 3))classLabelVector = []index = 0for line in array0Lines:line = line.strip()listFromLine = line.split('\t')returnMat[index,:] = listFromLine[0:3]classLabelVector.append(int(listFromLine[-1]))index += 1return returnMat, classLabelVector, array0Lines#获得数据集
datingDataMat, datingLabels, array0Lines = file2matrix('datingTestSet2.txt')
2.分析数据
可视化最直观,使用matplotlib绘制散点图
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
#参数111的意思是:将画布分割成1行1列,图像画在从左到右从上到下的第1块
ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0*array(datingLabels), 15.0*array(datingLabels))
#datingDataMat是上面返回的数组特征,这里1和2分别对应第二列特征和第三列特征
plt.xlabel('Percentage of Time Spent Playing Video Games')#坐标轴名称
plt.ylabel('Liters of Ice Cream Consumed Per Week')
plt.show()
得到结果,如图为“玩游戏视频的时间百分比”,“每周冰淇淋公升数”的分布,不同颜色代表喜好程度;
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
ax2.scatter(datingDataMat[:,0], datingDataMat[:,1], 15.0*array(datingLabels), 15.0*array(datingLabels))
plt.xlabel('frequent fliters miles per year ')
plt.ylabel('Liters of Ice Cream Consumed Per Week')
plt.show()
得到结果,如图为“每年飞行公里数”,“每周冰淇淋公升数”的分布,不同颜色代表喜好程度;
3.数据归一化
分析图像就会发现,里程数和公斤数这个数据大小相差太多了,那么数据大的将严重影响其它两个特征,那么此时就需要让这三个比值同等重要,此时就需要用到归一化
使用公式:newvalue=(oldvalue-min)/(max-min)
#数据归一化函数,增加一个新的函数autoNorm自动转化到(0,1)区间
def autoNorm(dataSet):minVals = dataSet.min(0)maxVals = dataSet.max(0)ranges = maxVals - minValsnormDataSet = zeros(shape(dataSet))m = dataSet.shape[0]# 行数normDataSet = dataSet - tile(minVals, (m,1))normDataSet = normDataSet/tile(ranges, (m,1)) #element wise dividereturn normDataSet, ranges, minVals
# 得到归一化的样本集
normMat, ranges, minVals = autoNorm(datingDataMat)
得到的数据集normMat如图:
4. 测试算法→使用错误率来检测性能
def datingClassTest():hoRatio = 0.1 #测试集和训练集的比例,测试集和训练集的比例1:9![请添加图片描述](https://img-blog.csdnimg.cn/5effccb1c74248f3b85ab1e852cf7a4b.png)datingDataMat,datingLabels, array0Lines = file2matrix('datingTestSet2.txt') normMat, ranges, minVals = autoNorm(datingDataMat)m = normMat.shape[0] # 行数,也是样本总数 mnumTestVecs = int(m*hoRatio)# 取所有样本中的一部分当成测试集errorCount = 0.0for i in range(numTestVecs):classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)print("the classifier came back with: %s, the real answer is: %s" % (classifierResult, datingLabels[i]))if (classifierResult[0]!= datingLabels[i]): errorCount += 1.0print("the total error rate is: %f" % (errorCount/float(numTestVecs)))print(errorCount)print(numTestVecs)
#运行代码
datingClassTest()
得到的部分结果:
5. 构建完整的系统
此时我们通过输入他人信息来判断海伦对对方的喜欢程度
# 新的样本判断喜欢程度
def classifyPerson():resultList = ['unlike', 'in small doses', 'in large doses']percentTats = float(input("percentage of time spent playing video games>"))ffMiles = float(input("frequent fliters miles per year?"))iceCream = float(input('liters of ice cream consumed per year?'))inArr = array([ffMiles, percentTats, iceCream])classifierResult = classify0((inArr-minVals)/ranges, normMat, datingLabels,3)print(classifierResult)print("you will probably like this person:", resultList[classifierResult[0]-1])
#运行代码
classifyPerson()
测试结果如下:
6.总结分析
- 分类时只设定了k=3,没有讨论其他的k值大小;是否选择其他的k值,会对准确率有所提高?
- 测试集和训练集的划分,只是简单的按比例取前10%的数据作为测试集,剩下的为训练集,可以进一步使用交叉验证等方法。
完整的代码:
# 准备数据
def file2matrix(filename):fr = open(filename)array0Lines = fr.readlines()numberOfLines = len(array0Lines)returnMat = zeros((numberOfLines, 3))classLabelVector = []index = 0for line in array0Lines:line = line.strip()listFromLine = line.split('\t')returnMat[index,:] = listFromLine[0:3]classLabelVector.append(int(listFromLine[-1]))index += 1return returnMat, classLabelVector, array0Lines# KNN分类算法
def classify0(inX, dataSet, labels, k):dataSetSize = dataSet.shape[0] # 查看当前数据集有多少列,返回列数diffMat = tile(inX,(dataSetSize,1)) - dataSet # inX 是待输入数组,(,)使用维度sqDiffMat = diffMat**2 # 计算两点间距离公式用二次方sqDistances = sqDiffMat.sum(axis=1)distances = sqDistances**0.5 # 所有平方和最后根号也就是0.5次方sortedDistIndicies = distances.argsort() # 排序classCount={}for i in range(k): # for循环,前k次voteIlabel = labels[sortedDistIndicies[i]]classCount[voteIlabel] = classCount.get(voteIlabel,0)+1sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)return sortedClassCount[0][0], classCount # 最后返回最高频率元素#数据归一化
def autoNorm(dataSet):minVals = dataSet.min(0)maxVals = dataSet.max(0)ranges = maxVals - minValsnormDataSet = 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.1 datingDataMat,datingLabels, array0Lines = file2matrix('datingTestSet2.txt') normMat, ranges, minVals = autoNorm(datingDataMat)m = normMat.shape[0]numTestVecs = int(m*hoRatio)errorCount = 0.0for i in range(numTestVecs):classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)print("the classifier came back with: %s, the real answer is: %s" % (classifierResult, datingLabels[i]))if (classifierResult[0]!= datingLabels[i]): errorCount += 1.0print("the total error rate is: %f" % (errorCount/float(numTestVecs)))print(errorCount)print(numTestVecs)datingClassTest()# 进行新的预测
def classifyPerson():resultList = ['unlike', 'in small doses', 'in large doses']percentTats = float(input("percentage of time spent playing video games>"))ffMiles = float(input("frequent fliters miles per year?"))iceCream = float(input('liters of ice cream consumed per year?'))inArr = array([ffMiles, percentTats, iceCream])classifierResult = classify0((inArr-minVals)/ranges, normMat, datingLabels,3)print(classifierResult)print("you will probably like this person:", resultList[classifierResult[0]-1])classifyPerson()
三、实战之手写数字识别
1.准备数据
实际图像存储在文件夹trainingDigits和testDigits中,我们使用trainingDigits去训练分类器,使用testDigits去进行测试分类效果。
我们需要将这个32*32的二进制图像转换为1 * 1024的向量,那么就需要一个函数去进行转化
#把图片变成向量
def img2vector(filename):returnVect = zeros((1,1024)) fr = open(filename)#读取文件的32行32列,将其放在returnVector向量中for i in range(32): lineStr = fr.readline()for j in range(32):returnVect[0,32*i+j] = int(lineStr[j]) return returnVecttestVector = img2vector('testDigits/0_13.txt')
2.使用算法识别手写数字
如图为trainingDigits中的文件名称,开头第一个数字就为图片的标签
手写数字识别代码如下,导入训练集和测试集,并输出错误率
from os import listdir
def handwritingClassTest(): hwLabels = []trainingFileList = listdir('trainingDigits') # listdir列出给定目录的文件名m = len(trainingFileList) # m 是文件个数 trainingMat = zeros((m,1024)) #创建m行1024列的训练集汇总矩阵,zeros代表矩阵的元素都是0 for i in range(m): fileNameStr = trainingFileList[i] # 矩阵的每一行是一个图像的,对行进行操作,先把每行的文件名给到fileNameStr fileStr = fileNameStr.split('.')[0] classNumStr = int(fileStr.split('_')[0]) # 把.和_去掉hwLabels.append(classNumStr) # append作用是将()内内容加到hwLabels数组中,也就是把标签加入trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr) #使用转换函数转换为1*1024,如此循环i行,将训练集trainingMat填满#下面是测试集,导入文件时也同样的操作testFileList = listdir('testDigits') errorCount = 0.0mTest = len(testFileList) for i in range(mTest):fileNameStr = testFileList[i]fileStr = fileNameStr.split('.')[0] classNumStr = int(fileStr.split('_')[0])vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)# 使用之间的classify0分类算法,对测试集进行测试,和真实结果对比,可以算出错误率classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3) print("the classifier came back with: %d, the real answer is: %d" % (classifierResult[0], classNumStr))if (classifierResult[0] != classNumStr): errorCount += 1.0print("\nthe total number of errors is: %d" % errorCount)print("\nthe total error rate is: %f" % (errorCount/float(mTest)))
#运行识别数字程序
handwritingClassTest()
得到的运行结果如下:(k=3)
3.改进
- 在不同的k值下的识别错误率比较
k=2时
k=4时
k=5时
考虑加上不同k下的错误率统计图,完整的代码如下:
from os import listdir
#把图片变成向量
def img2vector(filename):returnVect = zeros((1,1024)) fr = open(filename)#读取文件的32行32列,将其放在returnVector向量中for i in range(32): lineStr = fr.readline()for j in range(32):returnVect[0,32*i+j] = int(lineStr[j]) return returnVect
#识别数字,输入正整数k
def handwritingClassTest(k): hwLabels = []trainingFileList = listdir('trainingDigits')m = len(trainingFileList) trainingMat = zeros((m,1024)) for i in range(m): fileNameStr = trainingFileList[i] fileStr = fileNameStr.split('.')[0] classNumStr = int(fileStr.split('_')[0])hwLabels.append(classNumStr) trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr) testFileList = listdir('testDigits') errorCount = 0.0mTest = len(testFileList) for i in range(mTest):fileNameStr = testFileList[i]fileStr = fileNameStr.split('.')[0] classNumStr = int(fileStr.split('_')[0])vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, k) '''print("the classifier came back with: %d, the real answer is: %d" % (classifierResult[0], classNumStr))'''if (classifierResult[0] != classNumStr): errorCount += 1.0print("\n K=%d ,the total number of errors is: %d" % (k,errorCount))print("\n K=%d ,the total error rate is: %f" % (k,(errorCount/float(mTest)))) return errorCount/float(mTest)#绘制不同k下的错误率统计图
y = []
for i in range(1, 10):y.append(handwritingClassTest(i))
fig = plt.figure()
ax = fig.add_subplot(111)
x = [i for i in range(1, 10)]
plt.bar(x, y, align='center')
plt.xlabel('the value of K', )
plt.ylabel('Error rate')
plt.title('K graph')
plt.show()
结果大致如图所示:
- 还可以增加因距离远近的加权比重,这里感兴趣的小伙伴可以自己尝试一下哦
升华主题
KNN算法并不算难,属于机器学习入门基础,现在我们在学习了这个算法后再次想一想,其核心思想能用于解决其他什么问题呢?
- 著名商业哲学家、成功学创始人吉米·罗恩说过:“把你最常接触的五个人平均起来,就是你自己,而这也可以预测你的未来会如何。”
古语有云:物以类聚,人以群分。燕雀不可能与鸿鹄为伍,想要站在群山之巅的人,亦不会与甘于平庸之辈相处。
我们耳熟能详的孟母三迁故事就是体现了周围人对你成长的影响,人在交友的过程中不断学习,潜移默化地受到对方的影响,这种影响也会伴随着人的一生,正所谓:“近朱者赤,近墨者黑。”
用机器学习的话说,距离你最近的K个“邻居”,决定了你是什么样的人,距离你最“近”的那些朋友,能看出你最真实的生活状况。
- 人有不同的气质,你是什么样的气质,就会吸引什么样的人。你若优秀,自然会吸引优秀的人,从一个人朋友的身上,往往也能找到这个人的影子。
你在受到周围人的影响同时,也会影响其他人;类似“环境影响生物,生物改造环境”、“实践决定认知,而认知对实践有反作用”,都是说明作用是相互的。
围棋盘上的每一颗棋子无论身处何处都会影响整盘棋的胜负,只不过随着距离的增大,影响力会快速衰减,但永远不会为零。
本身处于周围人影响的同时,我们也可以通过改变自身而影响他人。舍友喊你打游戏时,叫上他一起自习;朋友约你去网吧,劝他来图书馆。
- 眼界的高低,决定你格局的大小。
当你把K取成1时,你的眼睛只看到手上的事物就停下了,心甘情愿接受周围的同化;你把脚步局限在屋子里,舒舒服服地躺在沙发上摆烂;你只关心当下,得过且过是一天,一言不合就摆烂…
但是如果你尝试把K取成100呢?你可以通过网络了解到时代当今热点,国家出台新政策,政府发布新规范,行业迎来新机遇,就业有了新方向…看似距离我们很远的事物其实都和我们生活息息相关;
十鸟在林,不如一鸟在手,眼界高不仅看到当下,更要看到未来;格局大不计较眼前的小小得失,而是关注整盘棋的胜负。
模式识别和机器学习实战-K近邻算法(KNN)- Python实现 - 约会网站配对效果判断和手写数字识别相关推荐
- 机器学习:K-近邻算法(二)约会网站配对效果
目录 K-近邻算法实战(二):约会网站配对效果判断 实战 1.背景介绍 2.准备数据:数据分类 3.分析数据:数据可视化 4.准备数据:数据归一化 5.测试算法:验证分类器 6.使用算法:构建完整可用 ...
- 用MXnet实战深度学习之一:安装GPU版mxnet并跑一个MNIST手写数字识别 (zz)
用MXnet实战深度学习之一:安装GPU版mxnet并跑一个MNIST手写数字识别 我想写一系列深度学习的简单实战教程,用mxnet做实现平台的实例代码简单讲解深度学习常用的一些技术方向和实战样例.这 ...
- TensorFlow实战笔记之(4):卷积神经网络(CNN) 实现手写数字识别
一.引言 前一篇博文使用单隐层的全连接神经网络,并结合一些神经网络的优化策略,如指数衰减学习率.正则化.Relu激活函数和Adam优化算法等,用包含100个隐层神经元的神经网络实现了MNIST数据集上 ...
- 机器学习笔记——从手写数字识别开始
文章目录 前言 关于这篇博客(预计八月下旬全部完成) 关于项目实现 监督学习 ANN全连接神经网络的实现 1.总述 2.初始化 3.传播及损失 4.反向传播 决策树以及随机森林的实现 1.总述 2.单 ...
- 【机器学习/人工智能】 大作业:手写数字识别系统
写在前面 参考的是https://zh.d2l.ai/index.html 一.大作业设计目的与要求 (1)利用所学习的聚类算法完成简单的图像分割系统. (2)编程并利用相关软件完成大作业测试,得到实 ...
- 2 机器学习 K近邻算法(KNN) 学习曲线 交叉验证 手写数字识别
机器学习 1 K-近邻算法介绍 1.1 分类问题 分类问题:根据已知样本的某些特征,判断一个未知样本属于哪种样本类别. 与回归问题相比,分类问题的输出结果是离散值,用于指定输入的样本数据属于哪个类别. ...
- k近邻算法_【机器学习】K近邻算法(KNN)
点击关注上方"小田学python",获取更多精彩内容 机器学习是一门多领域交叉学科,涉及概率论.统计学.逼近论.凸分析.算法复杂度理论等多门学科.专门研究计算机怎样模拟或实现人类的 ...
- 一文搞懂K近邻算法(KNN),附带多个实现案例
简介:本文作者为 CSDN 博客作者董安勇,江苏泰州人,现就读于昆明理工大学电子与通信工程专业硕士,目前主要学习机器学习,深度学习以及大数据,主要使用python.Java编程语言.平时喜欢看书,打篮 ...
- 01 K近邻算法 KNN
01 K近邻算法 KNN k近邻算法基础 等价于 scikit-learn中的机器学习算法封装 训练数据集,测试数据集 分类准确度 超参数 考虑距离权重 更多关于距离的定义 搜索明可夫斯基距离相应的p ...
最新文章
- 快速了解上市公司年报
- 视图、存储函数、存储过程、触发器:MySQL系列之五
- Python报表自动化
- Mysql语句与应用
- 不创建 sequence 自增字段
- shell脚本 linux
- python工资高还是java-Python和Java哪个工资高
- 新版FMEA软件参数图(P图)简介(FMEAHunter)
- hadoop权威指南 读书笔记
- fcntl函数的SET用法
- linux键盘映射默认,Linux 中的键盘映射【转】
- 【分享】小米MIUI免root一键删除系统内置软件
- [Android]朝花夕拾之使用DexClassLoader动态加载广点通jar包
- 拿什么拯救你——王阿姨的少女心!
- 程序员越来越多,大数据行业工资也越来越高
- 6-1 Point类的运算 (10 分)
- matlab互相关检测器,自相关函数和互相关函数的利用MATLAB计算和作图
- Tomcat原理和源码分析
- 基于C6748+FPGA的高精度北斗接收机设计与实现
- 【linux下CA证书过期怎么处理】
热门文章
- 企业怎么运营公众号,怎么策划微信集赞活动?
- 3D啤酒饮料冷冻柜模型
- 找工作的小技巧(雕虫小技),刚参加工作的小伙伴可以看看
- 服务器专用隐藏式显示器,惠普DreamColor Z27x G2 Studio显示器评测:自带隐藏色度计 专为设计师打造的专业显示器...
- 紫光国芯整合大戏 为吃进长江存储或再推增发
- python抓取文献关键信息,python爬虫——使用selenium爬取知网文献相关信息
- 如何监视从电脑发出的http或https
- 抖音快手热门特效视频用手机软件怎么制作?
- UG NX1953软件下载 NX1953安装说明视频教程
- table的td宽度控制