理论学习:
3. 算法详述
3.1 步骤:
为了判断未知实例的类别,以所有已知类别的实例作为参照
选择参数K
计算未知实例与所有已知实例的距离
选择最近K个已知实例
根据少数服从多数的投票法则(majority-voting),让未知实例归类为K个最邻近样本中最多数的类别
3.2 细节:
关于K
关于距离的衡量方法:
3.2.1 Euclidean Distance(欧式距离) 定义
![](https://images2017.cnblogs.com/blog/701977/201708/701977-20170801163905958-659796865.jpg)
![](https://images2017.cnblogs.com/blog/701977/201708/701977-20170801163911646-210269019.png)
其他距离衡量:余弦值(cos), 相关度 (correlation), 曼哈顿距离 (Manhattan distance)
4. 算法优缺点:
4.1 算法优点
简单
易于理解
容易实现
通过对K的选择可具备丢噪音数据的健壮性
4.2 算法缺点
需要大量空间储存所有已知实例
算法复杂度高(需要比较所有已知实例与要分类的实例)
当其样本分布不平衡时,比如其中一类样本过大(实例数量过多)占主导的时候,新的未知实例容易被归类为这个主导样本,因为这类样本实例的数量过大,但这个新的未知实例实际并木接近目标样本
5. 改进版本
考虑距离,根据距离加上权重
比如: 1/d (d: 距离)
应用:
1、用库来进行实现算法
1 from sklearn import neighbors 2 from sklearn import datasets 3 4 knn = neighbors.KNeighborsClassifier() 5 6 iris = datasets.load_iris() 7 8 print(iris) 9 10 knn.fit(iris.data, iris.target) # 建模,两个参数:二维的特征值矩阵、一维的每一个实例所对应的对象 11 12 predictedLabel = knn.predict([[0.1, 0.2, 0.3, 0.4]]) 13 14 print(predictedLabel)
2、不调用任何库来实现knn算法,其中使用到的数据集是sklearn自带的iris数据集
1 # 不调用任何库来实现knn算法 2 3 import csv 4 import random 5 import math 6 import operator 7 8 # 将数据集装载到Python里面 9 # filename:数据集存放的文件 10 # split:以此参数为界限将数据集分为trainingSet训练集和testSet测试集 11 def loadDataset(filename, split, trainingSet=[], testSet=[]): 12 with open(filename, 'r') as csvfile: # 打开文件 13 lines = csv.reader(csvfile) # 读取文件的所有行 14 dataset = list(lines) # 文件内容转换成list结构 15 16 # 将数据集分为两部分 17 for x in range(len(dataset) - 1): 18 for y in range(4): 19 dataset[x][y] = float(dataset[x][y]) 20 # 随机数小于split放入训练集,大于就放入测试集 21 if random.random() < split: 22 trainingSet.append(dataset[x]) 23 else: 24 testSet.append(dataset[x]) 25 26 # 计算两个实例之间的欧式距离 27 # instance1、instance2是两个实例 28 # length是实例的维数 29 def euclideanDistance(instance1, instance2, length): 30 distance = 0 # 设置初始值为0 31 32 # 计算所有维度的差的平方和 33 for x in range(length): 34 distance += pow((instance1[x] - instance2[x]), 2) 35 return math.sqrt(distance) 36 37 # 测试集中的一个实例到训练集的距离最近的k个实例 38 # trainingSet:训练集 39 # testInstance:测试集实例 40 # k:距离最近的个数 41 def getNeighbors(trainingSet, testInstance, k): 42 distances = [] 43 length = len(testInstance) - 1 44 for x in range(len(trainingSet)): 45 dist = euclideanDistance(testInstance, trainingSet[x], length) 46 distances.append((trainingSet[x], dist)) 47 distances.sort(key=operator.itemgetter(1)) 48 neighbors = [] 49 for x in range(k): 50 neighbors.append(distances[x][0]) 51 return neighbors 52 53 def getResponse(neighbors): 54 """ 55 得到 56 :param neighbors:附近的实例 57 :return:得票最多的类别情况 58 59 """ 60 classVotes = {} 61 for x in range(len(neighbors)): 62 response = neighbors[x][-1] 63 if response in classVotes: 64 classVotes[response] += 1 65 else: 66 classVotes[response] = 1 67 sortedVotes = sorted(classVotes.items(), key=operator.itemgetter(1), reverse=True) # classVotes.iteritems() 68 return sortedVotes[0][0] 69 70 def getAccuracy(testSet, predictions): 71 """ 72 得到预测的正确率 73 :param testSet:测试集 74 :param predictions: 预测结果 75 :return: 预测的正确率 76 77 """ 78 correct = 0 79 for x in range(len(testSet)): 80 if testSet[x][-1] == predictions[x]: 81 correct += 1 82 return (correct/float(len(testSet))) * 100.0 83 84 85 def main(): 86 """ 87 88 :return: 89 """ 90 trainingSet = [] 91 testSet = [] 92 split = 0.67 # 把2/3的数据作为训练集,1/3为测试集 93 loadDataset(r'irisdata.txt', split, trainingSet, testSet) 94 print('Train set: ' + repr(len(trainingSet))) 95 print('Test set: ' + repr(len(testSet))) 96 97 predictions = [] 98 k = 3 99 for x in range(len(testSet)): 100 neighbors = getNeighbors(trainingSet, testSet[x], k) # 找到各个测试集实例最近的邻居 101 result = getResponse(neighbors) 102 predictions.append(result) 103 print('> predicted=' + repr(result) + ',actual=' + repr(testSet[x][-1])) 104 accuracy = getAccuracy(testSet, predictions) 105 print('Accuracy: ' + repr(accuracy) + '%') 106 107 108 if __name__ == '__main__': 109 main()