《机器学习实战》— k-近邻算法

目录

 

一、算法主要适用情形

二、算法主要实现思路

三、代码实现

1、引入numpy及后续读取目录需要引入的

2、创建数据集和标签

3、k-邻近分类算法

4、测试(0,0)的分类结果

四、应用一:使用k-邻近算法改进约会网站的配对效果

1、算法步骤

2、代码实现

(1)读取数据文件,把数据划分特征值矩阵和标签矩阵

          (2)归一化特征值

(3)测试代码:源数据为datingTestSet2.txt

(4)运行上述函数,输出结果

五、应用二:手写识别算法

1、算法描述

2、代码实现

(1)准备数据:将图像转换为测试向量

(2)使用k-近邻算法的手写识别系统

(3)运行上述函数测试


一、算法主要适用情形

1、优缺点:精度高、对异常数值不敏感、无数据输入绑定,但是计算复杂度较高,空间复杂度高

2、适用类型:数值型、标称型

3、计算公式:

4、计算两点之间的距离:

二、算法主要实现思路

【注意:一般我们只选择样本数据中前k个最相似数据,通常k是不大于20的整数】

第一步:导入源数据,分离出特征值和标签

第二步:计算用于分类的输入向量与源数据文件特征向量之间的距离

第三步:对上述距离按照从小到大的顺序进行排序

第四步:算则距离最小的k个特征向量

第五步:找出这k个特征向量对应标签出现频率最高的作为分类结果

三、代码实现

1、引入numpy及后续读取目录需要引入的

#导入数据
from numpy import *
import operator
from os import  listdir

2、创建数据集和标签

#创建数据集和标签
def createDataSet():
    group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels = ['A','A','B','B']
    return group, labels

3、k-邻近分类算法

#k-近邻算法
#计算距离
#inX:用于分类的输入向量
#dataSet:输入的训练样本集
#labels:标签向量
#k:用于选择最近邻居的数目
def classify0(inX, dataSet, labels, k):
    #=====计算距离=====
    dataSetSize = dataSet.shape[0]  #shape读取数据矩阵第一维度的长度--4
    #[[-1.  -1.1],[-1.  -1. ],[ 0.   0. ],[ 0.  -0.1]]
    diffMat = tile(inX,(dataSetSize,1)) - dataSet #tile重复数组inX,有dataSetSize行 1个dataSet列,减法计算差值
    #[[1.   1.21],[1.   1.  ], [0.   0.  ],[0.   0.01]]
    sqDiffMat = diffMat**2  #**是幂运算的意思,这里用的欧式距离
    sqDistances = sqDiffMat.sum(axis=1) #普通sum默认参数为axis=0为普通相加,axis=1为一行的行向量相加
    distances = sqDistances**0.5
    sortedDistIndicies = distances.argsort()#argsort返回数值从小到大的索引值(数组索引0,1,2,3)
    classCount={}
    #=====选择距离最小的k个点=====
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]] #根据排序结果的索引值返回靠近的前k个标签
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #各个标签出现频率
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)#排序频率
    return sortedClassCount[0][0]#找出频率最高的

4、测试(0,0)的分类结果

import knn
from numpy import *
#获得已知数据集
group,labels=knn.createDataSet()
a=knn.classify0([0, 0], group, labels, 2)
print(a)

四、应用一:使用k-邻近算法改进约会网站的配对效果

1、算法步骤

第一步:读取数据文件,把数据划分特征值矩阵和标签矩阵

第二步:;归一化特征值,将数字特征值转化到0到1的区间

第三步:按照上述k-邻近算法计算前k个与待求特征向量距离最近的特征向量,返回出现频率最高的分类标签

2、代码实现

(1)读取数据文件,把数据划分特征值矩阵和标签矩阵

#用来从文件中加载数据:把文件中的数据划分为特征值矩阵returnMat和标签矩阵classLabelVector分别返回
def file2matrix(filename):
    fr=open(filename) #打开文件并且获取数据
    arrayOLines=fr.readlines()
    numberOfLines=len(arrayOLines)#读出数据行数
    returnMat=zeros((numberOfLines,3)) #准备返回矩阵,numberOfLine行,3列
    classLabelVector=[] #准备结果标签
    index=0
    for line in arrayOLines:
        line=line.strip() #删除空白符
        listFromLine=line.split("\t")#split指定分隔符对数据切片
        returnMat[index,:]=listFromLine[0:3]#选取前3个元素(特征)存储在返回矩阵中
        classLabelVector.append(int(listFromLine[-1])) #-1索引表示最后一列元素,位label信息存储在classLabelVector
        index += 1
    return returnMat,classLabelVector #返回矩阵和标签

(2)归一化特征值

#归一化特征值,将数字特征值转化到0到1的区间
#归一化公式  :归一化后的值=(当前值-最小值)/(最大值-最小值)
def autoNorm(dataSet):
    minVals = dataSet.min(0)#存放每列最小值,参数0使得可以从列中选取最小值,而不是当前行
    maxVals = dataSet.max(0)#存放每列最大值
    ranges = maxVals - minVals
    #[[0. 0.],[0. 0.],[0. 0.], [0. 0.]]
    normDataSet = zeros(shape(dataSet))#初始化归一化矩阵为读取的dataSet格式
    m = dataSet.shape[0]#m保存数据项数--4
    # 特征矩阵是3x1000,min max range是1x3 因此采用tile将变量内容复制成输入矩阵同大小
    #最小值minVals是0,利用tile()函数将变量内容复制成输入矩阵同大小tile(minVals, (m,1):[[0. 0.],[0. 0.],[0. 0.],[0. 0.]]
    normDataSet = dataSet - tile(minVals, (m,1))
    normDataSet = normDataSet/tile(ranges, (m,1))
    return normDataSet, ranges, minVals

(3)测试代码:源数据为datingTestSet2.txt

#测试约会网站分类结果代码
def datingClassTest():
    hoRatio = 0.10      #hold out 10%
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')  #分类特征值和标签并存为矩阵
    normMat, ranges, minVals = autoNorm(datingDataMat)  #归一化特征值
    m = normMat.shape[0]  #样本总数量
    numTestVecs = int(m*hoRatio) #计算测试样本的数量;90%训练样本、10%测试样本
    errorCount = 0.0  #错误率初始化为0
    for i in range(numTestVecs):
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]))
        if (classifierResult != datingLabels[i]):
            errorCount += 1.0
    print ("the total error rate is: %f" % (errorCount/float(numTestVecs)))
    print (errorCount)

(4)运行上述函数,输出结果

五、应用二:手写识别算法

1、算法描述

第一步:准备数据:将图像转换为测试向量(由于数据格式较为特殊,因此需要先进行转化)

               每个txt文件用矩阵来表示一个汉字,读取这个文件,转化为一个1xn的矩阵存储

第二步:分别读取目录中的所有训练文件和测试文件,其实质同上

2、代码实现

(1)准备数据:将图像转换为测试向量

文件格式:

#准备数据:将图像转换为测试向量---img2vector
#将一个32x32的二进制矩阵转化为1x1024的向量,这样上述的分类器就可以处理数字图像信息了
def img2vector(filename):
    returnVect = zeros((1,1024))
    fr=open(filename)
    for i in range(32):  #循环读出32行
        lineStr=fr.readline()
        for j in range(32):  #每行的头32个字符值存储在Numpy数组中
            returnVect[0,32*i+j] = int(lineStr[j])
    return returnVect

(2)使用k-近邻算法的手写识别系统

#使用k-近邻算法的手写识别系统
def handwritingClassTest():
    hwLabels = []
    trainingFileList = listdir(r'trainingDigits')  #将该文件目录中的文件内容存储在列表中
    m=len(trainingFileList) #有多少文件
    trainingMat = zeros((m, 1024)) #创建一个m行1024列的训练矩阵,矩阵中的每个数据项是1024列,该矩阵的每行数据存储一个图像
    for i in range(m):
        fileNameStr=trainingFileList[i]
        fileStr=fileNameStr.split(".")[0]
        classNameStr=int(fileStr.split("_")[0])
        hwLabels.append(classNameStr)  #该目录下的文件按照规则命名,如文件9_18.txt的分类是9,它是数字9的第18个实例,将类代码存储在hwLabels中
        trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
    #开始测试
    testFileList=listdir('testDigits')
    errorCount=0.0
    mTest=len(testFileList)
    for i in range(mTest):
        fileNameStr=testFileList[i]
        fileStr = fileNameStr.split('.')[0]
        classNumStr = int(fileStr.split('_')[0])
        vectorUnderText=img2vector('testDigits/%s' % fileNameStr)
        classifierResult=classify0(vectorUnderText,trainingMat,hwLabels,3)
        print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr))
        if (classifierResult != classNumStr): errorCount += 1.0
    print("\nthe total number of errors is: %d" % errorCount)
    print( "\nthe total error rate is: %f" % (errorCount / float(mTest)))

(3)运行上述函数测试

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值