K邻近算法

(一)算法基本思想

KNNKNNKNN是一种常用的监督学习方法。给定测试样本,基于某种距离度量找出训练集中与其最靠近的kkk个训练样本,然后基于这kkk个邻居的信息来进行预测。使用投票法,选择kkk个样本中出现最多的类别标记作为预测结果,这kkk个实例的多数属于某类,就把该输入实例分为哪类。也可以基于距离远近进行加权平均,距离越近样本权重越大。
kkk值的选择、距离的度量、以及分类决策规则是kkk邻近算法三个基本要素。

(二)算法实现

输入:训练数据集T=[(x1,y1),(x2,y2),...,(xn,yn)]T={[(x_1,y_1),(x_2,y_2),...,(x_n,y_n)]}T=[(x1,y1),(x2,y2),...,(xn,yn)],xix_ixi为特征向量,yiy_iyi为实例类别。
输出:实例xxx所属的类别yyy

(1)

根据给定的距离度量,在训练集TTT中找出与xxx最邻近的kkk个点;

(2)

kkk个点中进行分类表决,少数服从多数原则,决定xxx的类别yyyy=argmax∑xI(yi=cj)y=argmax\sum_xI(y_i=c_j)y=argmaxxI(yi=cj),选择相应数目最多的类别。当k=1k=1k=1时,称为最邻近算法。

kkk邻近模型

(1)模型

当训练集、距离度量、kkk值以及分类决策规则确定后,对于任何一个新的输入实例,它所属的类唯一的确定。

(2)距离度量

使用的距离一般是欧式距离。Lp=(∑l=1n∣xi(l)−xj(l)∣p)1pL_p={(\sum_{l=1}^n|x_i^{(l)}-x_j^{(l)}|^p)^{\frac{1}{p}}}Lp=(l=1nxilxjlp)p1;当p=2p=2p=2时,为欧式距离。当p=1p=1p=1时,为曼哈顿距离。

(3)kkk值的选择

kkk值较小,学习的近似误差会减小,估计误差会增大,意味着整体模型变得更复杂,容易发生过拟合;若kkk值较大,可以减少学习的估计误差,但近似误差会变大,但意味着整体的模型变得简单。在实际中,kkk值一般选择一个比较小的数值。

(4) 分类决策规则

分类误差率为:1k∑xI(yi&lt;&gt;cj)=1−1k∑xI(yi=cj)\frac{1}{k}\sum_x{I(y_i&lt;&gt;c_j)=1-\frac{1}{k}}\sum_x{I(y_i=c_j)}k1xI(yi<>cj)=1k1xI(yi=cj)
要使分类误差率最小,即经验风险最小,就要使∑xI(yi=cj)\sum_xI(y_i=c_j)xI(yi=cj)最大,所以多数表决规则等价于经验风险最小化。

kkk邻近代码实现

# -*- coding: UTF-8 -*-
                
import numpy as np
import operator
from os import listdir
global nums
             
def classify0(inX, dataSet, labels, k):
                        #numpy函数shape[0]返回dataSet的行数
        dataSetSize = dataSet.shape[0]
                        #在列向量方向上重复inX共1次(横向),行向量方向上重复inX共dataSetSize次(纵向)
        diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
                        #二维特征相减后平方
        sqDiffMat = diffMat**2
                        #sum()所有元素相加,sum(0)列相加,sum(1)行相加
        sqDistances = sqDiffMat.sum(axis=1)
                        #开方,计算出距离
        distances = sqDistances**0.5
                        #返回distances中元素从小到大排序后的索引值
        sortedDistIndices = distances.argsort()
                        #定一个记录类别次数的字典
        classCount = {}
        for i in range(k):
                                #取出前k个元素的类别
                voteIlabel = labels[sortedDistIndices[i]]
                                #dict.get(key,default=None),字典的get()方法,返回指定键的值,如果值不在字典中返回默认值。
                                #计算类别次数
                classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
                        #python3中用items()替换python2中的iteritems()
                        #key=operator.itemgetter(1)根据字典的值进行排序
                        #key=operator.itemgetter(0)根据字典的键进行排序
                        #reverse降序排序字典
                sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
                        #返回次数最多的类别,即所要分类的类别
        return sortedClassCount[0][0]

def file2vector(filename):
        fr = open(filename)
        arrayOLines=fr.readlines()
        numberOfLines=len(arrayOLines)
        nums=numberOfLines
        returnMat=np.zeros((numberOfLines,16))
        classLabelVector=[]
        index=0
        for line in arrayOLines:
                line=line.strip()
                listFromLine=line.split(',')
                returnMat[index,:]=listFromLine[1:17]
                classLabelVector.append(listFromLine[0])
                index+=1
        return returnMat,classLabelVector

def alphabetClassTest():
        trainingMat,alLabels=file2vector("trainingData.txt")
        errorCount = 0.0
        with open("testingData.txt",'r',encoding='utf-8') as f:
                arrays=f.readline()
                while arrays:
                        testMat=np.zeros((1,16))
                        teLabels=[]
                        inde=0
                        l=arrays.strip()
                        llist=l.split(',')
                        for i in range(1,17):
                                testMat[0,inde]=llist[i]
                                inde+=1
                        teLabels.append(llist[0])
                        classifierResult = classify0(testMat, trainingMat, alLabels, 5)
                        print("分类返回结果为%s\t真实结果为%s" % (classifierResult, teLabels[0]))
                        if(classifierResult != teLabels[0]):
                                errorCount += 1.0
                        arrays=f.readline()
        print("总共4000,错了%d个数据\n正确率为%f%%" % (errorCount, (1-(errorCount)/4000)*100))


if __name__ == '__main__':
        alphabetClassTest()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值