KNN

KNN 算法原理

1、假设有一个带有标签的样本数据集(训练样本集),x_i表示第i个样本,包括m个特征和对应的标签y_i,可表示为x_i1、x_i2、、、x_im、y_i,假设整个训练样本数据集包括n个样本,则整个带有标签的样本数据集可表示成一个n行m+1列的矩阵X。
2、输入一个没有标签的测试数据后,将新数据的每个特征与训练样本集中每个样本对应的特征进行比较。如某测试数据的特征向量为(1,0,0,1),某训练样本数据特征向量为(2,3,0,1),则进行比较的方式是采用欧式距离进行计算, ( 1 − 2 ) 2 + ( 0 − 3 ) 2 + ( 0 − 0 ) 2 + ( 1 − 1 ) 2 \sqrt{(1-2)^2+(0-3)^2+(0-0)^2+(1-1)^2} (12)2+(03)2+(00)2+(11)2
3、计算新数据与样本数据集中每条数据的距离。
4、对求得的所有距离进行排序(从小到大,越小表示越相似)。取前 k (k 一般小于等于 20 )个样本数据对应的分类标签。
5、求 k 个数据中出现次数最多的分类标签作为新数据的分类。
KNN 通俗理解:给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的 k 个实例,这 k 个实例的多数属于某个类,就把该输入实例分为这个类。

KNN项目案例一:优化约会网站的配对效果

1、收集数据:提供文本文件

海伦把这些约会对象的数据存放在文本文件 datingTestSet2.txt 中,总共有 1000 行。海伦约会的对象主要包含以下 3 种特征:每年获得的飞行常客里程数、玩视频游戏所耗时间百分比、每周消费的冰淇淋公升数
文本文件.txt数据格式如下(最后一列为相应样本的标签表示对约会对象的喜欢程度):
40920 8.326976 0.953952 3
14488 7.153469 1.673904 2
26052 1.441871 0.805124 1
75136 13.147394 0.428964 1
38344 1.669788 0.134296 1

2、准备数据:使用 Python 解析文本文件(提取成训练样本数据矩阵,以及相应的标签向量)
def file2matrix(filename):
   """
   Desc:
       导入训练数据
   parameters:
       filename: 数据文件路径
   return: 
       数据矩阵 returnMat 和对应的类别 classLabelVector
   """
   fr = open(filename)
   # 获得文件中的数据行的行数
   numberOfLines = len(fr.readlines())
   # 生成对应的空矩阵
   # 例如:zeros(2,3)就是生成一个 2*3的矩阵,各个位置上全是 0 
   returnMat = zeros((numberOfLines, 3))
   #3列是由于数据文件的前三列为特征数据,第4列为标签 
   classLabelVector = []  
   fr = open(filename)
   index = 0
   for line in fr.readlines():
       line = line.strip()
       # str.strip([chars]) --返回已移除字符串头尾指定字符所生成的新字符串
       listFromLine = line.split('\t')# 以 '\t' 切割字符串
       returnMat[index, :] = listFromLine[0:3]
       classLabelVector.append(int(listFromLine[-1]))
       # 每行的最后一列为类别数据,就是 label 标签数据
       index += 1
   # 返回数据矩阵returnMat和对应的类别classLabelVector
   return returnMat, classLabelVector
3、归一化数据:消除特征之间量级不同导致的影响

如下面式子 ( 0 − 67 ) 2 + ( 20000 − 32000 ) 2 + ( 1.1 − 0.1 ) 2 \sqrt{(0-67)^2 + (20000-32000)^2 + (1.1-0.1)^2 } (067)2+(2000032000)2+(1.10.1)2
在这里插入图片描述

def autoNorm(dataSet):
    """
    Desc:
        归一化特征值,消除特征之间量级不同导致的影响
    parameter:
        dataSet: 数据集
    return:
        归一化后的数据集 normDataSet. ranges和minVals即最小值与范围,并没有用到

    归一化公式:
        Y = (X-Xmin)/(Xmax-Xmin)
        其中的 min 和 max 分别是数据集中的最小特征值和最大特征值。该函数可以自动将数字特征值转化为0到1的区间。
    """
    minVals = dataSet.min(0)
    # 0表示列,1表示行。计算每种属性即每一列的最大值、最小值、范围
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet)#输出dataset矩阵的行数和列数)
    m = dataSet.shape[0]#取矩阵的行数
    normDataSet = dataSet - tile(minVals, (m, 1))
    ### 要实现两个矩阵相减,需要将minVals向量进行行数重复m次列数重复1次即达到和dataset维度相同
    normDataSet = normDataSet / tile(ranges, (m, 1))  # element wise divide
    return normDataSet, ranges, minVals
4、KNN算法分类实现
def classify0(inX, dataSet, labels, k):
    #inx是新的测试数据,dataSet为整个训练样本数据矩阵,labels为相应训练样本标签
    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()
    #x=np.array([1,4,3,-1,6,9]),x.argsort()函数是将x中的元素从小到大排列,提取其对应的index(索引),然后输出到y,y=array([3,0,2,1,4,5])。例如:x[3]=-1最小,所以y[0]=3,x[5]=9最大,所以y[5]=5。
    classCount={}
    for i in range(k)#选取前K个最短距离, 选取这K个中最多的分类类别
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 
    sortedClassCount =sorted(classCount.items(),key=operator.itemgetter(1),
    reverse=True)
    return sortedClassCount[0][0]
5、kNN 分类器针对约会网站的测试代码
def datingClassTest():
    """
    Desc:
        对约会网站的测试方法
    parameters:
        none
    return:
        错误数
    """
    # 设置测试数据的的一个比例(训练数据集比例=1-hoRatio)
    hoRatio = 0.1  # 测试范围,一部分测试一部分作为样本
    # 从文件中加载数据
    datingDataMat, datingLabels = file2matrix('data/2.KNN/datingTestSet2.txt')  # load data setfrom file
    # 归一化数据
    normMat, ranges, minVals = autoNorm(datingDataMat)
    # m 表示数据的行数,即矩阵的第一维
    m = normMat.shape[0]
    # 设置测试的样本数量, numTestVecs:m表示训练样本的数量
    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)
        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)

KNN项目案例二: 手写数字识别系统

在案例一的基础上只需要再定义合适的函数就可以直接用

1、将图像文本数据转换为向量

案例二的每个样本数据是32x32的文本数据,因此需要将其转化为案例一适用的list类型,即将每个样本的32x32的二进制图像矩阵转换成1x1024的向量

def img2vector(filename):
    returnVect = zeros((1,1024))
    fr = open(filename)
    for i in range(32):
        lineStr = fr.readline()
        for j in range(32):
            returnVect[0,32*i+j] = int(lineStr[j])
    return returnVect
2、进行测试
def handwritingClassTest():
    # 1. 导入训练数据
    hwLabels = []
    trainingFileList = listdir('data/2.KNN/trainingDigits')  # 获取该目录下的文件夹名称。如9—22.txt表示数字9的第22个样本
    m = len(trainingFileList)
    trainingMat = zeros((m, 1024))
    # hwLabels存储0~9对应的index位置, trainingMat存放的每个位置对应的图片向量
    for i in range(m):
        fileNameStr = trainingFileList[i]
        fileStr = fileNameStr.split('.')[0]  # take off .txt
        classNumStr = int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        # 将 32*32的矩阵->1*1024的矩阵
        trainingMat[i, :] = img2vector('data/2.KNN/trainingDigits/%s' % fileNameStr)

    # 2. 导入测试数据
    testFileList = listdir('data/2.KNN/testDigits')  # iterate through the test set
    errorCount = 0.0
    mTest = len(testFileList)
    for i in range(mTest):
        fileNameStr = testFileList[i]
        fileStr = fileNameStr.split('.')[0]  # take off .txt
        classNumStr = int(fileStr.split('_')[0])
        vectorUnderTest = img2vector('data/2.KNN/testDigits/%s' % 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.0
    print("\nthe total number of errors is: %d" % errorCount)
    print("\nthe total error rate is: %f" % (errorCount / float(mTest)))

KNN.py文件下加入主函数运行上述两个案例

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值