K-近邻算法
记录一下自己的学习过程,希望也能够给学习中的你一些帮助。
主要包括以下几个部分:
1.K-近邻算法概述
2.K-近邻算法伪代码和python实现
3.K近邻算法人脸年龄识别
1.K-近邻算法(KNN)概述
k-近邻算法简单地说就是通过测量已知标签数据和未知标签数据不同特征值之间的距离,然后进行分类。
优点:精度高、对异常值不敏感、无数据输入假定(目前还不理解?)
缺点:计算复杂度高、空间复杂度高。
适用范围:数值型和标称型。
工作原理:存在已知标签的数据集,也称为训练集。输入没有标签的新的数据,将新数据的每个特征与样本数据中的特征值进行距离计算。然后选择距离最近的k个样本数据集。查看k个样本数据的对应标签,出现最多的标签记为新数据的预测标签。其中的k也是算法中k-近邻的来源。
2.K-近邻算法伪代码和python实现
伪代码:
1)计算训练集中每一个数据的特征点和新数据的特征点之间的距离。
2)按照距离递增次序进行排序。
3)选区与当前距离最小的k个点。
4)确定前k个点所在类别的出现频率。
5)返回前k个点出现频率最高的类别作为当前点的分类。
python代码:
def classify0(inX,dataset,labels,k):
datasetsize=dataset.shape[0]#获取数据集中数据的个数
diffMat=np.tile(inX,(datasetsize,1))-dataset#将待遇测数据扩展成与数据集一样大小的矩阵,并相减
sqdiffMat=diffMat**2#平方
sqdistance=sqdiffMat.sum(axis=1)#将矩阵每一行相加
distances=sqdistance**0.5#开平方得到距离
sortddistindicies=distances.argsort()#返回距离值从小到大排序后的索引值
classcount={}#定义一个字典
for i in range(k):
votelabel=labels[sortddistindicies[i]]#获取距离较近的前k个元素的类别
classcount[votelabel]=classcount.get(votelabel,0)+1#将类别作为字典的key,将出现次数作为value
sortedclasscount=sorted(classcount.items(),key=operator.itemgetter(1),reverse=True)
#将字典作为元组列表返回,按照元组的第二个元素进行逆向排序
return sortedclasscount[0][0]
3.K近邻算法人脸年龄识别
代码主要包括:1)图片转化为矩阵的函数、2)k-近值、3)矩阵归一化函数、4)读取csv数据函数、5)主函数
3.1图片转化为矩阵的函数
def img2vector(file_dir):
#print("file_dir:%s"%file_dir)
heigh=5#图片缩放后的高度
width=5#图片缩放后的宽度
im=cv2.imread(file_dir)#读取图片
im=cv2.resize(im,(heigh,width))#对图片进行缩放
data=im.reshape(1,heigh*width*3)#将图片矩阵变成1行
return data
3.2 k-近值函数和上面一样
3.3 矩阵归一化函数
def autonorm(dataset):
minvals=dataset.min(0)
maxvals=dataset.max(0)
ranges=maxvals-minvals
normdataset=np.zeros(np.shape(dataset))
print("the shape of dataset is :%s"%[dataset.shape])
m=dataset.shape[0]
normdataset=dataset-np.tile(minvals,(m,1))
normdataset=normdataset/np.tile(ranges,(m,1))
return normdataset,ranges,minvals
3.4 读取csv数据函数
def read_csv(file_dir):
with open(file_dir,'r') as csv_file:
train_data_label=[]
train_data_img=[]
test_data_label=[]
test_data_img=[]
csv_reader=csv.reader(csv_file)
csv_list=list(csv_reader)
print("the len is :%d"%len(csv_list))
train_data=csv_list[1:71]
print("the length of train_data:%s"%len(train_data))
test_data=csv_list[71:102]
print("the length of test_data:%d"%len(test_data))
for i in range(70):
train_data_img.append(train_data[i][0])
#print("train_data_img:%s"%train_data_img)
for i in range(70):
train_data_label.append(int(train_data[i][1]))
#print("train_data_label:%s"%train_data_label)
for i in range(30):
test_data_img.append(test_data[i][0])
for i in range(30):
test_data_label.append(int(test_data[i][1]))
return train_data_label,train_data_img,test_data_label,test_data_img
3.5 主函数
def facetest_knn():
csv_dir="./data/input/dev.csv"#csv文件地址
img_dir="./data/input/"#整个文件所在的地址
train_data_label,train_data_img,test_data_label,test_data_img=read_csv(csv_dir)#获取训练和测试数据
number_train=len(train_data_img)#获取训练数据长度
train_mat=np.zeros((number_train,75))#定义训练数据矩阵的大小
for i in range(70):
train_img_dir=img_dir+train_data_img[i]#获取训练图片的完整地址
train_data=img2vector(train_img_dir)#将训练图片转化为均真
train_mat[i,:]=train_data#将每一个训练图片矩阵添加到train_mat中
number_test=len(test_data_img)#获取测试数据的长度
#print("train_mat:%s"%train_mat)
#train_mat,ranges,minvals=autonorm(train_mat)#对训练数据进行归一化处理
errorcount=0.0#将错误个数初始化为1
for i in range(30):
test_img_dir=img_dir+test_data_img[i]#获取完整测试图片的地址
#print("test_img_dir:%s"%test_img_dir)
test_data=img2vector(test_img_dir)#测试图片转化为矩阵
label=test_data_label[i]#将正确标签赋值给label
classifierresult=classify0(test_data,train_mat,train_data_label,3)
print("the classifier come back with :%d,the real result is :%d"%(classifierresult,label))
if (classifierresult!=label):
errorcount+=1.0
print("the total number of errors is :%d"%errorcount)
print("the total error rate is :%f"%(errorcount/float(number_test)))
以上就是我的人脸年龄识别代码,下面又数据集的链接,一共有100张图片,我选择其中的70张作为训练,30张作为测试。当我调整输入图片矩阵的大小湿出现以下现象:1)当输入图片的长宽设置为5,错误率为0.5667。当将图片的尺寸设置为100,或者更大时,错误率为0.777。2)使用数据归一化处理后错误率增加,不知道是什么原因,我怀疑是不是我的数据量太小了。
数据地址:链接:https://pan.baidu.com/s/1IuZ2FqxkA6EFvuLtfvi30w 提取码:uoeb