这里是写给小白看的,大牛路过勿喷。

 

1 KNN算法简介

  KNN(K-Nearest Neighbor)工作原理:存在一个样本数据集合,也称为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类对应的关系。输入没有标签的数据后,将新数据中的每个特征与样本集中数据对应的特征进行比较,提取出样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k近邻算法中k的出处,通常k是不大于20的整数。最后选择k个最相似数据中出现次数最多的分类作为新数据的分类

 

2 KNN算法优缺点

  优点:精度高,对异常值不敏感、无数据输入假定

  缺点:计算复杂度高、空间复杂度高

 

 

做一个简单的应用:

一种花叫做虹膜花:

 

收集一些实例
 
萼片长度,萼片宽度,花瓣长度,花瓣宽度
(sepal length, sepal width, petal length and petal width)
 
类别:
Iris setosa, Iris versicolor, Iris virginica.
 
学习目标是:根据四种属性判断类别
 
用python的sklearn库实现:
(sklearn中已经存在的数据集)
  1. from sklearn import neighbors
  2. from sklearn import datasets
  3. knn = neighbors.KNeighborsClassifier()
  4. iris = datasets.load_iris()
  5. knn.fit(iris.data, iris.target)
  6. # 当数据为0.1, 0.2, 0.3, 0.4时,预测它是什么花
  7. predictedLabel = knn.predict([[0.1, 0.2, 0.3, 0.4]])
  8. print(predictedLabel)

 

 
 不调用sklearn,自己实现:
 
 这是一个数据集文本
 截取数据集(irisdata.txt)的一段:
  1. 5.1,3.5,1.4,0.2,Iris-setosa
  2. 4.9,3.0,1.4,0.2,Iris-setosa
  3. 4.7,3.2,1.3,0.2,Iris-setosa
  4. 4.6,3.1,1.5,0.2,Iris-setosa
  5. 5.0,3.6,1.4,0.2,Iris-setosa
  6. 5.4,3.9,1.7,0.4,Iris-setosa
  7. 4.6,3.4,1.4,0.3,Iris-setosa
  8. 5.0,3.4,1.5,0.2,Iris-setosa

 

导入几个基本的库:

  1. import csv
  2. import random
  3. import math
  4. import operator

 

全局定义两个集合:训练集、测试集

  1. # 训练集
  2. trainingSet = []
  3. # 测试集
  4. testSet = []

 

 读取数据并做一些初步的处理:

 传入一个分割概率,随机划分训练集和测试集

  1. def loadDataset(filename, split):
  2. with open(filename, 'r') as csvfile:
  3. lines = csv.reader(csvfile)
  4. dataset = list(lines)
  5. for x in range(len(dataset) - 1):
  6. for y in range(4):
  7. dataset[x][y] = float(dataset[x][y])
  8. if random.random() < split:
  9. trainingSet.append(dataset[x])
  10. else:
  11. testSet.append(dataset[x])

 

 欧式距离:
 类似代数中直角坐标系的两点距离,只是扩展到多维
  1. def euclideanDistance(instance1, instance2, length):
  2. distance = 0
  3. for x in range(length):
  4. distance += pow((instance1[x] - instance2[x]), 2)
  5. return math.sqrt(distance)

 

训练集中选出距离测试集中一个实例最近的k个数据:

计算训练集中每一项和该实例的欧氏距离,取最小的k个距离

  1. def getNeighbors(k, testInstance):
  2. distances = []
  3. length = len(testInstance) - 1
  4. for x in range(len(trainingSet)):
  5. dist = euclideanDistance(testInstance, trainingSet[x], length)
  6. distances.append((trainingSet[x], dist))
  7. distances.sort(key=operator.itemgetter(1))
  8. neighbors = []
  9. for x in range(k):
  10. neighbors.append(distances[x][0])
  11. return neighbors

 

获取的这些k项未必是同一类,接下来统计类别个数,并返回出现次数最多的类作为最终的结果:

  1. def getResponse(neighbors):
  2. classVotes = {}
  3. for x in range(len(neighbors)):
  4. response = neighbors[x][-1]
  5. if response in classVotes:
  6. classVotes[response] += 1
  7. else:
  8. classVotes[response] = 1
  9. sortedVotes = sorted(classVotes.items(), key=operator.itemgetter(1), reverse=True)
  10. return sortedVotes[0][0]

 

验证精确度:

将测试集中预测的类别和测试集中真实的类别对比,得出精确度百分比:

  1. def getAccuracy(predictions):
  2. correct = 0
  3. for x in range(len(testSet)):
  4. if testSet[x][-1] == predictions[x]:
  5. correct += 1
  6. return (correct / float(len(testSet))) * 100.0

 

主函数:

 

  1. if __name__ == '__main__':
  2. main()

 

  1. def main():
  2. split = 0.70
  3. loadDataset(r'D:\ml\irisdata.txt', split)
  4. print('Train set: ' + repr(len(trainingSet)))
  5. print('Test set: ' + repr(len(testSet)))

 

读取后打印下个数:

  1. Train set: 102
  2. Test set: 48

 

接下来预测:

  1. predictions = []
  2. k = 3
  3. for x in range(len(testSet)):
  4. neighbors = getNeighbors(k, testSet[x])
  5. result = getResponse(neighbors)
  6. predictions.append(result)
  7. print('>predicted=' + repr(result) + ', actual=' + repr(testSet[x][-1]))

 

看一下预测的一部分结果:

 

 

发现基本预测准确,测试精确度:

  1. accuracy = getAccuracy(predictions)
  2. print('Accuracy: ' + repr(accuracy) + '%')

 

发现精确度很高:

 

由于处理数据时候采用随机划分的方式,可以反复运行测试,发现准确率基本在90%到96%,说明这个模型是合适的

 

小结:

  KNN是简单有效的分类数据算法,在使用时必须有训练样本数据,还要计算距离,如果数据量非常大会非常消耗空间和时间。它的另一个缺陷是无法给出任何数据的基础结构信息,因此我们无法平均实例样本和典型实例样本具体特征,

版权声明:本文为xuyiqing原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/xuyiqing/p/8762066.html