KNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。 KNN方法在类别决策时,只与极少量的相邻样本有关。由于kNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,kNN方法较其他方法更为适合。
算法:
1. 准备数据,对数据进行预处理
2. 选用合适的数据结构存储训练数据和测试元组
3. 设定参数,如k
4.维护一个大小为k的的按距离由大到小的优先级队列,用于存储最近邻训练元组。随机从训练元组中选取k个元为初始的最近邻元组,分别计算测试元组到这k个元组的距离,将训练元组标号和距离存入优先级队列
5. 遍历训练元组集,计算当前训练元组与测试元组的距离,将所得距离L 与优先级队列中的最大距离Lmax
6. 进行比较。若L>=Lmax,则舍弃该元组,遍历下一个元组。若L < Lmax,删除优先级队列中最大距离的元组,将当前训练元组存入优先级队列。
7. 遍历完毕,计算优先级队列中k 个元组的多数类,并将其作为测试元组的类别。
8. 测试元组集测试完毕后计算误差率,继续设定不同的k值重新进行训练,最后取误差率最小的k值。
Python代码:
# coding=utf-8
from sklearn import neighbors
from sklearn import datasets
knn = neighbors.KNeighborsClassifier()
iris = datasets.load_iris()
# iris中文指鸢尾植物,这里存储了其萼片和花瓣的长宽,一共4个属性,鸢尾植物又分三类。与之相对,iris里有两个属性iris.data,iris.target,
# data里是一个矩阵,每一列代表了萼片或花瓣的长宽,一共4列,每一列代表某个被测量的鸢尾植物,一共采样了150条记录.
knn.fit(iris.data, iris.target)
predicted = knn.predict([[0.1, 0.2, 0.3, 0.4]])
print predicted
源代码:
# coding=utf-8
import csv
import math
import random
import operator
#按照sqilt跑随机来分训练组和联系组
def Sqlitset(file, textset, trainset, sqilt):
with open(file, 'rb') as file:
List = csv.reader(file)#将文件的每一行变成数组
dataset = list(List)#每一行的每一个元素变成数字类型的数组
for i in range(len(dataset)-1):
for j in range(4):
dataset[i][j] = float(dataset[i][j])
if(random.random() > sqilt):#取随机数
textset.append(dataset[i])
else:
trainset.append(dataset[i])
#求两点的距离
def XYlen(trainset, textset):
sum = 0;
for i in range(4):
sum += pow(textset[i]-trainset[i],2)
return math.sqrt(sum)
#求一组练习量来算距离,然后取k个距离最小的
def Nearlen(textset, trainset, k):
neardata = []
allLendata = []
for i in range(len(trainset)-1):
Len = XYlen(trainset[i], textset)
allLendata.append((trainset[i],Len))
allLendata.sort(key = operator.itemgetter(1))#按照len来进行升序排序
for i in range(k):
neardata.append(allLendata[i][0])
return neardata
#对距离进行分析获得预测的结果
def getrespon(nears):
aim = {}#用到了字典
for i in range(len(nears)):
respon = nears[i][-1]
if respon in aim:
aim[respon] += 1
else:
aim[respon] = 1
sortaim=sorted(aim.iteritems(), key=operator.itemgetter(1), reverse=True)
return sortaim[0][0]
#预测结果和实际结果进行比较得到概率
def getprobability(predict, textset):
ans = 0;
for i in range(len(textset)):
if textset[i][-1] == predict[i]:
ans+=1
return 1.0*ans/len(textset)*100
textset = []#练习组
trainset = []#训练组
sqlit = 0.67#随机分界
Sqlitset(r'C:\Users\l\Desktop\knndate.txt', textset, trainset, sqlit)
predict = []
k = 3
for i in range(len(textset)):
nears = Nearlen(textset[i], trainset, k)
respon = getrespon(nears)
predict.append(respon)
probability = getprobability(predict, textset)
print probability
注意:
K值的设定
一般会加一个权值来规范k。
K值设置过小会降低分类精度;若设置过大,且测试样本属于训练集中包含数据较少的类,则会增加噪声,降低分类效果。
通常,K值的设定采用交叉检验的方式(以K=1为基准)
经验规则:K一般低于训练样本数的平方根。
《机器学习实战》knn代码讲解:
KNN是相对来说比较简单的算法
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = tile(inX, (dataSetSize,1)) - dataSet
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5
sortedDistIndicies = distances.argsort()
classCount={}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
解释一下代码的意思吧
首先,我们需要需要的数据有四个,分别是:
(1)、测试集中的一个数据项,一个1*n的矩阵
(2)、训练集, 一个m*n的矩阵
(3)、训练集的标签,一个n*1的矩阵
(4)、k的数值
然后需要掌握的5个python的知识点:
(1)、tile(X,(n,m))返回一个n*m的矩阵,X为一个元素
(2)、X**2和X**0.5 分别为矩阵X的平方和开方
(3)、X.argsort()返回X从小到大的索引值
(4)、字典dict.get(key,default)获取字典的键值,如果不存在返回default,否则返回none
(5)、sort(classCount.iteritems(),key=operator.iteritems(1),reverse = True)字典排序,一共有三个值,第一个值为比较的列表,第二个为比较的键值,第三个值为Ture为升序。
最后万事俱备只欠代码:
(1)、求距离:将测试集数据变成m*n的矩阵减去训练集,平方求和开方,得到m*1的矩阵表示距m个训练集的距离。
(2)、选k个点:m个距离按索引排序(升序)找到最小的k个值建字典,字典排序(降序)
(3)、ok了:f返回字典的[0][0]