k-近邻算法

it2023-11-06  71

算法原理

将每个新数据与样本集中的每个特征进行比较,计算距离。把距离递增排序选取前k个距离最小的点,并统计前k个点的标签的出现频率,将出现频率最高的标签作为当前数据的预测分类。

此处使用欧氏距离公式:

代码:

import numpy as np import operator import matplotlib import matplotlib.pylab as plt """ 函数说明: 创建数据集的例子 参数: 无 返回值: group:数据集 labels:标签类别 """ def createDataSet(): group = np.array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]]) labels = ['A', 'A', 'B', 'B'] return group, labels """ 函数说明: kNN分类器,k-近邻算法 计算已知类别点和当前点的距离,从前k个距离最小的点中,选取出现频率最高的类别作为当前点的类别 参数: inx: 用于分类的数据,测试集 dataset: 训练样本集 labels: 标签类别 k: 选取最近邻近的数目 返回值: sortClassCount[0][0]: 分类结果 """ def classify0(inx, dataSet, labels, k): # 读取矩阵第一维的长度,即行数 # 注意是shape[0],不是shape(0) dataSetSize = dataSet.shape[0] # 把inX复制成和dataSet相同行数的矩阵, 并作差 diffMat = np.tile(inx, (dataSetSize, 1)) - dataSet # 将作差的结果平方 sqDiffMat = diffMat**2 # 矩阵每行相加 sqDistances = sqDiffMat.sum(axis=1) # 结果开方 distance = sqDistances**0.5 # 返回排序的下表索引值 sortedDistIndicies = distance.argsort() # 选取前k个距离最小的点并用classCount记录 classCount = {} for i in range(k): # 距离最小的标签 voteIlabel = labels[sortedDistIndicies[i]] # 若标签存在则在标签基础上+1,若不存在返回默认值0,即0+1 classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 print(classCount) sortClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) print(sortClassCount) return sortClassCount[0][0] """ 函数说明: 打开文件,读取数据信息 参数: filename: 文件名 返回值 returnMat: 特征矩阵 classLabelVector: 类别向量 """ def file2matrix(filename): fr = open(filename) # 读取文件所有内容,保存在列表中 arrayOLines = fr.readlines() numberOfLine = len(arrayOLines) # 创建numberOfLines行,3列的0矩阵 returnMat = np.zeros((numberOfLine, 3)) classLabelVector = [] index = 0 for line in arrayOLines: line = line.strip() listFromLine = line.split() # 将数据的前3列进行提取保存在returnMat矩阵中,也就是特征矩阵 returnMat[index, :] = listFromLine[0:3] classLabelVector.append(int(listFromLine[-1])) index += 1 return returnMat, classLabelVector """ 函数说明: 归一化数值,将特征值转化为0~1区间内的值 公式:newValue = (oldValue - min) / (max - min) 参数: dataSet: 特征矩阵 返回值: normDataSet: 归一化后的特征矩阵 ranges: 数据范围 minVals: 最小值 """ def autoNorm(dataSet): # 参数 0 可以使函数从列中选取最小值,而不是行 minVals = dataSet.min(0) maxVals = dataSet.max(0) ranges = maxVals - minVals # 创建和 dataset 行列相同的矩阵 normDataSet = np.zeros(np.shape(dataSet)) # 获取 datashape 的行数 m = dataSet.shape[0] # 原始值减去最小值 normDataSet = dataSet - np.tile(minVals, (m, 1)) # 差值除以ranges normDataSet = normDataSet/np.tile(ranges, (m, 1)) return normDataSet, ranges, minVals """ 函数说明: 分类器测试 参数: 无 返回值: 无 """ def datingClassTest(): # hoRatio 表示取10%的数据用来测试 hoRatio = 0.1 # datingDataMat, datingLabels = file2matrix('datingTestSet2.txt') # 数据归一化 normMat, ranges, minvals = autoNorm(datingDataMat) # m为归一化后矩阵的行数 m = normMat.shape[0] # numTestVecs 是测试数据的行数 numTestVecs = int(m*hoRatio) # 错误次数 errorCount = 0.0 for i in range(numTestVecs): # 前 numTestVecs 个数据作为测试集,剩下的作为训练集 # normMat[i, :] 返回 normMat 矩阵第i行的全部 classifierResult = classify0(normMat[i, :], normMat[numTestVecs:m, :], datingLabels[numTestVecs:m], 3) print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i])) if(classifierResult != datingLabels[i]): errorCount += 1.0 print("the total error rate is: %f" % (errorCount/float(numTestVecs))) # group, labels = createDataSet() # datingDataMat, datingLabels = file2matrix('datingTestSet2.txt') # # fig = plt.figure() # ax = fig.add_subplot(111) # ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2], 15.0*np.array(datingLabels), 15.0*np.array(datingLabels)) # plt.show() datingClassTest()
最新回复(0)