《机器学习实战》之kNN实现

来源:互联网 发布:十大网络公关公司 编辑:程序博客网 时间:2024/06/01 07:29

第一次用Python,第一次编写机器学习的程序。所做完全是照葫芦画瓢。光是写入代码并运行就花了好久好久,真的是还有好远的路要走啊。

先附上代码吧。我是用sublime Text写的。编译环境是Python 3.63

from numpy import *import operatordef createDataSet():    group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])    labels = ['A','A','B','B']    return group, labelsdef 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.items(),                                key=operator.itemgetter(1), reverse = True)    return sortedClassCount[0][0]import kNNgroup1,labels1 =kNN.createDataSet()kNN.classify0([0,0],group1,labels1,3)print(kNN.classify0([0,0],group1,labels1,3))

首先是安装numpy包。第一次做完全不会,感觉还挺难搞的。先下了很多乱七八糟的东西,发现并没有什么卵用,又懒得仔细地阅读相关说明,终于在不懈地“百度”下,我利用pip成功安装了Python3.6版本的Numpy.whl文件。安装完突然觉得似乎还是很简单的,多亏了这些工具。

Pip是Python包管理工具,主要是用于安装PyPI( the Python Package Index)上的软件包。

whl格式本质上是一个压缩包,里面包含了py文件,以及经过编译的pyd文件。使得可以在不具备编译环境的情况下,选择合适自己的python环境进行安装。

如何安装Pip可参考:http://blog.csdn.net/olanlanxiari/article/details/48086917

如何利用Pip安装whl文件可参考:
https://jingyan.baidu.com/article/d45ad14857168e69552b801f.html

相关内容在里面解释的蛮详细了,我就不画蛇添足了。
另外值得一提的是,我在安装whl文件时,并没有先安装Pip,我也不知道是为什么,我在cmd直接输入 pip install wheel 就直接运行成功了,是不是下载的Python3.63里带了Pip? 不懂。


好,安装的事情说完了,回到代码。
这是我第一次接触Python代码,基本全然不懂。于是边“抄”代码边百度,苦也。

就比如说这个def ,在Python中,函数声明和函数定义是视为一体的。其函数定义的基本形式如下:

def function(params):    block    return expression/value

嗯,和以前学Matlab、C++的时候还蛮像。Get it。
但是需要注意的是:

(1)在Python中采用def关键字进行函数的定义,不用指定返回值的类型。

(2)函数参数params可以是零个、一个或者多个,同样的,函数参数也不用指定参数类型,因为在Python中变量都是弱类型的,Python会自动根据值来维护其类型。

(3)return语句是可选的,它可以在函数体内任何地方出现,表示函数调用执行到此结束;如果没有return语句,会自动返回NONE,如果有return语句,但是return后面没有接表达式或者值的话也是返回NONE。

(4)在Python中不允许前向引用,即在函数定义之前,不允许调用该函数。

了解了def的公用,那么关于kNN代码中的第一部分就很好理解了。

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

不外乎是通过def建立了一个返回“group”和”label”值的函数。在这里group就是训练样本集合,label是对应于每一个样本的标签。

KNN算法的主要思想是通过计算待分类数据与每一个样本之间的距离,取出距离最近的k个样本,通过这k个样本的标签,来判断待分类数据属于哪一类。核心思想还是很好理解的。

看到这里的时候,我想到了几个问题:

1、如果训练样本集合很大,是不是还是要算出待分类数据与每一个样本之间的距离?这样是不是计算量过大?有没有缩小计算量的方法?
2、k的值该如何选取才能使得判断准确率达到最好?

再回到代码,书中提到:

为了方便使用createDataSet()函数,它创建数据集和标签,依次执行以下步骤:保存kNN.py文件,改变当前路径到储存kNN.py文件的位置,打开python开发环境,…..,通过输入import kNN 来导入kNN模块。

如果是在Sublime Text中编译的话,只需要选择利用python来Build就好。如果是在python的编译环境下,就需要调整当前路径,相关的命令是:

os.getcwd()      # 获取当前路径位置os.chdir("d:\\") # 更改为目标路径d盘

终于到最关键的部分了,也就是kNN的具体实现代码。其思想在上面已经提到了,还是蛮朴素的。
代码中用到了许多我第一次接触的函数,具体的解释我已经通过注释添加到了代码中。
原谅我这蹩脚的英语。

def classify0(inX, dataSet, labels , k):    # inX : the data waiting for being decided    # dataSet : which include all samples     # labels : the labels of sample dataset    # k : the nearest k samples of all dataset    dataSetSize = dataSet.shape[0]    # Shape is a function of Numpy .It has the ability to read the size of matrix or array.    # Here we use shape[0] to read the first dimension of the array "dataSet"     diffMat = tile(inX,(dataSetSize,1)) - dataSet     # Tile is a function of Numpy . It changes the dimension of inX to "1*col(inX)" col and "dataSetSize" row    sqDiffmat = diffMat**2    # every number in diffMat square     sqDistances = sqDiffmat.sum(axis=1)    # axis=0 means plus column     # axis=1 means plus row    distances = sqDistances**0.5    sortedDistIndicies = distances.argsort()    # argsort return the index(position) of the array which has been sorted from small to large.    classCount={}    # define a dictionary     for i in range(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]

shape :Numpy中的函数之一,返回其数组或矩阵的规模大小。

tile : Numpy中的函数之一,在行、列上实现重复。
具体解释参见http://blog.csdn.net/ksearch/article/details/21388985

sum: axis=0 按照列求和 ; axis=1 按行求和。

argsort :将数组从小到大排序后,返回其原数组对应数值的索引(也就是位置)。

还有关于字典中的sorted函数、get函数,没有实例的话解释还是蛮麻烦的。我懒,给个网址算了。>.<
具体的内容可以参考:http://www.runoob.com/python/python-tutorial.html
sorted函数可以参考:http://blog.csdn.net/myarrow/article/details/51200167

有一点注解:在字典中,创建时如果同一个键被赋值两次,后一个值会被记住。注意到在上述代码中

classCount[voteIlabel] = classCount.get(voteIlabel,0)+1

由于voteIlabel只有“A”“B”两种值,所以在k次循环中,会将重复出现的”A”或者“B”的次数累加,显然,如果“A”出现的次数大于“B”,则待归类数据离“A”更近。故在sorted排序中要选择“reverse = True” 降序排列,且按照“itemgetter(1)”即每组的第二个值(出现次数) 来进行排序。


之后,本书给出了一个示例:使用k近邻算法法改进约会网站的配对效果
在这个示例中,有三个地方需要注意:

  1. 使用Matplotlib画二维扩散图
  2. 将文本记录转换为Numpy的解析程序
  3. 数据的归一化处理

    先来看如何读取文本数据

def file2matrix(filename):    fr = open(filename)    arrayOlines = fr.readlines()    numberoflines = len(arrayOlines)    returnMat = zeros((numberoflines,3))    classLaberVec = []    index = 0    for line in arrayOlines:        line =line.strip()        listFromLine = line.split('\t')        returnMat[index,:] = listFromLine[0:3]        classLaberVec.append(int(listFromLine[-1]))        index += 1    return returnMat,classLaberVec

关于读取文件的函数使用可参见:http://www.runoob.com/python/file-methods.html
关于split字符串切割函数可参见:http://blog.csdn.net/doiido/article/details/43204675

注意:

readlines() 方法用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由 Python 的 for… in … 结构进行处理。
如果碰到结束符 EOF 则返回空字符串。

for line in arrayOlines:    #依次读取每行        line =line.strip()  #去掉每行头尾空白 
原创粉丝点击