基于:ml in action


KNN算法原理:

  1. 训练样本集及其标签集

  2. 测试样本

  3. 计算与测试样本距离最近的K个训练样本

  4. 统计这K个训练样本的标签频率

  5. 选择频率最高的标签作为测试样本的标签


确定K的值:通过对样本的实验(多次和人工结合),取出误差最小的分类结果。一般小于20


距离:可以是欧氏距离,


归一化:

训练样本为向量,其每个属性的尺度差别很大时,比如X=[x1,x2..],x1属于[0,1],x2属于[1000,2000],

假定距离为欧式距离,样本为X1,X2,

则distance=sqrt((X11-X21)^2+(X12-X22)^2),显然属性x2的差最大值可取1000,其平方为1000*1000,而,x1属性的差最大值为1,其平方为1,则在distance中,x2属性所占比重就会很大,x1的影响可以忽略。

事实上,x1,x2属性的在distance中比重可能应当同样重要,这个时候,需要对x2属性进行放缩,使其尺度放缩到[0,1],一般对所有属性均放缩到[0,1]

公式:

newvalue=(oldvalue-minvalue)/(maxvalue-minvalue)

oldvalue:当前样本值(向量)

minvalue:训练集中对应属性的最小值向量

maxvalue:...最大值向量

优点:简单,

缺点:需要保存训练数据,每次都要计算N次距离,N为训练样本数。时间空间复杂度高


python代码

from numpy import *

import operator

import matplotlib

import matplotlib.pyplot as plt

def generateDataset():

    group=array([[1.0,1.1],[1.1,1.0],[0,0],[0,0.1]])

    lables=['A','A','B','B']

    return group,lables


def classify0(intX,dataSet,lables,k):

    datasize=dataSet.shape[0]

    diffMat=tile(intX,(datasize,1))-dataSet

    distance=diffMat**2


    sqrtdistance=distance.sum(1)

    sqrtdistance=sqrtdistance**0.5


    sortedDistanceIndex=sqrtdistance.argsort()


    classsorted={}


    for i in range(k):

        votedlable=lables[sortedDistanceIndex[i]]

        classsorted[votedlable]=classsorted.get(votedlable,0)+1


    sortedclass=sorted(classsorted.items(),key=operator.itemgetter(1),reverse=True)


    return sortedclass[0][0]


def file2matrix(filepath):

    fr=open(filepath)

    arrayOlines=fr.readlines()

    numberoflines=len(arrayOlines)

    returnMat=zeros((numberoflines,3))

    vectorlables=[]

    index=0

    for line in arrayOlines:

        line.strip()

        listFromline=line.split('\t')

        returnMat[index,:]=listFromline[0:3]

        vectorlables.append(int(listFromline[-1]))

        index+=1

    return returnMat,vectorlables

def normMatrix(dataset):

    rows=dataset.shape[0]

    minval=dataset.min(0)

    maxval=dataset.max(0)


    maxsubmin=maxval-minval


    dataset=(dataset-tile(minval,(rows,1)))/tile(maxsubmin,(rows,1))

    return dataset,minval,maxsubmin


def plotdata(dataset,lables):

    fig=plt.figure()

    ax=fig.add_subplot(111)

    ax.scatter(dataset[:,0],dataset[:,1],15.0*array(lables),15.0*array(lables))

    fig.show()

    

(dataset,lables)=file2matrix("datingTestSet.txt")


dataset,minval,maxsubmin=normMatrix(dataset)

print (dataset)

#print (lables)

#print (minval)

#print (maxsubmin)



datasize=dataset.shape[0]

print(type(datasize))

print (datasize)

print (dataset[0,:])

traindata=dataset[0:datasize-10,:]

trainlable=lables[:datasize-10]

testdata=dataset[datasize-10:,:]

print (traindata.shape)

print (testdata.shape)

print (testdata)

testlable=lables[datasize-10:]


for i in range(9):

    result=classify0(testdata[i],traindata,trainlable,3)

    print ("result is ",result," real lable is ",testlable[i])