KNN因为需要提前准备好已分类样本,所以属于supervised learning
KNN算法思想比较简单,基本原理如下:
给定一个未分类的样本,计算其与其他所有已分类样本的距离,然后选取距离其最近的K的点,在这K个点中进行vote,决定未分类样本的归属。
python代码如下:
def classify0(inX,dataSet,labels,k):
dataSetSize=dataSet.shape[0] #已分类样本大小
diffMat=tile(inX,(dataSetSize,1))-dataSet #计算距离
sq=(diffMat**2).sum(1)
distance=sq**0.5
indexo=distance.argsort() #numpy.argsort() return the sorted index
count={}
for x in range(k): #进行vote
voteLabel=labels[indexo[x]]
count[voteLabel]=count.get(voteLabel,0)+1
result=sorted(count.items(), key=lambda d:d[0])
return result[0][0]
在对数据进行计算前,首先得对数据进行一些处理,比如同一条记录中,可能因为数值差异很大,那么就会带来数据本身权重的影响,所以需要对数据进行预处理下,比如normalization(什么是normalization,请戳我)。
python 代码如下:
def autoNorm(dataSet):
minVal=dataSet.min(0) #None表示所有数据中,最小的;0表示,每column中最小的;1表示每row中最小的
maxVal=dataSet.max(0)
ranges=maxVal-minVal
normDataSet=zeros(shape(dataSet)) #构建一个新的标准的矩阵
m=dataSet.shape[0] #shape,类似octave中的size()
normDataSet=dataSet-tile(minVal,(m,1))
normDataSet=normDataSet/tile(ranges,(m,1))
return normDataSet, ranges, minVal #返回新的数据、范围、最小值,都是矩阵类型的
从本地文件中读取数据到内存,以矩阵形式:
def image2vector(filename):
vct=zeros((1,1024))
returned=[]
f=open(filename,'r')
s=f.read()
for x in s:
if x!='\n':
returned.append(int(x))
vct=array(returned).reshape((1,1024))
f.close()
return vct
书中的例子是对手写数字进行算法识别
def handwrittingClassTest():
hwWritting=[]
file_list=os.listdir("./digits/trainingDigits/")
m=len(file_list)
trainingMat = zeros((m,1024))
for i in range(m):
filename=file_list[i]
filestr = filename
filenumber=int(filestr.split('_')[0])
hwWritting.append(filenumber)
trainingMat[i,:] = image2vector('./digits/trainingDigits/%s' % filestr)
testFileList = os.listdir('./digits/testDigits/')
errorCount = 0.0
mTest = len(testFileList)
for i in range(mTest):
filename = testFileList[i]
filestr = filename
filenumber = int(filestr.split('_')[0])
vectorUnderTest = image2vector('./digits/testDigits/%s' % filestr)
classifierResult = classify0(vectorUnderTest,trainingMat, hwWritting, 3) #K的取值为3
print "the classifier came back with: %d, the real answer is: %d"\
% (classifierResult, filenumber)
# print filename
if (classifierResult != filenumber): errorCount += 1.0
print "\nthe total number of errors is: %d" % errorCount
print "\nthe total error rate is: %f" % (errorCount/float(mTest))
最终结果(原始样本为946条):
the total number of errors is: 31
the total error rate is: 0.032770
PS:感觉效果没有想象中的那么好
KNN算法的优缺点:
Pros: 准确度高(样本数量少的话,可能会大幅度降低准确性),模型简单
Cons: 计算开销大,需要内存较多