机器学习实战——KNN
一、简介
参考:https://blog.csdn.net/c406495762/article/details/75172850
环境:win 10, notebook,python 3.6
原blog较长,主要实现其算法,尽可能的简洁些,并对一些细节给出实例,
如果熟练,细节处的函数尽可能的可以忽略,写出来主要是未来加强印象。
三、四、五、三个实例,前两个同一种方法,分类函数是同一个,只是数据不一样,最后一个使用SKLerrn实现KNN,十分方便。
二、算法简介
1、原理:
输入没有标签的新数据后,将新的数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
2、距离度量
欧式距离
3、步骤:
计算已知类别数据集中的点与当前点之间的距离;
按照距离递增次序排序;
选取与当前点距离最小的k个点;
确定前k个点所在类别的出现频率;
返回前k个点所出现频率最高的类别作为当前点的预测分类。
k-近邻算法的一般流程:
收集数据:可以使用爬虫进行数据的收集,也可以使用第三方提供的免费或收费的数据。一般来讲,数据放在txt文本文件中,按照一定的格式进行存储,便于解析及处理。
准备数据:使用Python解析、预处理数据。
分析数据:可以使用很多方法对数据进行分析,例如使用Matplotlib将数据可视化。
测试算法:计算错误率。
使用算法:错误率在可接受范围内,就可以运行k-近邻算法进行分类。
优缺点:
优点
简单好用,容易理解,精度高,理论成熟,既可以用来做分类也可以用来做回归;
可用于数值型数据和离散型数据;
训练时间复杂度为O(n);无数据输入假定;
对异常值不敏感。
缺点:
计算复杂性高;空间复杂性高;
样本不平衡问题(即有些类别的样本数量很多,而其它样本的数量很少);
一般数值很大的时候不用这个,计算量太大。但是单个样本又不能太少,否则容易发生误分。
最大的缺点是无法给出数据的内在含义。
三、KNN简单实例
训练集是一个矩阵,测试集也是一个矩阵,要预测测试集中每一个数据的类别
算法步骤:
1、将测试集中的每一个数据扩展成和训练集一样大小的矩阵,用于该数据与训练集的每一个数据进行距离计算
2、扩展矩阵与训练集对应元素相减,
3、相减后的每一个元素进行平方,
4、每一行的元素相加
5、开根号,
6、找出k个最小的的值,这k个中,类别最多的那个即是预测类型
如图:
代码如下:
def classify(inX,dataSet,labels,k):# 返回行数dataSetSize = dataSet.shape[0]# 扩展维度,相减diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet# 平方sqDiffMat = diffMat**2# 求和sqDistances = sqDiffMat.sum(axis=1)# 开根号distances = sqDistances**0.5#返回distances中元素从小到大排序后的索引值sortedDistIndices = distances.argsort()classCount = {}for i in range(k):voteIlabel = labels[sortedDistIndices[i]]classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1# 对字典按值排序,返回的是一个列表,列表元素是元组sortedClassCount = sorted(classCount.items(),key=lambda item:item[1],reverse=True)return sortedClassCount[0][0]
完整代码:
import numpy as npgroup = np.array([[1,101],[5,89],[108,5],[115,8]])
labels = ['爱情片','爱情片','动作片','动作片']def classify(inX,dataSet,labels,k):# 返回行数dataSetSize = dataSet.shape[0]# 扩展维度,相减diffMat = np.tile(inX, (dataSetSize, 1)) - dataSetsqDiffMat = diffMat**2sqDistances = sqDiffMat.sum(axis=1)distances = sqDistances**0.5#返回distances中元素从小到大排序后的索引值sortedDistIndices = distances.argsort()classCount = {}for i in range(k):voteIlabel = labels[sortedDistIndices[i]]classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1# 对字典按值排序,返回的是一个列表,列表元素是元组sortedClassCount = sorted(classCount.items(),key=lambda item:item[1],reverse=True)return sortedClassCount[0][0]test = [101,20]
test_class = classify(test, group, labels, 3)
print(test_class)
预测结果:
动作片
注:源代码使用了operator模块对字典进行排序
python补充:
四个函数,tile(), np.sum(), np.argsort(), sorted(),
(1)np.tile()
import numpy as npa = [2,3]
b = np.tile(a,(4,3))
print(b)
[[2 3 2 3 2 3][2 3 2 3 2 3][2 3 2 3 2 3][2 3 2 3 2 3]]
(2)np.argsort():
返回从小到大排序后的索引值
import numpy as npa = np.array([1,2,3,4])
b = np.array([4,3,2,1])
print(a.argsort())
print(b.argsort())
[0 1 2 3]
[3 2 1 0]
(3)np.sum():
0:返回列相加
1:返回行相加
import numpy as npa = np.array([[1,2,3],[4,5,6],[7,8,9],[10,11,12]])
print(a)
print('---------axis=0-----------')
b = a.sum(axis=0)
print(b)
print('---------axis=1-----------')
c = a.sum(axis=1)
print(c)
[[ 1 2 3][ 4 5 6][ 7 8 9][10 11 12]]
---------axis=0-----------
[22 26 30]
---------axis=1-----------
[ 6 15 24 33]
(4)sorted():
第一个参数:可迭代对象
第二个参数,排序规则
第三个参数,是否降序,True为降序,False为升序,
返回值是一个列表,
d = {'mom':23,'linme':34,'ioio':89,'falali':232}
a = sorted(d.items(),key=lambda item:item[1],reverse=True)
print(a)
c = sorted(d.items(),key=lambda item:item[1],reverse=False)
print(c)
[('falali', 232), ('ioio', 89), ('linme', 34), ('mom', 23)]
[('mom', 23), ('linme', 34), ('ioio', 89), ('falali', 232)]
(5)数据处理过程:
import numpy as npgroup = np.array([[1,2],[6,4],[80,81],[78,83]])
print('----------group------------')
print('group: ')
print(group)test = [3,4]
mat = np.tile(test,(4,1))
print('----------mat------------')
print('mat: ')
print(mat)mat_g = mat - group
print('----------mat_g------------')
print('mat_g: ')
print(mat_g)mat_2 = mat_g**2
print('----------mat_2------------')
print('mat_2: ')
print(mat_2)mat_sum = mat_2.sum(axis=1)
print('----------mat_sum------------')
print('mat_sum: ')
print(mat_sum)
----------group------------
group:
[[ 1 2][ 6 4][80 81][78 83]]
----------mat------------
mat:
[[3 4][3 4][3 4][3 4]]
----------mat_g------------
mat_g:
[[ 2 2][ -3 0][-77 -77][-75 -79]]
----------mat_2------------
mat_2:
[[ 4 4][ 9 0][5929 5929][5625 6241]]
----------mat_sum------------
mat_sum:
[ 8 9 11858 11866]
四、海伦数据
文件总共四列,最后一列是标签,海伦收集的样本数据主要包含以下3种特征:
每年获得的飞行常客里程数
玩视频游戏所消耗时间百分比
每周消费的冰淇淋公升数
分析数据:数据可视化,数据归一化
数据读取,获取特征矩阵和标签,
在windows上使用open打开utf-8编码的txt文件时开头会有一个多余的字符\ufeff,它叫BOM,是用来声明编码等信息的,但python会把它当作文本解析。对UTF-16, Python将BOM解码为空字串。然而对UTF-8, BOM被解码为一个字符\ufeff。
步骤:
打开文件, 去除BOM, 获取行数, 对于每一行:
去除每行前后空白符, 按tab切分 前三列保存到特征矩阵中, 最后一保存到标签中,
def file2matrix(filename):fr = open(filename,'r',encoding = 'utf-8')arrayOLines = fr.readlines()#针对有BOM的UTF-8文本,应该去掉BOM,否则后面会引发错误。arrayOLines[0]=arrayOLines[0].lstrip('\ufeff')numberOfLines = len(arrayOLines)returnMat = np.zeros((numberOfLines,3))classLabelVector = []index = 0for line in arrayOLines:line = line.strip()listFromLine = line.split('\t')#将数据前三列提取出来,存放到returnMat的NumPy矩阵中,也就是特征矩阵returnMat[index,:] = listFromLine[0:3]if listFromLine[-1] == 'didntLike':classLabelVector.append(1)elif listFromLine[-1] == 'smallDoses':classLabelVector.append(2)elif listFromLine[-1] == 'largeDoses':classLabelVector.append(3)index += 1return returnMat, classLabelVector
归一化步骤:
1、找出每一列最大、小值,返回值是一维列表,每个元素代表该列最大、小值
2、最大值列表减去最小值列表得出差列表
3、将最小值列表扩展为数据集大小,
4、将差值列表扩展为数据集大小,
5、原始数据减去最小值扩展,然后除以差值扩展
def autoNorm(dataSet):minVals = dataSet.min(0)maxVals = dataSet.max(0)ranges = maxVals - minValsnormDataSet = np.zeros(np.shape(dataSet))m = dataSet.shape[0]# 原始值减去最小值normDataSet = dataSet - np.tile(minVals, (m, 1))normDataSet = normDataSet / np.tile(ranges, (m, 1))return normDataSet, ranges, minVals
则全部代码:
import numpy as npdef classify(inX,dataSet,labels,k):# 返回行数dataSetSize = dataSet.shape[0]# 扩展维度,相减diffMat = np.tile(inX, (dataSetSize, 1)) - dataSetsqDiffMat = diffMat**2sqDistances = sqDiffMat.sum(axis=1)distances = sqDistances**0.5#返回distances中元素从小到大排序后的索引值sortedDistIndices = distances.argsort()classCount = {}for i in range(k):voteIlabel = labels[sortedDistIndices[i]]classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1# 对字典按值排序,返回的是一个列表,列表元素是元组sortedClassCount = sorted(classCount.items(),key=lambda item:item[1],reverse=True)return sortedClassCount[0][0]def file2matrix(filename):fr = open(filename,'r',encoding = 'utf-8')arrayOLines = fr.readlines()#针对有BOM的UTF-8文本,应该去掉BOM,否则后面会引发错误。arrayOLines[0]=arrayOLines[0].lstrip('\ufeff')numberOfLines = len(arrayOLines)returnMat = np.zeros((numberOfLines,3))classLabelVector = []index = 0for line in arrayOLines:line = line.strip()listFromLine = line.split('\t')#将数据前三列提取出来,存放到returnMat的NumPy矩阵中,也就是特征矩阵returnMat[index,:] = listFromLine[0:3]if listFromLine[-1] == 'didntLike':classLabelVector.append(1)elif listFromLine[-1] == 'smallDoses':classLabelVector.append(2)elif listFromLine[-1] == 'largeDoses':classLabelVector.append(3)index += 1return returnMat, classLabelVectordef autoNorm(dataSet):minVals = dataSet.min(0)maxVals = dataSet.max(0)ranges = maxVals - minValsnormDataSet = np.zeros(np.shape(dataSet))m = dataSet.shape[0]# 原始值减去最小值normDataSet = dataSet - np.tile(minVals, (m, 1))normDataSet = normDataSet / np.tile(ranges, (m, 1))return normDataSet, ranges, minValsdef main():filename = "datingTestSet.txt"datingDataMat, datingLabels = file2matrix(filename)normMat, ranges, minVals = autoNorm(datingDataMat)# 行数m = normMat.shape[0]# 测试比率hoRatio = 0.10numTestVecs = int(m * hoRatio)#分类错误计数errorCount = 0.0for i in range(numTestVecs):classifierResult = classify(normMat[i,:], normMat[numTestVecs:m,:], datingLabels[numTestVecs:m], 4)print("分类结果:%s\t真实类别:%d" % (classifierResult, datingLabels[i]))if classifierResult != datingLabels[i]:print('分类: ',classifierResult)print('真实: ',datingLabels[i])errorCount += 1.0print("错误率:%f%%" %(errorCount/float(numTestVecs)*100))main()
结果(只输出最后几行):
分类结果:2 真实类别:3
分类: 2
真实: 3
分类结果:1 真实类别:1
分类结果:2 真实类别:2
分类结果:1 真实类别:1
分类结果:3 真实类别:3
分类结果:3 真实类别:3
分类结果:2 真实类别:2
分类结果:2 真实类别:1
分类: 2
真实: 1
分类结果:1 真实类别:1
错误率:4.000000%
python函数:min(),max(), 列表切分
(1)min(),max()
0:列最值
1:行最值
空:全局最值
import numpy as np
a = np.array([[1,2,3,10,4,5],[2,3,4,3,5,6],[3,4,5,4,6,7]])
print(a)print('-------全局最大小------')
print(a.min())
print(a.max())print('------列最大小-------')
print(a.min(0))
print(a.max(0))print('------行最大小-------')
print(a.min(1))
print(a.max(1))
[[ 1 2 3 10 4 5][ 2 3 4 3 5 6][ 3 4 5 4 6 7]]
-------全局最大小------
1
10
------列最大小-------
[1 2 3 3 4 5]
[ 3 4 5 10 6 7]
------行最大小-------
[1 2 3]
[10 6 7]
(2)列表切分:
import numpy as np
a = np.array([[1,2,3,4,5],[2,3,4,5,6],[3,4,5,6,7]])
print(a)
print('----------------')
print('a[2,:]: ')
print(a[2,:])
print('----------------')
print('a[0:2,:]: ')
print(a[0:2,:])
print('----------------')
print('a[0:2]: ')
print(a[0:2])
[[1 2 3 4 5][2 3 4 5 6][3 4 5 6 7]]
----------------
a[2,:]:
[3 4 5 6 7]
----------------
a[0:2,:]:
[[1 2 3 4 5][2 3 4 5 6]]
----------------
a[0:2]:
[[1 2 3 4 5][2 3 4 5 6]]
五、使用SKLearn中的KNN对手写字体进行处理
步骤:
1、获取训练集特征矩阵,标签
2、使用训练集特征矩阵、标签初始化KNN实例
3、获取测试集特征矩阵,标签 4、预测测试集,记录正确率
其实即代码:
实例KNN: neigh = kNN(n_neighbors = 3, algorithm = 'auto') neigh.fit(trainingMat, hwLabels)
预测: classifierResult = neigh.predict(vectorUnderTest)
首先将32*32的数据展开成1*1024,然后实例KNN,预测,代码如下:
import numpy as np
from os import listdir
from sklearn.neighbors import KNeighborsClassifier as kNN# 将32*32展开成1*1024
def img2vector(filename):returnVect = np.zeros((1, 1024))fr = open(filename)for i in range(32):lineStr = fr.readline()#每一行的前32个元素依次添加到returnVect中for j in range(32):returnVect[0, 32*i+j] = int(lineStr[j])return returnVectdef handwritingClassTest():hwLabels = []# 训练集列表trainingFileList = listdir('trainingDigits')m = len(trainingFileList)trainingMat = np.zeros((m, 1024))# 获取训练集特征矩阵及其标签for i in range(m):# 训练集文件名fileNameStr = trainingFileList[i]# 数字classNumber = int(fileNameStr.split('_')[0])# 训练集标签列表hwLabels.append(classNumber)# 训练集特征矩阵,即 M*1024trainingMat[i,:] = img2vector('trainingDigits/%s' % (fileNameStr))# 构建分类器neigh = kNN(n_neighbors = 3, algorithm = 'auto')neigh.fit(trainingMat, hwLabels)# 测试集文件名列表testFileList = listdir('testDigits')errorCount = 0.0# 测试集数量mTest = len(testFileList)for i in range(mTest):# 文件名fileNameStr = testFileList[i]# 类别classNumber = int(fileNameStr.split('_')[0])# 特征矩阵vectorUnderTest = img2vector('testDigits/%s' % (fileNameStr))# 预测结果classifierResult = neigh.predict(vectorUnderTest)print("分类返回结果为%d\t真实结果为%d" % (classifierResult, classNumber))if(classifierResult != classNumber):errorCount += 1.0print("总共错了%d个数据\n错误率为%f%%" % (errorCount, errorCount/mTest * 100))handwritingClassTest()
结果(最后几行输出):
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
分类返回结果为9 真实结果为9
总共错了12个数据
错误率为1.268499%
我们发现,使用SKLearn确实比自己手写要方便的多。
机器学习实战——KNN相关推荐
- 机器学习实战-KNN算法-20
机器学习实战-KNN算法-鸢尾花分类 # 导入算法包以及数据集 from sklearn import neighbors from sklearn import datasets from skle ...
- 机器学习实战——KNN及部分函数注解
书籍:<机器学习实战>中文版 IDE:PyCharm Edu 4.02 环境:Adaconda3 python3.6 本系列主要是代码学习记录,其中设计的理论知识,不做过多解释.书中代码 ...
- 机器学习实战——KNN算法预测电影类型
预测电影类型 现有爱情片和动作片(不是爱情动作片,雾)的打斗场面和接吻场面的次数统计,然后给出一个电影打斗场面和接吻场面出现的次数,预测其类型. 那么如何预测呢?当然用KNN了. KNN算法的原理就是 ...
- knn的python代码_《机器学习实战》之一:knn(python代码)
数据 标称型和数值型 算法 归一化处理:防止数值较大的特征对距离产生较大影响 计算欧式距离:测试样本与训练集 排序:选取前k个距离,统计频数(出现次数)最多的类别 def classify0(inX, ...
- 机器学习实战笔记(Python实现)-02-k近邻算法(kNN)
k近邻算法(kNN) 本博客来源于CSDN:http://blog.csdn.net/niuwei22007/article/details/49703719 本博客源代码下载地址:CSDN免费下载. ...
- 《机器学习实战》chapter02 K-近邻算法(KNN)
2.2 示例:使用K-近邻算法改进约会网站的配结果 收集数据:提供文本文件 准备数据:使用Python解析文本文件(文本转numpy矩阵.归一化数据等) 分析数据:使用Matplotlib画二维扩散图 ...
- 算法代码[置顶] 机器学习实战之KNN算法详解
改章节笔者在深圳喝咖啡的时候突然想到的...之前就有想写几篇关于算法代码的文章,所以回家到以后就奋笔疾书的写出来发表了 前一段时间介绍了Kmeans聚类,而KNN这个算法刚好是聚类以后经常使用 ...
- 基于kNN的手写字体识别——《机器学习实战》笔记
看完一节<机器学习实战>,算是踏入ML的大门了吧!这里就详细讲一下一个demo:使用kNN算法实现手写字体的简单识别 kNN 先简单介绍一下kNN,就是所谓的K-近邻算法: [作用原理]: ...
- 机器学习实战(一)k-近邻kNN(k-Nearest Neighbor)
目录 0. 前言 1. k-近邻算法kNN(k-Nearest Neighbor) 2. 实战案例 2.1. 简单案例 2.2. 约会网站案例 2.3. 手写识别案例 学习完机器学习实战的k-近邻算法 ...
最新文章
- python3 subprocess.Popen 报错 No such file or directory
- rknn 学习资料整理
- Leetcode 208. 实现 Trie (前缀树) 解题思路及C++实现
- 困扰程序员的30种软件开发问题,你是否时曾相识?
- java mysql 语句解析器_几种基于Java的SQL解析工具的比较与调用
- 为什么中国人穷得只剩房子
- Netty工作笔记0039---Netty模型--详细版
- httpclient 下载大文件
- 系统同步网络时间服务器不可用,电脑时间同步出错 RPC服务器不可用解决方案...
- Azure通过Vnet Peering和用户自定义路由(UDR)实现hub-spoken连接
- 既要面子,也要里子,车企成不了自动驾驶的“独行侠”
- java博客论坛设计报告,javaweb课程设计报告-个人博客网站的实现(Java).doc
- 著名的菲尔人格测试,看看你适合做什么类型的工作
- 【高效沟通技巧】与人交流要求我们巧妙地听和说
- ros2中navigation2的BT常用语法总结1
- 十部门发促消费“24条”:提高相对低收入群体待遇
- U盘安装centos遇到bootmgr is missing
- Java项目:SSH羽毛球馆管理系统
- 什么是DQL?其含义及其常用命令解析
- CK-GL16-AB传感器|读卡器在工业自动化AGV小车磁导航RFID定位领域应用与解决方案