第一次用Python,第一次编写机器学习的程序。所做完全是照葫芦画瓢。光是写入代码并运行就花了好久好久,真的是还有好远的路要走啊。
先附上代码吧。我是用sublime Text写的。编译环境是Python 3.63
from numpy import *
import operator
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 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 kNN
group1,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近邻算法法改进约会网站的配对效果
在这个示例中,有三个地方需要注意:
数据的归一化处理
先来看如何读取文本数据:
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() #去掉每行头尾空白