前言
在大学里,最好的方面不是你研修的课程或从事的研究,而是一些外围活动:与人会面、参加研讨会、加入组织、旁听课程,以及学习未知的知识。
一个机构会雇佣一些理论家(思考者)以及一些做实际工作的人(执行者)。前者可能会将大部分时间花在学术工作上,他们的日常工作就是基于论文产生思路,然后通过高级工具或教学进行建模。后者则通过编写代码与真实世界交互,处理非理想世界中的瑕疵,比如崩溃的及其或带噪声的数据。并不能完全区分两类人。
第一部分 分类
前两部分主要探讨监督学习。监督学习一般使用两种类型的目标变量:标称型(有限目标集)和数值型(无限的数值集合)。
第 1 章 机器学习基础
机器学习能让我们自数据集中受到启发,换句话说,我们会利用计算机来彰显数据背后的真实含义。
1.1 何谓机器学习
机器学习就是把无数的数据转换成有用的信息。
机器学习横跨计算机科学、工程技术和统计学等多个学科,对于任何需要解释并操作数据的领域都有所裨益。
机器学习用到了统计学知识,因为现实世界中很多例子我们无法位置简历精确的数学模型,所以需要统计学工具。
1.1.1 传感器和海量数据
互联网有大量的非人为数据,举了地震预测的例子,讲述了移动计算和传感器产生海量数据。
1.1.2 机器学习非常重要
大量的经济活动都依赖于信息,我们不能再海量的数据中迷失,机器学习将有助于我们穿越数据雾霭,从中抽取出有用的信息。
1.2 关键术语
特征、分类、训练集、目标变量、测试数据、知识表示
1.3 机器学习的主要任务
监督学习:分类和回归。无监督学习:聚类和密度估计。
1.4 如何选择合适的算法
必须考虑两个问题:一、使用机器学习算法的目的,想要算法完成何种任务。二、需要分析或收集的数据是什么。
1.5 开发机器学习应用程序的步骤
1、收集数据
2、准备输入数据
3、分析输入数据
4、训练算法
5、测试算法
6、使用算法
1.6 Python语言的优势
三个原因:(1)Python的语法清晰;(2)易于操作纯文本文件;(3)使用广泛,存在大量的开发文档。
1.6.1 可执行伪代码
Python具有清晰的语法结构,并且语言处理和操作文本文件非常简单。
1.6.2 Python比较流行
1.6.3 Python语言的特色
和MATLAB相比是免费的,其插件是开源的。
和Java、C相比,不需要编写大量冗余的代码。
1.6.4 Python语言的缺点
运行效率不高。
1.7 NumPy函数库基础
几个命令random.rand(4,4)产生4*4的随机数组。
randMat=mat(random.rand(4*4))产生矩阵
矩阵与数组的区别~
randMat.I 矩阵的逆 eye(n)n阶单位阵
1.8 本章小结
机器学习广泛应用于日常生活中,每天处理的数据不断增加,能够深入理解数据背后的真实含义,是数据驱动产业必须具备的基本技能。
第 2 章 k-近邻算法
知乎大神的相关笔记!
首先,我们将探讨k-近邻算法的基本理论,以及如何使用距离测量的方法分类物品;其次我们将使用Python从文本文件中导入并解析数据;再次,本书讨论了当存在许多数据来源时,如何避免计算距离时可能碰到的一些常见错误;最后,利用实际的例子讲解如何是所有k-近邻算法改进约会网站和手写数字识别系统。
2.1 k-近邻算法概述
简单地说,k-近邻算法采用测量不同特征值之间的距离方法进行分类。
k-近邻算法
优点:精度高、对异常值不敏感,无数据输入假定
缺点:计算复杂度高、空间复杂度高
使用数据范围:数值型和标称型
k-近邻算法的工作原理:在训练样本集中,每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据即中前k(通常k<20)个最相似的数据。最后选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
k-近邻算法的一般流程
1、收集数据:可以使用任何方法
2、准备数据:距离计算所需要的数值,最好是结构化的数据格式
3、分修数据:可以使用任何方法
4、训练算法:此步骤不适用于k-近邻算法
5、测试算法:计算错误率
6、使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输入数据分别术语哪个分类,最后应用对计算出的分类执行后续的处理。
2.1.1 准备:使用Python导入数据
2.1.2 实施kNN算法
2.1.3 如何测试分类器
使用已知答案的数据。
2.2 示例:使用k-近邻算法改进约会网站的配对效果
示例:在约会网站上使用k-近邻算法
(1) 收集数据:提供文本文件。
(2) 准备数据:使用Python解析文本文件。
(3) 分析数据:使用Matplotlib画二维扩散图。
(4) 训练算法:此步骤不适用于k-近邻算法。
(5) 测试算法:使用海伦提供的部分数据作为测试样本。
测试样本和非测试样本的区别在于:测试样本是已经完成分类的数据,如果预测分类与实际类别不同,则标记为一个错误。
(6) 使用算法:产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方是否为自己喜欢的类型。
2.2.1 准备数据:从文本文件中解析数据
在将特征数据输入到分类器之前,必须将待处理数据的格式改变为分类器可以接受的格式。
Numpy数组和Python数组
由于NumPy库提供的数组操作并不支持Python自带的数组类型,因此在编写代码时要注意不要使用错误的数组类型。
2.2.2 分析数据:使用Matplotlib创建散点图
具体可见Matplotlib简明教程
import matplotlib
import matplotlib.pyplot as plt
fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(datingDataMat[:,1],datingDataMat[:,2]
#或者 ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))
plt.show()
2.2.3 准备数据:归一化数值
def autoNorm(dataSet):
minVals=dataSet.min(0)#对于dataSet这个矩阵返回每一列的最小值
maxVals=dataSet.max(0)
ranges=maxVals-minVals
normDataSet=zeros(shape(dataSet))
m=dataSet.shape[0]
normDataSet=dataSet-tile(minVals,(m,1))
normDataSet=normDataSet/tile(ranges,(m,1))
return normDataSet,ranges,minVals
2.2.4 测试算法:作为完整程序验证分类器
随机选择一些数据测试分类器。
def datingClassTest():
hoRatio=0.10
datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
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))
2.2.5 使用算法:构建完整可用系统
def classifyPerson():
resultList=['not at all','in small doses','in large doses']
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.3 示例:手写识别系统
识别数字0-9
2.3.1 准备数据:将图像转换为测试向量
编写img2vector,创建1*1024的NumPyt数组,然后打开指定文件,将文件存储到NumPy数组中,返回数组。
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.3.2 测试算法:使用k-近邻算法识别手写数字
from os import listdir 从os模块中导入函数listdir,列出给定目录的文件名。
def handwritingClassTest():
hwLabels=[]
trainingFileList=listdir('trainingDigits')
m=len(trainingFileList)
trainingMat=zeros((m,1024))
for i in range(m):
fileNameStr=trainingFileList[i]
fileStr=fileNameStr.split('.')[0]
classNumStr=int(fileStr.split('_')[0])
hwLabels.append(classNumStr)
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])
vectorUnderTest=img2vector('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 "\n the total number of errors is: %d"% errorCount
print "\n the total error rate is: %f"%(errorCount/float(mTest))
2.4 本章小结
k-近邻算法是分类数据最简单最有效的算法。k-近邻算法是基于实力的学习,使用算法时我们必须有接近实际数据的训练样本数据。k-近邻算法必须保存全部数据集,如果训练数据集很大,必须使用大量的存储空间。此外,由于必须对数据集中每个数据计算距离值,实际使用可能非常耗时。
k-近邻算法的另一个缺陷是它无法给出任何数据的基础结构信息,因此我们无法知晓平均实例样本和典型实例样本具有什么特征。概率测量方法可以解决该问题。
第 3 章 决策树
k-近邻算法可以完成很多分类任务,但最大的缺点在于无法给出数据的内在含义,决策树的主要优势就在于数据形式非常容易理解。
3.1 决策树的构造
决策树
优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据。
确定:可能会产生过度匹配问题
使用数据类型:数值型和标称型
首先我们讨论数学上如何使用信息论划分数据集,然后编写代码将理论应用到具体的数据集上,最后编写代码构建决策树。
首先要解决的问题:评估每个特征,找到决定性的特征。
决策树的一般流程
1、收集数据:可以使用任何方法。
2、准备数据:树构造算法只适用于标称型数据,因此数值型数据必须离散化。
3、分析数据:可以使用任何方法,构造树完成之后,我们应该检查图形是否符合预期。
4、训练算法:构造树的数据结构
5、测试算法:使用经验树计算错误率。
6、使用算法:此步骤可以适用于任何监督学习算法,而使用决策树可以更好地理解数据的内在含义。
本书使用ID3算法划分数据集。
3.1.1 信息增益
划分数据集的大原则:将无序的数据变得更加有序。
组织杂乱无章数据的一种方法就是使用信息论度量信息。
在划分数据集之前之后信息发生的变化成为信息增益。集合信息的度量方式成为香农熵或熵。
如果待分类的事务可能划分在多个分类之中,则符号
xi
的信息定义为
其中 p(xi) 是选择该分类的概率。
所有类别所有可能值包含的信息期望值
其中n是分类的数目。
from math import log
def calcShannonEnt(dataSet):
numEntries=len(dataSet)
labelCounts={}
for featVec in dataSet:
currentLabel=featVec[-1]
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel]=0
labelCounts[currentLabel]+=1
shannonEnt=0.0
for key in labelCounts:
prob =float(labelCounts[key])/numEntries
shannonEnt-=prob*log(prob,2)
return shannonEnt
得到熵之后,按照获取最大信息增益的方法划分数据集。
另一个度量集合无序程度的方法是基尼不纯度,简单地说是从一个数据集中随机玄子子项,度量其被错误分类到其他分组里的概率。
3.1.2 划分数据集
除了需要测量信息熵,还需要划分数据集,度量划分数据集的熵,以便判断当前是否正确地划分了数据集。
def splitDataSet(dataSet,axis,value):
retDataSet=[]
for featVec in dataSet:
if featVec[axis]==value:
reducedFeatVec=featVec[:axis]
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet
遍历整个数据集,循环计算香农熵和splitDataSet()函数,找到最好的特征划分方式。
def chooseBestFeatureToSplit(dataSet):
#选取特征,划分数据集,计算得出最好的特征
numFeatures=len(dataSet[0])-1
baseEntropy=calcShannonEnt(dataSet)
bestInfoGain=0.0;bestFeature=-1
for i in range(numFeatures):
featList=[example[i] for example in dataSet]
uniqueVals=set(featList)
newEntropy=0.0
for value in uniqueVals:
subDataSet=splitDataSet(dataSet,i,value)
prob=len(subDataSet)/float(len(dataSet))
newEntropy+=prob*calcShannonEnt(subDataSet)
infoGain=baseEntropy-newEntropy
#信息增益是熵的减少,或数据无序度的减少。
if (infoGain>bestInfoGain):
bestInfoGain=infoGain
bestFeature=i
return bestFeature
3.1.3 递归构建决策树
工作原理如下:得到原始数据集,然后基于最好的属性值划分数据集,由于特征值可能多于两个,因此可能存在大于两个分支的数据集划分。第一次划分之后,数据将被向下传递到树分支的下一个节点,在这个节点上,我们可以再次划分数据。因此我们可以采用递归的原则处理数据集。
递归结束的条件是,程序遍历完所有划分数据集的属性,或者每个分支下的所有实例都具有相同的分类。