机器学习系列-k-nearestneighbo

哇小明 哇小明     2022-08-18     417

关键词:


这是记录自学的过程,目前的理论基础就是:大学高等数学+线性代数+概率论。编程基础:C/C++,python
在观看机器学习实战这本书,慢慢介入。相信有读过以上三门课的人完全可以开始自学机器学习了,当然我上面这三门课学的一般,所以你只知道有这么一个公式或名词,不懂可以百度之深究之。在写这篇文章的时候作者机器学习还没学完,故文章中的错误还请不吝指出。再次声明,系列文章只是分享学习过程,学习点滴,不能保证文章的技术含量。后续再技术的不断完善中,我会重新再捋一遍这个学习过程,纠正其中错误。
目前的学习方法如下:
理论:斯坦福Andrew NG machine learning,系列课程。
代码实战:引用书籍 机器学习实战(python)。
真枪实战: 研究一个案例,建模选择合适的机器学习算法,分析数据。
演变:基于C/C++ 在linux下实现部分机器学习过程。将在学习中期阶段去实现。


一、K近邻算法的概念


 K近邻算法(kNN)属于一种分类的算法,与逻辑回归属于同一种。它的工作原理是:存在一组样本数据,它们的每一个样本的组成由若干个特征和一个既定的label与之对应,label也就是标明了这个样本点属于哪个分类,如果是简单的二元分类,那么label可以假设为1或0,以此类推。如果输入新的数据,而算法的目的就是输出新的数据的标签。这个新的数据将会和样本集合中的每个数据进行对比(求两个样本点之间的距离),对比的结果从小排到大,取前k个对比结果,当中出现次数最多的分类就是该新数据的分类。


近邻算法的优缺点:

1.优点:

精度高,对异常值不敏感,无数据输入的假定

2.缺点:

计算复杂度高,空间复杂度高。

3.使用数据范围:

数值型和标称型。

二、k近邻算法简单例子

伪代码:

1.计算样本集合中的已知点与当前点之间的距离
2.按照距离递增的顺序排序
3.选择排序中与当前点距离最近的前k个样本数据
4.计算出每个分类的样本个数并计算频率
5.返回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()     
    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]

==深入分析:==

1.dataSetSize = dataSet.shape[0].计算出dataSet 矩阵的行数。
2.diffMat = tile(inX, (dataSetSize,1)) - dataSet 这边主要是将输入数据分别与样本进行相减,这边pyth tile的用法我用自己的理解总结了一下:


上网查了下tile用法的教程,发现看的有点吃力,于是自己亲自研究了一下然后发现可以这理解,与大家分享一下,有什么错误的地方请大家指出:
1.tile的用法总结:

定义:tile(A,R),A和R都可以是数组或者普通单个数据。结果是将A重复R,具体有以下几种机制:

假设:
tile([a1,a2,…,an],[r1,r2,…,rn])=B
得到的结果B的一些属性是由R来决定的,B的第一维数就是r1,第二维数就是r2,…..,B的每一维由重复A数组rn遍的结果组成。当R的长度为1时(类似(1,2)长度2,(1,2,3)长度3,(3)长度为1),此时R控制维数。

例子1.
tile([1,2],2)=
array([1,2],
   [1,2]);

tile([1,2],4)=
array([1,2],
[1,2],
[1,2],
[1,2]);

tile([1,2],(1,2))= //1决定结果只是一维,2决定重复A(1,2)两遍
array([[1,2,1,2]])

tile([1,2],(3,3))= //3决定结果是三维,后面的三决定将重复(1,2)三遍
array([[1,2,1,2,1,2],
[1,2,1,2,1,2],
[1,2,1,2,1,2]])

tile([1,2],(2,2,2)) //第一个2决定结果将是一个2维,第二个2决定2为中的每一维都是一个2维,最后一个2决定最里面的维度的元素将是重复两遍A(1,2)的结果,层层嵌套。

结果:
array([[[1, 2, 1, 2],
    [1, 2, 1, 2]], //这里是维度分界线,注意中括号个数

   [[1, 2, 1, 2],
    [1, 2, 1, 2]]])

以此类推。


3.sqDiffMat = diffMat**2 //把刚才得到的结果求平方  
4.sqDistances = sqDiffMat.sum(axis=1)  
    distances = sqDistances**0.5  //这两句的意思是将求平方后的结果相加,然后结果开方  
5.sortedDistIndicies = distances.argsort()  //把求到的输入数据和每个点之间的距离进行递增排序,argsort返回的是每个数据的index。

6.for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1  
        //总体的作用选取距离最小的K个点。for循环中的第一句:sortedDistIndicies[i]记录着一排index比如(2,3,0,1)  
        //2代表dataSet中的index为2的数据距离输入数据距离最短,以此类推,1代表最长。由于dataSet和labels是对应  
        //的,所以当i从0>>k时,会找到最小的那几个数据所对应的lable值。第二行就进行对这些label进行分类计数,并  
        //保存在classCount中  

7.sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)  
//以上是对一个有多个类型的数据进行排序的函数,总之作用就是把刚才得到的保存有距离最短的k个数据中每一个label出现  
//个数的数组进行从大到小排序,最后结果被保存在sortedClassCount中,第一个元素就是前K个数据中频率最高的label  sortedClassCount[0][0]  ,关于sorted的用法详见附录1.

三、k近邻算法的实际应用-约会网站的预测

背景我就不细细描述了,总之目的就是输入一个数据,这个数据包含三个特征:1.每年获得的飞行常客里程数2.玩视频游戏所耗时间百分比3.每周消费的冰淇淋公升数。通过这三个特征对数据进行分类,当然原理还是计算这个数据和其他数据的距离,不同的是这次是三维空间中的距离了。

1.第一步:解析数据。
我们先看下数据的特点:

这里写图片描述

第一列是飞行里程数,第二列是游戏时间所占百分比,第三列是吃冰淇淋的公升数。第四列是lable值,有三种:不喜欢,魅力一般,极具魅力。书中提供了解析数据的代码,目的就是把这些数据规律性的输入到一个数组中,方便后面处理,具体代码:


def file2matrix(filename):
    fr = open(filename)
    numberOfLines = len(fr.readlines())         #get the number of lines in the file
    returnMat = zeros((numberOfLines,3))        #prepare matrix to return
    classLabelVector = []                       #prepare labels return   
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index,:] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat,classLabelVector

上面代码运行过程如下:
输入:datingDataMat,dataingLabels = kNN.file2matrix(‘datingTestSet2.txt’) 记住这边参数是datingTestSet2.txt,书本那种会报错误:

==ValueError: invalid literal for int() with base 10: ‘largeDoses’ ==

然后在看看换算的结果:
datingDataMat:

这里写图片描述

label的结果:

这里写图片描述

这样子数据就从文件导成我们需要的格式了,后面就开始用算法来处理这些数据。

2.第二步:归一化数值:
如上图数据所示第一列数据与后面两列差了10的4次方级别,这会导致在求点和点的距离的时候,加减运算时,第二第三列的数据影响效果大大减小,甚至不起作用。所以这边要把所有数据之按照一定的计算方式归一化到0-1之间,这样数据之间的加减运算才会有意义。

下面的公式可以将数据转化到0-1之间:

newValue = (oldValue - minValue)/(maxValue - minValue)

其中minValue和maxValue分别是数据中的最小值和最大值。

用python代码实现如下:

def autoNorm(dataSet):
    minVals = dataSet.min(0) //获得dataSet中每列的最小值保存到minVals
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet - tile(minVals, (m,1)) //oldValue-minValue
    normDataSet = normDataSet/tile(ranges, (m,1))   #element wise divide
    return normDataSet, ranges, minVals

运行结果如下:
这里写图片描述

3.第三步:测试算法

直接撸代码:

def datingClassTest():
    hoRatio = 0.10      #hold out 10%
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')       #load data setfrom file
    normMat, ranges, minVals = autoNorm(datingDataMat)
    m = normMat.shape[0]
    numTestVecs = int(m*hoRatio)
    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))

前面两句主要是从文件加载数据然后再进行归一化转换。m = normMat.shape[0] 算出来的是数据的总个数,后面取出的测试数据的个数就是由 numTestVecs = m*hoRatio ,这边hoRatio为0.1也就是说测试数据取10%。然后将测试数据和已有的数据还有label值分别输入分类器classfy0中,这个函数前面已经分析过。这边输入的第一个参数为待测试的数据:normMat[i,:],这个表达式的意思是取normMat的第i行数据,直到numTestVecs比如:

normMat[0,:]
array([ 0.44832535, 0.39805139, 0.56233353])

normMat[1,:]
array([ 0.15873259, 0.34195467, 0.98724416])

第二个参数:datingLabels[numTestVecs:m],表示一直数据从第numTestVecs行开始取知道结尾,前面的都是待测数据。

下面是运行的结果:

这里写图片描述

可以看到最后的错误率是6.4%,这是一个不错的结果。在此,我们可以通改变hoRotio和变量k的值,来观察错误率的变化情况。

上述只是测试算法,数据直接从现有的数据中取出来的,下面构建完整的算法系统:

下面是完整代码:

def classifyPerson():
    resultList = ['not at all','in small doses','in large doess']
    percentTats = float(raw_input("percentage of time spent playing video games?"))
    ffMiles = float(raw_input("frequent flier miles earned per year?"))
    iceCream = float(raw_input("liters of ice cream consumed per year?"))

    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
    normMat,ranges,minVals = autoNorm(datingDataMat)
    inArr = array([ffMiles,percentTats,iceCream])

    classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3)

    print "you will probably like this person:",resultList[classifierResult - 1]

第一行是标签数组化,有三个类别。
2-4行 分别要求输入玩游戏占用时间比、飞行里程数、消费冰淇淋公升数。

接下来两行就是将数据从文件中转化出来并归一化保存的过程。

最后就是输入分类器进行分类,返回分类结果。

下面是运行结果:

这里写图片描述

附录1:
sorted
sorted函数
Python内置的排序函数sorted可以对list或者iterator进行排序,官网文档见:http://docs.python.org/2/library/functions.html?highlight=sorted#sorted,该函数原型为:

sorted(iterable[items[], cmp, key, reverse)

参数解释:

(1)iterable指定要排序的list或者iterable,不用多说;

(2)cmp为函数,指定排序时进行比较的函数,可以指定一个函数或者lambda函数,如:

  students为类对象的list,没个成员有三个域,用sorted进行比较时可以自己定cmp函数,例如这里要通过比较第三个数据成员来排序,代码可以这样写:
  students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
  sorted(students, key=lambda student : student[2])

(3)key为函数,指定取待排序元素的哪一项进行排序,函数用上面的例子来说明,代码如下:
sorted(students, key=lambda student : student[2])

  key指定的lambda函数功能是去元素student的第三个域(即:student[2]),因此sorted排序时,会以students所有元素的第三个域来进行排序。

有了上面的operator.itemgetter函数,也可以用该函数来实现,例如要通过student的第三个域排序,可以这么写:
sorted(students, key=operator.itemgetter(2))
sorted函数也可以进行多级排序,例如要根据第二个域和第三个域进行排序,可以这么写:
sorted(students, key=operator.itemgetter(1,2))

即先跟句第二个域排序,再根据第三个域排序。
(4)reverse参数就不用多说了,是一个bool变量,表示升序还是降序排列,默认为false(升序排列),定义为True时将按降序排列。

机器学习系列1-学习资料和学习路线

该系列是学习机器学习的系列博客,主要用于记录和分享学习机器学习(和深度学习)过程中的各种知识和问题,希望能够将自己学习到的知识、方法论转化为文字,分享给更多有志于从事机器学习相关工作或学习的同学。学习... 查看详情

机器学习系列_机器学习路线图(附资料)

...有,转载请联系作者并注明出处1.引言也许你和这个叫『机器学习』的家伙一点也不熟,但是你 查看详情

机器学习数学系列:机器学习与数学基础知识

目录:机器学习基础:  机器学习的分类与一般思路微积分基础:  泰勒公式,导数与梯度概率与统计基础:  概率公式、常见分布、常见统计量线性代数基础:  矩阵乘法的几何意义  这是一张非常著名的图,... 查看详情

机器学习基础环境部署|机器学习系列(代码片段)

...Spyder配置与使用安装PyTorch总结前言本文主要是分享一下机器学习初期,基本的环境搭建。也适用于其他python工程化项目环境搭建。都差不多。Anaconda安装anaconda官方链接:Anaconda|TheWorld'sMostPopularDataSciencePlatform点 查看详情

机器学习相关的awesome系列

IndexAwesome备注1AwesomeMachineLearning机器学习资源大全中文版2Awesome ArtificialIntelligence人工智能3AwesomeAwesomenessAwesomeAwesome的平方,还有个立方但是不经典4AwesomeDeepLearning深度学习5AwesomeVeryDeepLearning非常深的深度学习6AppliedD 查看详情

机器学习入门复习1机器学习导论

...系列实验,导致其他系列暂时无法得到及时更新。【机器学习入门复习】系列是学习coursera上AndrewNg的机器学习课程所做的及时总结,以防遗漏。----------------------------------------------------------------------------------------------------... 查看详情

机器学习导图系列:过程

机器学习导图系列教程旨在帮助引导开发者对机器学习知识网络有一个系统的概念,其中有些具体释义并未完善,需要开发者自己探索才能对具体知识有深入的掌握。本项目灵感来自DanielFormoso的github开源项目。本文作者对其项... 查看详情

机器学习技术系列:一篇图文笔记了解机器学习基础知识

导言最近有小半年由近半数工作和生活时间在机器学习技术(ML)的学习与工程实践中,感觉自己阅读了几本ML方面好书,找到了一些更好的学习网站,所以重新梳理了一下自己理解的的ML基础知识。相关参考摘录书籍及网站如下... 查看详情

索引::机器学习方法系列,深度学习方法系列,三十分钟理解系列等

...et/xbinworld。技术交流QQ群:433250724,欢迎对算法、机器学习技术感兴趣的同学加入。纯技术交流。以下是我利用业余时间在自己博客中写的文章,主要是一些基础、经典,并且公开的算法整理。我写博客的目的一... 查看详情

spark入门实战系列--8.sparkmllib(上)--机器学习及sparkmllib简介

 Spark入门实战系列--8.SparkMLlib(上)--机器学习及SparkMLlib简介 1、机器学习概念1.1 机器学习的定义在维基百科上对机器学习提出以下几种定义:l“机器学习是一门人工智能的科学,该领域的主要研究对象是人工智能,... 查看详情

机器学习系列-adaboost

集成学习在一般经验中,如果把好坏不等的东西掺到一起,那么通常结果会是比最坏的要好一些,比最好的要坏一些。这就是集成学习的出发点。如果把多个学习器结合起来,是否能获得比最好的单一学习器更好的性能呢?集成... 查看详情

吴恩达《机器学习系列课程》学习笔记:监督学习

...f0c;不过看着还是有些云里雾里,倒是杉山将的《图解机器学习》介绍得更易懂些。在此进行结合学习。杉山将是这么通俗地定义监督学习、无监督学习和强化学习,它们是机器学习的主要种类:监督学习:有求知... 查看详情

数据科学机器学习系列3机器学习的流程

...试试😂一、课程简介        构建、使用和维护机器学习模型及其所使 查看详情

机器学习入门系列01,introduction简介

我们将要学习什么东东?什么是机器学习?有右边这样非常大的音频数据集,写程序来进行学习,然后可以输出音频“Hello”有右边这样非常大的图片数据集,写程序来进行学习,然后可以识别左边这样图,识别为正确的物种。... 查看详情

吴恩达《机器学习系列课程》学习笔记

...,B站反而更像中国的YouTube。在B站上看到吴恩达的《机器学习系列课程》,看了看发现挺有意思,就梳理一下在此形成学习笔记。第一节:前言机器学习早已成为我们的日常。每当使用Google或Bing等搜索引擎时࿰... 查看详情

系列ml.net学习篇——初识机器学习

由于公司项目涉及到机器学习和图像识别,虽然我并不是算法专家,但毕竟需要了解和知道其运转原理,因此自我进行了学习进化,决定在机器学习上有所进展,结合.NET技术的ML.NET,把机器学习的技能提升一个Level&#... 查看详情

机器学习导图系列:数据处理

机器学习导图系列教程旨在帮助引导开发者对机器学习知识网络有一个系统的概念,其中具体释义并未完善,需要开发者自己探索才能对具体知识有深入的掌握。本项目灵感来自DanielFormoso的github开源项目。本文作者对其项目进... 查看详情

机器学习:逻辑回归

...*****注:本系列博客是博主学习Stanford大学AndrewNg教授的《机器学习》课程笔记。博主深感学过课程后,不进行总结非常easy遗忘,依据课程加上自己对不明确问题的补充遂有此系列博客。本系列博客包含线性回归、逻辑回归、神... 查看详情