一、 KNN算法的字面解释
所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表。
kNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。 kNN方法在类别决策时,只与极少量的相邻样本有关。由于kNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,kNN方法较其他方法更为适合。
二、举例说明
下图中,绿色圆要被决定赋予哪个类,是红色三角形还是蓝色四方形?如果K=3,由于红色三角形所占比例为2/3,绿色圆将被赋予红色三角形那个类,如果K=5,由于蓝色四方形比例为3/5,因此绿色圆被赋予蓝色四方形类。
三、代码实现及解析
import csv
import random
import math
import operator
import pandas as pd
'''def loadDataset(filename,split,trainingSet=[],testSet=[]):
with open(filename,'rb')as csvfile:
lines=csv.reader(csvfile)
dataset=list(lines)
for x in range(len(dataset)-1):
for y in range(4):
dataset[x][y]=float(dataset[x][y])
if random.random()<split:
trainingSet.append(dataset[x])
else:
testSet.append(dataset[x])
'''
#计算距离,也就是所预测的点和训练集中的点的距离
def eulideanDistance(instance1,instance2,length):
distance=0
for x in range(length):
distance+=pow((instance1[x]-instance2[x]),2)
return math.sqrt(distance)
#计算所要预测的点距离最小的K个邻居
def getNeighbors(trainingSet,testInstance,k):
distances=[]
length=len(testInstance)-1
for x in range(len(trainingSet)):
dist=eulideanDistance(testInstance,trainingSet[x],length)
distances.append([trainingSet[x],dist])
distances.sort(key=operator.itemgetter(1))
neighbors=[]
for x in range(k):
neighbors.append(distances[x][0])
return neighbors
#把所计算的邻居进行分类,返回最多的那个类,也就是预测点所属于的类
def getResponse(neighbors):
classVotes={}
for x in range(len(neighbors)):
response=neighbors[x][-1]
if response in classVotes:
classVotes[response]+=1
else:
classVotes[response]=1
sortedVotes=sorted(classVotes.items(),key=operator.itemgetter(1),reverse=True)
#operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号(即需要获取的数据在对象中的序号)
return sortedVotes[0][0]
#计算精确度,把预测集中的真实分类和预测的分类对比,计算精确度
def getAccuracy(testSet,predictions):
correct=0
for x in range(len(testSet)):
if testSet[x][-1]==predictions[x]:
correct+=1
return (correct/float(len(testSet))*100.0)
def main():
trainingSet=[]
testSet=[]
with open('iris_training.csv','r')as csvfile:
lines=csv.reader(csvfile)
for row in lines:
dataset=list(row)
#dataset[-1]=int(dataset[-1])
for y in range(4):
dataset[y]=float(dataset[y])
trainingSet.append(dataset)
#print(trainingSet)
with open('iris_test.csv','r')as csvfile:
lines=csv.reader(csvfile)
for row in lines:
dataset=list(row)
#dataset[-1]=int(dataset[-1])
for y in range(4):
dataset[y]=float(dataset[y])
testSet.append(dataset)
print('train set:'+str(len(trainingSet)))
print('test set:'+str(len(testSet)))#repr()和作用一样str()
predictions=[]
k=3
for x in range(len(testSet)):
neighbors=getNeighbors(trainingSet,testSet[x],k)
result=getResponse(neighbors)
predictions.append(result)
print('predictions'+repr(result)+' ,actual'+repr(testSet[x][-1]))
accuracy=getAccuracy(testSet,predictions)
print('accuracy'+repr(accuracy)+'%')
if __name__ == "__main__":
tf.app.run()
注:
1、代码实现过程中,最麻烦的就是数据的读入和数据格式不匹配。
2、本代码中所用数据集是训练集和测试集分开的两个数据集,如果你下载的数据集是一个数据集,要分成两部分,一部分为训练集和测试
3、注意数据集中是否含有表头,含有表头的话数据怎么处理,不含表头的话数据怎么处理,由于本人没有找到合适的方法,所以手动删除了数据集的表头,后续将会寻找更好的数据集处理的方法。
4、数据集已上传到我的博客,有需要的可以下载