k-邻近算法是一种测量不同特征值之间距离来进行分类的一种算法。
該算法的优点是精度高,对异常的特征值不敏感,但是缺点也很明显,计算的复杂度高,计算空间复杂度也比较高。
k邻近算法就是 通过计算 目标点的特征值 与样本点的特征值 前k个距离最小的样本点的类别中概率最大的一个就是目标点的类别。
如上图 若取前10个与C距离最小的点,那么这前10个点中属于集合A必定大于属于集合B的,那么就可以得出C的应该按集合A分类。
该算法也存在缺陷,比如在样本数量不足的情况下。比如上图的集合A只有一个点,那么10个最近的点中有9个都会是属于集合B,
得出不可靠的结论,在一个缺点就是该算法需要将目标与大量样本计算比较才能得出前k个最近的样本,计算量大。
接下来完成一个同个KNN算法实现识别数字的例子:
样本是类似如下图的32*32的数据,下面是0,4,5
下面通过一个dataPrepare函数来将上面形式的数据转换成1*1024的向量(32*32 = 1024), trainDataMat函数将目录下的样本全部转换为一个m*1024的矩阵
1 def dataPrePare(filename): 2 ReturnVect = zeros((1,1024)) 3 file = open(filename) 4 for i in range(32): 5 Rowdata = file.readline() 6 for j in (32): 7 ReturnVect[0, 32 * i + j] = Rowdata[j] 8 return ReturnVect 9 10 11 # 将目录下的样本数据转换为矩阵 12 def trainDataMat(filenamePath): 13 filenameList = listdir(filenamePath) 14 TrainMat = zeros((len(filenameList), 1024)) 15 DataLabel = [] 16 for i in range(len(filenameList)): 17 filename = filenameList.split('.')[0] # 样本文件的名称 例如 0_9.txt 表示 数字为0 的第9个样本 18 DataLabel.append(int(filename.split('_')[0])) 19 20 TrainMat[i, :] = DataToMat(filenamePath + '\\' + filename) 21 22 return TrainMat, DataLable
分类函数 knnClassify
1 #ClassifyTarget 待分类目标 TrainMatData 训练样本 LableMat 训练样本标签 K 前K个根据特征值计算出距离的最小距离样本 2 def knnClassify(ClassifyTarget, TrainMatData, LableMat, k): 3 RowCount_TrainDataMat = TrainMatData.shape[0] # 训练样本矩阵行数 4 ClassifyTarget_Mat = tile(ClassifyTarget, (RowCount_TrainDataMat, 1)) 5 diffmat = ClassifyTarget_Mat - TrainMatData #带分类目标与训练样本作差 6 sqdiff_mat = diffmat**2 #每行每个元素取平方 7 sqdistance_mat = sqdiff_mat.sum(axis = 1)# 每行相加 8 distance_mat = sqdistance_mat **0.5 #特征值 距离矩阵 9 sortindex = distance_mat.argsort() #距离从小到达排列 返回其索引数组 10 11 labelcount_dict = {} 12 13 for i in range(k): 14 labelcount_dict[LableMat[sortindex[i]]] = labelcount_dict.get(LableMat[sortindex[i]], 0) + 1 # 各个标签计数 15 16 Return_dict = sorted(labelcount_dict.items(), key=operator.itemgetter(1), reverse=True) #得到次数最多的标签 17 return Return_dict[0][0] #返回 分类值
完整代码
# _*_ coding=utf-8 from numpy import * import operator def dataPrePare(filename): returnVect = zeros((1,1024)) #初始化一个全为0的1*1024向量 file = open(filename) for i in range(32): rowline = file.readline() for j in range(32): returnVect[0,32*i + j] = int(rowline[j]) return returnVect def trainDataMat(DataPath): trainlable = [] trainfilelist = listdir(DataPath) DataCount = len(trainfilelist) #获取训练数据数量 在该路径下的文件都是训练数据 trainMat = zeros((DataCount, 1024)) for i in range(DataCount): filename = trainfilelist[i] filenamestr = filename.split('.')[0] ClassNumint = int(filenamestr.split('_')[0]) trainlable.append(ClassNumint) trainMat[i, :] = dataPrePare(DataPath + '/%s'% filename) return trainMat, trainlable #ClassifyTarget 待分类目标 TrainMatData 训练样本 LableMat 训练样本标签 K 前K个根据特征值计算出距离的最小距离样本 def knnClassify(ClassifyTarget, TrainMatData, LableMat, k): RowCount_TrainDataMat = TrainMatData.shape[0] # 训练样本矩阵行数 ClassifyTarget_Mat = tile(ClassifyTarget, (RowCount_TrainDataMat, 1)) diffmat = ClassifyTarget_Mat - TrainMatData #带分类目标与训练样本作差 sqdiff_mat = diffmat**2 #每行每个元素取平方 sqdistance_mat = sqdiff_mat.sum(axis = 1)# 每行相加 distance_mat = sqdistance_mat **0.5 #特征值 距离矩阵 sortindex = distance_mat.argsort() #距离从小到达排列 返回其索引数组 labelcount_dict = {} for i in range(k): labelcount_dict[LableMat[sortindex[i]]] = labelcount_dict.get(LableMat[sortindex[i]], 0) + 1 Return_dict = sorted(labelcount_dict.items(), key=operator.itemgetter(1), reverse=True) return Return_dict[0][0] #返回 分类值 if __name__ == '__main__': TargetMat = dataPrePare('XXXXXX.txt')#待分类目标路径 TrainDataMat, TrainDataLabel = trainDataMat('xxxxx') #用于分类的样本路径 ClassifyResult = knnClassify(TargetMat, TrainDataMat, TrainDataLabel, 10) print(ClassifyResult) pass
总结:KNN是分类最简单的最有效的算法,但是 需要大量的样本,导致需要的存储空间大,耗时长