KNN(K近邻)算法的简单入门

来源:互联网 发布:final cut mac 编辑:程序博客网 时间:2024/06/05 15:36

机器学习实战(第二章:k-近邻算法)

今天学习了第二章,在此就我理解做一下简单的总结,算是加深我的理解和用我自己的语言描述出这个算法吧。


距离计算

基于向量空间的欧几里得距离的计算。(L2距离)

特别情况下可采用Lp距离(明氏距离) L1距离。


简单点来说就是 在一个具有大量样本集中,每一个实例都具有3个或以上的特征属性,其中有一个属性必然是分类属性,其余属性为数值型属性(即使是标称型属性,也可以通过 某些方法转变过来),每一个实例都是由属性特征值组成的一个向量,一个样本集就是多个向量组成。

例如下面这个例子

 身高体重年龄性别17014022男16010021女
“”性别“”可以看成是一个分类属性,然后其他看特征属性 ,组成一个实例向量就为 [170,140,22]和[160,100,21]


一、算法步骤:
1、计算已知类别数据集中的点与当前点之间的距离;
2、按照距离递增次序排序;
3、选取与当前点距离最小的k个点;
4、确定k个点所在类别的出现频率;

(K用于选择最近邻的数目,K的选择非常敏感。K值越小意味着模型复杂度越高,从而容易产生过拟合;K值越大则 意味着整体的模型变得简单,学习的近似误差会增大,在实际的应用中,一般采用一个比较小的K值,用交叉验证的 方法,选取一个最优的K值。)
5、返回前k个点出现频率最高的类别作为当前点的预测分类

二、例子说明(python)

首先按照算法编写一个knn算法类

'''
inX:用于分类的输入向量
dataSet:训练样本集
labels:标签向量
k:用于选择最近邻的数目

'''
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() #按从小到大的排序后的索引值
#选择距离最小的k个点
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]


举一个实例说明(手写识别数据)

数据说明:



我们需要把每一个样本数据转变成向量的格式,由于图片是32X32的txt文本格式存在,我们转变成1X1024的向量,并把所有的训练样本保存为一个矩阵,对应的每一行就是每一个实例。

#把一个32X32的变成1X1024的向量def img2vector(filename):    returnVec = zeros((1,1024))    fr = open(filename)    for i in range(32):        lineStr = fr.readline()        for j in range(32):            returnVec[0,32*i+j] = int(lineStr[j])    return returnVec


运用我们事先写好的knn算法类,按照格式代进去训练并且计算错误率。

def handwritingClassTest():    hwLabels = []    #获取训练集    trainingFileList = os.listdir('digits//trainingDigits') #获取该目录下所有文件名 类型:list    m = len(trainingFileList)    trainingMat = zeros((m,1024))    for i in range(m):        fileNameStr = trainingFileList[i]               #7_173.txt        fileStr = fileNameStr.split('.')[0]             #'7_173' 'txt'        classNumStr = int(fileStr.split('_')[0])        #7  173        hwLabels.append(classNumStr)        trainingMat[i,:] = img2vector("digits//trainingDigits//"+fileNameStr)    #获取测试集    testFileList = os.listdir("digits//testDigits")    errorCount = 0    mTest = len(testFileList)    for i in range(mTest):        fileNameStr = testFileList[i]        fileStr = fileNameStr.split('.')[0]  # '7_173' 'txt'        classNumStr = int(fileStr.split('_')[0])  # 7  173        vectorUnderTest = img2vector("digits//testDigits//"+fileNameStr)        classifierResult = classify0(vectorUnderTest,trainingMat,hwLabels,3)        print("the classifier came back with: %d,the real answer is: %d"%(classifierResult,classNumStr))        if classifierResult != classNumStr:            errorCount += 1    print "the total number of errors is:%d" %errorCount    print "the total error rate is:%f" %(errorCount/float(mTest))

总结:

优点
1.精度高
2.对异常值不敏感
3.没有对数据的分布假设
缺点
1、knn算法不像其他算法有一个训练的过程
2、knn算法针对那些分类不均匀的分类训练样本可能误差较大
3、计算量太大,每一个待测测试样本都要遍历一遍训练样本来计算距离
4、我们无法知晓实例样本和典型实例样本具有什么特征,无法给出任何数据的基础结构信息















0 0
原创粉丝点击