这里写目录标题
1.K近邻算法概述
1.1概述
简单的说,k-近邻算法采用测量不同特征值之间的距离方法进行分类。
优点:精度高,对异常值不敏感,无数据输入假定。
缺点:计算复杂度高,空间复杂度高。
使用数据范围:数值型和标称型。
原理:存在一个样本数据集,也称为训练样本集,并且样本数据集中都存在标签,即我们知道样本数据集中每一个数据所属的分类的对应关系。输入没有标签的数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本数据集中特征最为相似数据(最近邻)的分类标签。一般,选择k个最为相似数据中出现次数最多的分类,作为新数据的分类。那么相似是如何定义的?这里采用距离来度量相似度。
1.2准备:使用python导入数据
首先创建KNN.py,
'''
K近邻算法实现
参数
inX:待分类的新数据向量
dataSet:样本数据集
labels:样本集的标签
K:取前K个最为相似的结果,即距离最近
'''
def classify0(inX,dataSet,labels,K):
#计算距离
dataSetSize=dataSet.shape[0]#获取数据集的大小
diffMat=tile(inX,(dataSetSize,1))-dataSet#计算待分类向量与样本集数据各个特征值之间的差
sqDiffMat=diffMat**2
sqDistances=sqDiffMat.sum(axis=1)#将各个特征值的差相加
distances=sqDistances**0.5#开方处理,结果是待分类数据与样本数据之间的距离
sortedDistIndicies=distances.argsort()#对距离进行从小到大排序,返回值是排序后的数在原列表中的下标位置
classcount={}#定义一个字典
#选择距离最小的K个点
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)
# python3中用items()替换python2中的iteritems()
# key=operator.itemgetter(1)根据字典的值进行排序
# key=operator.itemgetter(0)根据字典的键进行排序
# reverse降序排序字典
return sortedClasscount[0][0]
函数用法解释:
1.tile()函数:就是重复的意思,
eg:a=[0,1,2]
b=tile(a,2)
print(b) 结果是:array([0,1,2],[0,1,2])
我们也可以不输入数字,而改用元组,用元组来表示格式.
下面我们的元组是(1,2) ,也就是1行2次
b=tile(a,(1,2))
结果是:array([0,1,2],[0,1,2])
我们也可以把元组改为(2,1),也就是2行1列
b=tile(a,(2,1))
结果是:array([0,1,2]
[0,1,2])
2.argsort()函数: x=np.array([1,4,3,-1,6,9]),y=x.argsort()
y=[3 0 2 1 4 5];即该函数是将x中的元素从小到大排列,提取其对应的index(索引),然后赋值给y;
距离计算公式:
1.若数据的特征是二维的,则数据间的距离度量可以用两点间的距离公式进行计算
2.当数据上升为高维时,则可采用欧式距离、曼哈顿距离,相关度等进行度量
2.K近邻算法实战-约会网站匹配改进
2.1准备数据:从文本文件中解析文件数据
样本数据有3种特征和确定和类别标签
1.每年飞行的里程数
2.玩视频游戏所耗用的百分比
3.每周消费冰淇淋的公斤数
在KNN.py中创建名为fileread_matrix()的函数:用来处理文件数据,返回的是训练样本矩阵和类标签向量。
'''
处理txt文件函数
参数:文件名
返回训练样本矩阵和类标签向量
'''
def fileread_matrix(filename):
fr=open(filename)
arrayOLines=fr.readlines()#按行读取全部文件数据
numberLines=len(arrayOLines)#统计行数
returnMat=zeros((numberLines,3))#创建一个矩阵
classLabels=[]#类别标签向量
index=0
for line in arrayOLines:
line=line.strip() #去除空格
listFormLine=line.split('\t')#每行按'\t'分割字符串
returnMat[index,:]=listFormLine[0:3]
classLabels.append(int(listFormLine[-1]))#将每行的最后一个数据加入到类别标签向量
index+=1
return returnMat,classLabels
2.2分析数据:使用Matplotlib创建散点图
'''
展示数据函数
参数:数据文件名
'''
def show_data(filename):
# 设置汉字格式
font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14)
datingDataMat,label=fileread_matrix(filename)
# 将fig画布分隔成1行1列,不共享x轴和y轴,fig画布的大小为(13,8)
# 当nrow=2,nclos=2时,代表fig画布被分为四个区域,axs[0][0]表示第一行第一个区域
fig,axs=plt.subplots(nrows=2,ncols=2,sharex=False,sharey=False,figsize=(13,8))
print(fig)
numberofLabel=len(label)
LabelsColors=[]
for i in label:
if i==1:
LabelsColors.append('black')
if i==2:
LabelsColors.append('orange')
if i==3:
LabelsColors.append('red')
#画出散点图,数据集矩阵第一列(飞行里数),第二列(玩游戏)数据画散点图,散点大小为15,透明度为0.5
axs[0][0].scatter(x=datingDataMat[:,0],y=datingDataMat[:,1],color=LabelsColors,s=15,alpha=.5)
#设置标题,x轴,y轴
axs0_title_text = axs[0][0].set_title(u'每年获得的飞行常客里程数与玩视频游戏所消耗时间占比', FontProperties=font)
axs0_xlabel_text = axs[0][0].set_xlabel(u'每年获得的飞行常客里程数', FontProperties=font)
axs0_ylabel_text = axs[0][0].set_ylabel(u'玩视频游戏所消耗时间占', FontProperties=font)
plt.setp(axs0_title_text, size=9, weight='bold', color='red')
plt.setp(axs0_xlabel_text, size=7, weight='bold', color='black')
plt.setp(axs0_ylabel_text, size=7, weight='bold', color='black')
# 画出散点图,以datingDataMat矩阵的第一(飞行常客例程)、第三列(冰激凌)数据画散点数据,散点大小为15,透明度为0.5
axs[0][1].scatter(x=datingDataMat[:, 0], y=datingDataMat[:, 2], color=LabelsColors, s=15, alpha=.5)
# 设置标题,x轴label,y轴label
axs1_title_text = axs[0][1].set_title(u'每年获得的飞行常客里程数与每周消费的冰激淋公升数', FontProperties=font)
axs1_xlabel_text = axs[0][1].set_xlabel(u'每年获得的飞行常客里程数', FontProperties=font)
axs1_ylabel_text = axs[0][1].set_ylabel(u'每周消费的冰激淋公升数', FontProperties=font)
plt.setp(axs1_title_text, size=9, weight='bold', color='red')
plt.setp(axs1_xlabel_text, size=7, weight='bold', color='black')
plt.setp(axs1_ylabel_text, size=7, weight='bold', color='black')
# 画出散点图,以datingDataMat矩阵的第二(玩游戏)、第三列(冰激凌)数据画散点数据,散点大小为15,透明度为0.5
axs[1][0].scatter(x=datingDataMat[:, 1], y=datingDataMat[:, 2], color=LabelsColors, s=15, alpha=.5)
# 设置标题,x轴label,y轴label
axs2_title_text = axs[1][0].set_title(u'玩视频游戏所消耗时间占比与每周消费的冰激淋公升数', FontProperties=font)
axs2_xlabel_text = axs[1][0].set_xlabel(u'玩视频游戏所消耗时间占比', FontProperties=font)
axs2_ylabel_text = axs[1][0].set_ylabel(u'每周消费的冰激淋公升数', FontProperties=font)
plt.setp(axs2_title_text, size=9, weight='bold', color='red')
plt.setp(axs2_xlabel_text, size=7, weight='bold', color='black')
plt.setp(axs2_ylabel_text, size=7, weight='bold', color='black')
# 显示图片
plt.show()
通过图可以分析出海伦喜欢生活有品质的男人,因为飞行数多但又不高,玩游戏但又不沉迷。图1所示。
2.3准备数据:归一化数字
若存在样本
序号 玩游戏百分比 飞行数 每周消费冰淇淋公斤数 样本分类
1 0.8 400 0.5 1
2 12 13400 0.9 3
3 0 20000 1.1 2
4 67 32000 0.1 2
样本3与样本4间的距离计算公式为:
这样明显,飞行里数会对结果产生较大的影响,而事实上这三种特征是同等重要的,因此作为等权重的,飞行里数不应该如此严重到计算结果。所以需要对数据进行归一化操作。
通常将取值范围处理为0到1或者-1到1,下面的公式可以将任何范围的值转化为0到1区间的值:
newvalue=(oldvalue-min)/(max-min)
'''
数值归一化操作
参数:数据集特征矩阵
'''
def autoNorm(dataset):
min=dataset.min(0)#将每一列的最小值放在min
max=dataset.max(0)#将每一列的最大值放在min
ranges=max-min
#normDataSet=zeros(shape(dataset))
m=dataset.shape(0)#获取样本集中数据的个数
normDataSet=dataset-tile(min,(m,1))
normDataSet=normDataSet/tile(ranges,(m,1))
return normDataSet,ranges,min
2.4测试算法:验证分类器
'''
验证算法的正确率:
无参数
'''
def check_classfy():
ratio=0.1
datingMat,labels=fileread_matrix('datingTestSet.txt')
normMat,ranges,minval=autoNorm(datingMat)
num=normMat.shape[0]
num_test=int(num*ratio)
errot_count=0.0
for i in range(num_test):
result=classify0(normMat[i,:],normMat[num_test:num,:],labels[num_test:num],3)
print("预测结果:%d,真实结果:%d"%(result,labels[i]))
if result!=labels[i]:
errot_count+=1.0
print("错误率为:%d"%(errot_count/float(num_test)))
3.K近邻算法实战-手写数字识别系统
3.1数据集
手写数字数据集TXT格式
https://download.csdn.net/download/qq_37937847/12502613
3.2代码实现
'''
时间:2020-6-6
地点:家中
内容:knn实现手写数字识别
训练集:machine_learning/KNN/trainingDigits
测试集:machine_learning/KNN/testDigits
'''
from numpy import *
from os import listdir
import operator
'''
函数名:img2vector(filename)
描述:将图像转换为算法所需的向量格式
参数:文件名
图片是txt文件,是图像文件二值化后转化为,01数据格式的txt文件。32*32大小
'''
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
'''
K近邻算法实现
函数名:classify0(inX,dataSet,labels,K)
参数说明
inX:待分类的新数据向量
dataSet:样本数据集
labels:样本集的标签
K:取前K个最为相似的结果,即距离最近
'''
def classify0(inX,dataSet,labels,K):
#计算距离
dataSetSize=dataSet.shape[0]#获取数据集的大小
diffMat=tile(inX,(dataSetSize,1))-dataSet#计算待分类向量与样本集数据各个特征值之间的差
sqDiffMat=diffMat**2
sqDistances=sqDiffMat.sum(axis=1)#将各个特征值的差相加
distances=sqDistances**0.5#开方处理,结果是待分类数据与样本数据之间的距离
sortedDistIndicies=distances.argsort()#对距离进行从小到大排序,返回值是排序后的数在原列表中的下标位置
classcount={}#定义一个字典
#选择距离最小的K个点
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)
# python3中用items()替换python2中的iteritems()
# key=operator.itemgetter(1)根据字典的值进行排序
# key=operator.itemgetter(0)根据字典的键进行排序
# reverse降序排序字典
return sortedClasscount[0][0]
'''
函数名:handwritingClassTest()
描述:使用K近邻算法实现手写数字识别
无参数
'''
def handwritingClassTest():
hwLabels=[]
trainingFileList=listdir('trainingDigits')#获取目录内容,即文件夹中所有文件的名字
m=len(trainingFileList)#计算文件夹中文件的总个数
trainingMat=zeros((m,1024))#初始化特征矩阵
for i in range(m):
fileNameStr=trainingFileList[i]
fileStr=fileNameStr.split('.')[0]#利用文件名,获得数据的标签分类
calssNumStr=int(fileStr.split('_')[0])
hwLabels.append(calssNumStr)
trainingMat[i,:]=img2vector('trainingDigits/%s'%fileNameStr)
testFileList=listdir('testDigits')#获得测试集文件夹中文件的名字列表
errorcount=0.0
mTest=len(testFileList)
for i in range(mTest):
fileNameStr=testFileList[i]
fileStr=fileNameStr.split('.')[0]#利用文件名获取数据的分类标签
calssNumStr=int(fileStr.split('_')[0])
vectorUnderTest=img2vector('testDigits/%s'%fileNameStr)
class_result=classify0(vectorUnderTest,trainingMat,hwLabels,3)
print('分类结果是:%d,真实结果是:%d'%(class_result,calssNumStr))
if(class_result!=calssNumStr):
errorcount+=1.0
print('测试集数据个数共有:%d'%mTest)
print('错了%d'%errorcount)
print('错误率为%f'%(errorcount/float(mTest)))
handwritingClassTest()
4.利用Sklearn中的knn函数库实现-手写数字识别系统
Sklearn简介,是机器学习领域出名的python模块之一,包含了很多机器学习算法,
1.Classification
2.Regression回归
3.Clustering非监督分类
4.Dimensionality reduction 数据降维
5.ModelSelection 模型选择
6.Preprocessing 数据处理
这里我们将会使用到函数:sklearn.neighbors.KNeighborsClassifier
class sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, *, weights=‘uniform’, algorithm=‘auto’, leaf_size=30, p=2, metric=‘minkowski’, metric_params=None, n_jobs=None, **kwargs)
这个函数会用很多参数:
1.n_neighbors:默认为5,就是Knn中的K值
2.weights:默认是uniform,参数可以是unifrom,distance,也可以是用户自己定义的函数,uniform是均等的权重,就说所有的邻近点的权重都是相等的。distance是不均等的权重,距离近的点比距离远的点的影响大。用户自定义的函数,接收距离的数组,返回一组维数相同的权重。
3.algorithm:快速k近邻搜索算法,默认参数为auto,可以理解为算法自己决定合适的搜索算法。除此之外,用户也可以自己指定搜索算法ball_tree、kd_tree、brute方法进行搜索,brute是蛮力搜索,也就是线性扫描,当训练集很大时,计算非常耗时。kd_tree,构造kd树存储数据以便对其进行快速检索的树形数据结构,kd树也就是数据结构中的二叉树。以中值切分构造的树,每个结点是一个超矩形,在维数小于20时效率高。ball tree是为了克服kd树高纬失效而发明的,其构造过程是以质心C和半径r分割样本空间,每个节点是一个超球体。
4.leaf_size:默认是30,这个是构造的kd树和ball树的大小。这个值的设置会影响树构建的速度和搜索速度,同样也影响着存储树所需的内存大小。需要根据问题的性质选择最优的大小。
5.metric:用于距离度量,默认度量是minkowski,也就是p=2的欧氏距离(欧几里德度量)。
6.metric_params:距离公式的其他关键参数,这个可以不管,使用默认的None即可
7.并行处理设置。默认为1,临近点搜索并行工作数。如果为-1,那么CPU的所有cores都用于并行工作。
'''
时间:2020-6-6
地点:家中
内容:调用sklearn中的KNN算法实现手写数字识别
'''
from sklearn.neighbors import KNeighborsClassifier as kNN
import operator
from os import listdir
import numpy as np
'''
函数名:img2vector(filename)
描述:将图像转换为算法所需的向量格式
参数:文件名
图片是txt文件,是图像文件二值化后转化为,01数据格式的txt文件。32*32大小
'''
def img2vector(filename):
returnVect=np.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
'''
函数说明:调用Sklearn中的Knn函数实现手写数字识别
函数名:handwritingClassTest()
参数:无参
'''
def handwritingClassTest():
errorcount=1.0
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)
#将每一个文件的1*1024数据存储到trainingMat矩阵中
trainingMat[i,:]=img2vector('trainingDigits/%s'%(fileNameStr))
#构建Knn分类器
sklearn_knn=kNN(n_neighbors=3, algorithm='auto')
#传入数据进行拟合模型
sklearn_knn.fit(trainingMat,hwlabels)
testFileList=listdir('testDigits')
mtest=len(testFileList)
for i in range(mtest):
fileNameStr=testFileList[i]
classNumber=int(fileNameStr.split('_')[0])
vectorUndertest=img2vector('testDigits/%s'%(fileNameStr))
classResult=sklearn_knn.predict(vectorUndertest)
#test=sklearn_knn.predict_proba(vectorUndertest)#返回的待测数据是各个类别的概率
#print('test:',test)
print('预测结果是:%d\t真实结果是:%d'%(classResult,classNumber))
if(classResult!=classNumber):
errorcount+=1.0
print("总共错了%d个数据\n错误率是:%f"%(errorcount,errorcount/mtest))
handwritingClassTest()