机器学习—KNN算法

工作原理:给定测试样本,基于某种距离度量找出训练集中于其最靠近的K个训练样本,然后基于这K个训练样本的信息进行预测。
在分类任务中可以使用"投票法"
在回归任务中可以使用"平均法"
还可以根据距离远近进行加权平均或加权投票,距离越近样本的权重越大
没有显式的训练过程
例子一
我的朋友海伦一直使用在线约会网站寻找适合自己的约会对象。尽管约会网站会推荐不同的 人选,但她并不是喜欢每一个人。经过一番总结,她发现曾交往过三种类型的人:  不喜欢的人  魅力一般的人  极具魅力的人
示例:
在约会网站上使用k-近邻算法
(1) 收集数据:提供文本文件。
(2) 准备数据:使用Python解析文本文件。
(3) 分析数据:使用Matplotlib画二维扩散图。
(4) 训练算法:此步骤不适用于k-近邻算法。
(5) 测试算法:使用海伦提供的部分数据作为测试样本。 测试样本和非测试样本的区别在于:测试样本是已经完成分类的数据,如果预测分类 与实际类别不同,则标记为一个错误。 (6) 使用算法:产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方是否 为自己喜欢的类型。
2

from numpy import *
import operator
from os import listdir
def classify0(inX,dataSet,labels,k):
'''
inX为要测试的数据,dataSet为数据集,labels为标签
'''
    dataSetSize=dataSet.shape[0]#求出dataSet的行数
    diffMat=tile(inX,(dataSetSize ,1))-dataSet#创建一个每一行都为inX的矩阵,方便使inX与每一个数据相减来求距离
    sqdiffMat=diffMat**2#将inX与每一个数据相减的每一个属性分别求平方
    sqDistances=sqdiffMat.sum(axis=1)#按行相加即把inX的各个属性的差求和,求出inX与每个数据间的距离,形成一个列表
    distances=sqDistances **0.5#距离开根号
    sortedDisIndicies=distances .argsort()#将distances排序之后按照从大到小返回原数据的index
    classCount={}#创建一个空的字典,来储存inX附近k的个数据及他们出现的次数,用投票法求出inX属于哪个类
    for i in range(k):
        voteIlabel=labels[sortedDisIndicies [i]]#遍历求出与inX距离前k个数据
        classCount[voteIlabel]=classCount.get(voteIlabel,0)+1#统计数据出现的次数
    sortedclassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)#将字典中的数据按照数据出现的次数从大到小从排序
    return sortedclassCount [0][0]#返回inX附近k个数中出现最多的内个类,即投票法的结果
def file2matrix(filename):#读取数据,将文件里面的数据
    fr=open(filename)#打开文件
    numberOfLines=len(fr.readlines() )#求出数据的行数,以便创建returnMat
    returnMat=zeros((numberOfLines,3))
    classLabelVector=[]
    fr.seek(0,0)
    index=0
    for line in fr.readlines():#按行读取数据
        line=line.strip()#去除数据首尾的空格
        listFromLine=line.split('\t')#按’\t‘划分数据,求出包含各个特征值的列表
        returnMat[index,:]=listFromLine[0:3]#将数据的三个特征读取到returnMat上
        classLabelVector.append(int(listFromLine[-1]))#将数据的分类标签读取到classLabelVector中
        index+=1
    return returnMat,classLabelVector#返回读取出来的数据集和标签
def autoNorm(dataSet):#数据归一化
    minVals=dataSet.min(0)#求出dataSet中每一列的最小值,即返回每个特征的最小值。
    maxVals=dataSet.max(0)#求出dataSet中每一列的最大值,即返回每个特征的最大值。
    ranges=maxVals-minVals
    normDataSet=zeros(shape(dataSet))#创建一个与dataSet函数和列数都一样的矩阵
    m=dataSet.shape[0]#求出dataSet的行数,方便下一步创建一个各个特征值都为最小值的矩阵与之运算
    normDataSet=dataSet-tile (minVals,(m,1))
    normDataSet=normDataSet/tile(ranges,(m,1))
    return normDataSet,ranges,minVals#返回归一化后的矩阵
def datingClassTest():#程序的测试函数
    hoRatio=0.1
    datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')#首先读取文件
    normMat,ranges,minVals=autoNorm(datingDataMat)#将数据归一化
    m=normMat.shape[0]#求出数据集的行数
    numTestVecs=int(m*hoRatio)#求出测试集
    print('numTestVecs=',numTestVecs)
    errorCount=0.0#初始化归类错误的次数
    for i in range(numTestVecs):遍历测试集
        classifierResult=classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)#调用KNN算法函数进行分类
        print('the classifier came back with : %d,the real answer is : %d'%(classifierResult,datingLabels[i]))
        if(classifierResult!=datingLabels[i]):
            errorCount+=1#统计判断错误的个数
        print('the total error rate is: %f'%(errorCount/float(numTestVecs)))
        print('errorCount=',errorCount)
datingClassTest()

例子二
示例:使用k-近邻算法的手写识别系统
(1) 收集数据:提供文本文件。
(2) 准备数据:编写函数classify0(),将图像格式转换为分类器使用的list格式。
(3) 分析数据:在Python命令提示符中检查数据,确保它符合要求。

from numpy import *
import operator
from os import listdir
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
    sortedDisIndicies=distances .argsort()
    classCount={}
    for i in range(k):
        voteIlabel=labels[sortedDisIndicies [i]]
        classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
    sortedclassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    return sortedclassCount [0][0]
def img2vector(filename):#将图片转换成向量
    returnVect=zeros((1,1024))#创建一个1行1024列的向量
    fr=open(filename)#打开文件
    for i in range(32):#遍历每行,分别读取出每行的数据
        lineStr=fr.readline()#读取出该行的数据
        for j in range(32):#遍历第i行的每一列
            returnVect[0,32*i+j]=int(lineStr[j])#将32乘32的矩阵中的数据,读取进1乘1024的向量中去
    return returnVect#返回该向量
def handwritingClassTest():#手写识别系统的测试
    hwLabels=[]#创建一个空的标签列表
    trainingFileList=listdir('digits/trainingDigits')#列举trainingDigits中的文件名
    m=len(trainingFileList)#求出trainingDigits中文件的个数
    trainingMat=zeros((m,1024))#创建一个矩阵,其中每一行为每个文件照片的参数
    for i in range(m):#遍历m个文件
        fileNameStr=trainingFileList[i]#求出文件名
        fileStr=fileNameStr.split('.')[0]#求出文件名
        classNumStr=int(fileStr.split('_')[0])#得出该文件的分类,即这个数字是几
        hwLabels.append(classNumStr)#将该标签加入到标签列表hwLabels中
        trainingMat[i,:]=img2vector('digits/trainingDigits/%s'%fileNameStr)#将该图片读入到数据集中
    testFileList=listdir('digits/testDigits')#列举测试集中的文件列表,方便接下来进行遍历测试
    errorCount=0.0#初始化错误的数目
    mTest=len(testFileList)#求出测试集的文件数目,方便接下来进行遍历
    for i in range(mTest):#遍历测试集进行测试
        fileNameStr=testFileList[i]#读取第一个文件姓名
        fileStr=fileNameStr.split('.')[0]#读取文件名
        classNumStr=int(fileStr.split('_')[0])#读取文件类别
        vectorUnderTest=img2vector('digits/testDigits/%s'%fileNameStr)#读取文件的特征
        classifierResult=classify0(vectorUnderTest,trainingMat,hwLabels,3)#利用KNN算法进行分类
        print('the classifier came back with :%d,the real answer is :%d'%(classifierResult,classNumStr))
        if(classifierResult!=classNumStr):
            errorCount+=1
    print ('\nthe total number of errors is:%d'%errorCount)
    print('\nthe total error rate is:%f'%(errorCount/float(mTest)))
handwritingClassTest()

相关语法
.sum()函数是模块numpy的一个函数
对于二维数组
axis=1表示按行相加 , axis=0表示按列相加

·get()函数作用
以classCount.get(voteIlabel,0)为例:
classCount.get(voteIlabel,0)返回字典classCount中voteIlabel元素对应的值,若无,则进行初始化
若不存在voteIlabel,则字典classCount中生成voteIlabel元素,并使其对应的数字为0,即
classCount = {voteIlabel:0}
此时classCount.get(voteIlabel,0)作用是检测并生成新元素,括号中的0只用作初始化,之后再无作用
当字典中有voteIlabel元素时,classCount.get(voteIlabel,0)作用是返回该元素对应的值,即0

·operator.itemgetter函数
operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号(即需要获取的数据在对象中的序号)(operator.itemgetter函数获取的不是值,而是定义了一个函数,通过该函数作用到对象上才能获取值。)

·sorted函数 sorted(iterable[, cmp[, key[, reverse]]])
Python内置的排序函数sorted可以对list或者iterator进行排序
(1)iterable指定要排序的list或者iterable
(2)cmp为函数,指定排序时进行比较的函数,可以指定一个函数或者lambda函数

·zeros(shape, dtype=float, order=‘C’)
返回:返回来一个给定形状和类型的用0填充的数组;
参数:shape:形状
dtype:数据类型,可选参数,默认numpy.float64

·Python strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
注意:该方法只能删除开头或是结尾的字符,不能删除中间部分的字符。

·min(0),max(0) python 矩阵中的用法
min(0)返回该矩阵中每一列的最小值
min(1)返回该矩阵中每一行的最小值
max(0)返回该矩阵中每一列的最大值
max(1)返回该矩阵中每一行的最大值

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值