将下载之后的数据集复制到你的Python代码目录下,我的是D:\pythonStudy\机器学习\K-近邻算法
其中datingTestset 与datingTestset2是关于约会网站配对
trainingDigits与testDigists是关于手写数字识别的txt文件
# -*- coding: utf-8 -*-
# @Author : Mathematic
# @Time : 2022-1-27 11:30
# @Function: KNN Python代码实现(不调用sklearn包)
from numpy import *
from os import listdir #可以列出给定目录的文件名
import operator
import matplotlib.pyplot as plt
def creatdataset(): #定义训练数据集
group=array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]]) #定义测试数据
labels=['A','A','B','B'] #定义标签
return group,labels
#################以下注释代码可以可视化数据集createdataset#####################################
##########################测试数据集散点图表示(封面代码)##############################
'''
group=array([[1.0,1.1],[1.0,1.0],[0.0,0.0],[0,0.1]]) #获取矩阵group
labels=['A',"A",'B','B'] #获取列表labels
x=group[:,0] #读取矩阵的第一列
y=group[:,1] #读取矩阵的第二列
label=['A','A','B','B']
plt.xlim(xmax=1.2,xmin=-0.2)
plt.ylim(ymax=1.2,ymin=-0.2)
####画出散点图
for i in range(4):
plt.plot(x[i],y[i],'ro')
plt.text(x[i],y[i],label[i])
#plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.title('labels-data')
plt.show()
'''
##########################################################################################
##################################定义KNN算法分类器1###############################################################
def classify1(inX,dataset,labels,k):
datasetSize=dataset.shape[0] #获取dataset数据集的行数,如果是shape[1]就是获得列数
diffMat=tile(inX,[datasetSize,1])-dataset #tile(A,[a,b])是将A的行重复a次,列重复b次
####计算欧式距离
sqDiffMat=diffMat**2
sqdistances=sqDiffMat.sum(axis=1)
distance1=sqdistances**0.5
sorteindex=distance1.argsort() #argsort返回的是从小到大排序的索引
countdic={} #定义一个空字典
for i in range(k):
newlabel=labels[sorteindex[i]] #将空字典赋予新的键:newlabel
#print(newlabel)
countdic[newlabel]=countdic.get(newlabel,0)+1
#print(countdic)
sortedcount=sorted(countdic.items(),key=operator.itemgetter(1),reverse=True) #sorted函数返回的是列表,itemgetter(1)是指按照第二个元素的顺序进行从小到大排列
#print(sortedcount)
return sortedcount[0][0] #45行代码后返回的是列表:[('B', 2), ('A', 1)],列表里面是元组,[0][0]表示的是列表第一个元素(元组)的第一个值,即B
###########################处理文本数据##############################################
def filematrix(filename):
fr=open(filename)
arrayofline=fr.readlines()
numberoflines=len(arrayofline) #读取文本的列的长度
Mat=zeros((numberoflines,3))#生成一个与文本文件行数列数相同的零矩阵,由于本题文本前三列是数据,最后一列是标签
classifylabelvector=[] #初始化标签为空列表
index=0 #初始化索引
for line in arrayofline:
line=line.strip() #截取掉回车符
listfromline=line.split('\t') #利用\tab字符将上一步获得的整行数据分割成一个元素列表
Mat[index,:]=listfromline[0:3] #选取列表中前三个元素存储到特征矩阵中
classifylabelvector.append(listfromline[-1]) #Python中索引值-1指向列表最后一个元素,将其存储到标签列表中
index+=1 #索引值+1
return Mat,classifylabelvector #返回特征矩阵与标签列表
###########################################################################
#############################数据归一化处理##################################
def autonorm(dataset):
minval=dataset.min(0) #将dataset的每一列的最小值存储到minval中,min(0)的0为取所在列的最小值,而不是当前行的最小值
maxval=dataset.max(0) #dataset的每一列的最大值存储到maxval中,max(0)的0为取所在列的最大值,而不是当前行的最大值
ranges=maxval-minval #最大值减去最小值
normdataset=zeros(shape(dataset)) #生成与dataset同类型的零矩阵,即初始化normdataset
m=dataset.shape[0] #获取dataset的行数
normdataset=dataset-tile(minval,(m,1)) #将dataset的每个元素都减去该元素所在列的最小值
normdataset=normdataset/tile(ranges,(m,1)) #归一化处理
return normdataset,ranges,minval
#############################################################################
##############################对分类器1进行测试,拿出datingTestset2.txt中的10%数据来进行测试###########################################
def datingclassTest():
ratio=0.1 #选取数据集的10%作为测试集
datingmat,datinglabels=filematrix('datingTestSet.txt') #选取文本类数据datingTestSet.txt
normMat,ranges,minval=autonorm(datingmat) #数据归一化处理
m=normMat.shape[0] #读取归一化矩阵的行数
testnumbers=int(m*ratio) #测试集的数据个数
errorcount=0 #初始化错误预测的数据个数
for i in range(testnumbers): #由于该数据集没有先后顺序,故选取前面10%的数据来进行测试
result=classify1(normMat[i,:],normMat[testnumbers:m,:],datinglabels[testnumbers:m],3) #输入数据为测试集前m个,原数据为其余的1000-m个
print('The predict data class is :{0},The real value is : {1}'.format(result,datinglabels[i]))
if(result!=datinglabels[i]):
errorcount+=1
print('The accuracy is ',1-errorcount/testnumbers)
#最后显示准确率为0.95,故该分类器效果比较不错
###########################################################################################
###################################利用分类器对自己输入的数据进行预测#####################################
def predictperson():
personlabels=['not at all','small doses','large doses']
percentTats=float(input('percentage of time in playing video games?'))
ffmiles=float(input('frequent flier mails earned every year?'))
icecream=float(input('liters of ice cream consumed per year? '))
datingdatamat,datinglabels=filematrix('datingTestSet2.txt')
normmat,ranges,minval=autonorm(datingdatamat)
inarray=array([ffmiles,percentTats,icecream])
classifyresult=classify1((inarray-minval)/ranges,normmat,datinglabels,3)
print('You will probably like like this person :',personlabels[int(classifyresult) -1])
###############################################################################################
#########################将图像格式化处理成一个向量#####################################33
def imgtovector(filename):
returnvector=zeros((1,1024))
fr=open(filename)
for i in range(32):
linestr=fr.readline()
for j in range(32):
returnvector[0,32*i+j]=int(linestr[j])
return returnvector
##########################################################################################
###############################手写数字识别系统的测试代码########################################
def handwritingtest1():
hwlabels=[]
#############获取目录内容##################
trainingfilelist=listdir('trainingDigits') #listdir可以获得目录所存的文件名称
m=len(trainingfilelist) #获得文件的个数
trainmat=zeros((m,1024)) #初始化训练集矩阵,一共有m个文件,每个文件生成【1,1024】维行向量
for i in range(m):
filenamestr=trainingfilelist[i] #获得第i个文件名称
filestr=filenamestr.split('.')[0] #将文件名称分为两部分,分隔符以'.',取第一部分,例如:3_112.txt分割为3_112与txt,取3_112
classNumstr=int(filestr.split('_')[0]) #将3_112划分为两个部分,分隔符以'_',取第一部分,例如:3_112分割为3和112,取3,也就是待识别的数字3
#print(classNumstr)
hwlabels.append(classNumstr) #将待识别的数字添加到列表hwlabels里面去
trainmat[i,:]=imgtovector('D:/pythonStudy/机器学习/K-近邻算法/trainingDigits/%s' % (filenamestr)) #存储训练数据
testfilelist=listdir('testDigits') #获得测试集的文件名称
errorcount=0
mtest=len(testfilelist)
for i in range(mtest):
fileNamestr=testfilelist[i] #读取测试集里面第i个文件名称
fileStr=fileNamestr.split('.')[0] #同上
testclassnumber=int(fileStr.split('_')[0]) #同上
vectortest=imgtovector('D:/pythonStudy/机器学习/K-近邻算法/testDigits/%s' % (fileNamestr)) #注意%两边都是空格
clssifyresult=classify1(vectortest,trainmat,hwlabels,3) #由于KNN不需要训练过程,只需要待分类的数据集与测试集即可
#print('The predict number is:%d,The real number is :%d'%(clssifyresult,testclassnumber))
if(clssifyresult!=testclassnumber):
errorcount+=1
print('The accurray is :%f'%(1-errorcount/float(mtest))) #输出分类准确率
#####################通过调整k值大小来判断最优k值是多少(针对手写数字识别)############################
def handwritingtest2():
hwlabels = []
#############获取目录内容##################
trainingfilelist = listdir('trainingDigits') # listdir可以获得目录所存的文件名称
m = len(trainingfilelist) # 获得文件的个数
trainmat = zeros((m, 1024)) # 初始化训练集矩阵,一共有m个文件,每个文件生成【1,1024】维行向量
for k in range(2,7):
for i in range(m):
filenamestr = trainingfilelist[i] # 获得第i个文件名称
filestr = filenamestr.split('.')[0] # 将文件名称分为两部分,分隔符以'.',取第一部分,例如:3_112.txt分割为3_112与txt,取3_112
classNumstr = int(filestr.split('_')[0]) # 将3_112划分为两个部分,分隔符以'_',取第一部分,例如:3_112分割为3和112,取3,也就是待识别的数字3
# print(classNumstr)
hwlabels.append(classNumstr) # 将待识别的数字添加到列表hwlabels里面去
trainmat[i, :] = imgtovector('D:/pythonStudy/机器学习/K-近邻算法/trainingDigits/%s' % (filenamestr)) # 存储训练数据
testfilelist = listdir('testDigits') # 获得测试集的文件名称
errorcount = 0
mtest = len(testfilelist)
for i in range(mtest):
fileNamestr = testfilelist[i] # 读取测试集里面第i个文件名称
fileStr = fileNamestr.split('.')[0] # 同上
testclassnumber = int(fileStr.split('_')[0]) # 同上
vectortest = imgtovector('D:/pythonStudy/机器学习/K-近邻算法/testDigits/%s' % (fileNamestr)) # 注意%两边都是空格
clssifyresult = classify1(vectortest, trainmat, hwlabels, k) # 由于KNN不需要训练过程,只需要待分类的数据集与测试集即可
# print('The predict number is:%d,The real number is :%d'%(clssifyresult,testclassnumber))
if (clssifyresult != testclassnumber):
errorcount += 1
print('The accurray is :%f' % (1 - errorcount / float(mtest))) # 输出分类准确率
'''
k-近邻算法是分类数据最简单最有效的算法,本章通过两个例子讲述了如何使用k-近邻算法
构造分类器。k-近邻算法是基于实例的学习,使用算法时我们必须有接近实际数据的训练样本数
据。k-近邻算法必须保存全部数据集,如果训练数据集的很大,必须使用大量的存储空间。此外,
由于必须对数据集中的每个数据计算距离值,实际使用时可能非常耗时。
k-近邻算法的另一个缺陷是它无法给出任何数据的基础结构信息,因此我们也无法知晓平均
实例样本和典型实例样本具有什么特征。下一章我们将使用概率测量方法处理分类问题,该算法
可以解决这个问题。
'''
import Knn
'''
group,labels= KNN.creatdataset()
a= KNN.classify1([0, 0], group, labels, 3) #########对点[0,0]进行分类
print(a)
'''
datingMat,datinglabels=Knn.filematrix('datingTestSet.txt')
normmat,range,minval=Knn.autonorm(datingMat)
#Knn.datingclassTest()
#Knn.predictperson()
#Knn.handwritingtest2()
代码所需数据集在公众号:数学与智能科学 回复:KNN即可获得。
同时在公众号里面有关于算法KNN的详细介绍