机器学习算法原理与编程实践(txt+pdf+epub+mobi电子书下载)


发布时间:2020-06-28 20:04:13

点击下载

作者:郑捷

出版社:电子工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

机器学习算法原理与编程实践

机器学习算法原理与编程实践试读:

前言

动机

2011年1月14日,史上最强的人机对抗在美国纽约约克镇高地拉开序幕。Jeopardy!是美国具有25年历史的众所皆知的电视问答节目秀。每次三名参赛者相互角逐,在竞赛中需要迅速理解屏幕上提出的各类智力问题,并作出回答。问题涉及的领域十分广泛,就像一套世界知识的百科全书,超过个人所能掌握的知识容量的极限。而这次,一名特殊的参赛者名列其中,它就是IBM公司的计算机参赛者Watson,挑战两位人类选手Ken和Brad。经过激烈的角逐,Watson同时击败了两位人类选手,赢得100万美元奖金而一举成名。这一具有历史意义的比赛被Jeopardy!的哥伦比亚广播公司连续在2011年2月14—16日三天晚上进行了重播,也成为计算机发展史上一个重要的时刻。IBM评论为:“在Jeopardy!比赛中,计算机打败人类选手是开放领域问答系统的一个里程碑!”

事实上,这次比赛有力地证明了,在广泛的知识和智能领域,机器有能力全面超越人类。开放领域问答软件的一个重要核心就是机器学习。从很多方面来看,这才仅仅是一个开始。近年来,计算机行业取得的最重要成就或多或少地都与机器学习领域的技术突破密切相关。2010年前后,多伦多大学的Geoffrey Hinton提出的深度学习(Deep Learning)算法,突破了产生抽象概念的技术瓶颈,被评价为:“借助于DeepLearning算法,人类终于找到了如何处理‘抽象概念’这个亘古难题的方法。”

该算法与衍生的卷积神经网络(CNN——有监督)和深度置信网络(DNN——无监督)在计算机视觉、语音识别和部分自然语言处理领域获得巨大的成功,其与另一个并行处理架构Map Reduce并称“大数据”技术的基石。

2012年11月,微软在天津的一次活动上公开演示了一个全自动的同声传译系统,讲演者用英文演讲,后台的计算机一气呵成自动完成语音识别、英中机器翻译和中文语音合成,效果非常流畅。据报道,后面支撑的关键技术就是DNN,或者深度学习(DeepLearning,DL)。

人与动物最本质的区别之一就是人类具有高度发达的智能。千百年来,人类从未停止过对智慧本身的研究与探索。20世纪50年代,图灵就在论文《机器能思考吗》中提出了一个著名测试,后世称为图灵测试:“假如一台机器通过特殊的方式与人沟通,若有一定比例的人(超过30%)无法在特定时间内(5分钟)分辨出与自己交谈的是人还是机器,则可认为该机器具有‘思考’的能力。”

这里的思考能力就是指智能。而对于计算机领域而言,它是一个多么奢侈而艰难的字眼。以IBM Watson为例,它由90台IBM服务器、360个计算机芯片驱动组成,是一个有着10台冰箱那么大的计算机系统。它拥有15TB内存,2880台处理器,每秒可进行80万亿次运算。系统配置的处理器是Power 7系列处理器,这是当前RISC(精简指令集计算机)架构中最强的处理器。它采用45nm工艺打造,拥有8个核心、32个线程,主频最高可达4.1GHz,仅其二级缓存就达到32MB。

在大数据领域,据Google称,其知识图谱的信息有许多来源,包括CIA的世界概况、Freebase和维基百科,其功能与Ask.com和Wolfram Alpha等问题问答系统相似。截至2012年,其语义网络包含超过570亿个对象,超过18亿个介绍,用来理解搜索关键词含义的、不同对象之间的链接关系更是不可计数。2012年11月4日,知识图谱新增了7种语言:西班牙语、法语、德语、葡萄牙语、日语、俄罗斯语及意大利语。

历经半个多世纪,在各个领域的商业机构和科研机构的共同努力下,几经沉浮,人们逐渐意识到,高度并行的计算(硬件)能力和大规模数据的学习(算法)能力是“思考”的基础。距离让机器像人类一样思考的目标已经不远了!本书特色

本书的最大特色就是理论讲解深入浅出、通俗易懂,入门门槛不高,理论与实践并重。降低学习门槛是我们主要的努力方向。对于中国读者,特别是广大的工程技术人员,无论是在职还是学生,进入机器学习领域不外乎两条路。

第一条路是从开源代码学习,辅助一些书籍资料。大多数软件设计人员都做过几年源码解析工作,源码解析这条路是比较辛苦的,但一旦掌握,就会形成一种条件反射。程序员宁可读源码也不愿意读数学公式,这是普遍现象。笔者认为,随着机器学习一步步走向工程实践,这部分人在读者群中应占绝大部分。

为了最大限度地降低学习的难度,首先在内容上,我们以大量的文字描述来说明重要的定理和公式,尽可能在数学推导过程中增加充分的文字解释,消除初学者的理解障碍。其次,我们将源码、公式和文字解释对照起来,使初学者在阅读源码和文字解释的同时,也能够轻松理解算法的数学原理,使他们认识到数学分析并不遥远,理解起来并不困难。最后,我们使用矢量编程的设计方式,这种方式的优势是可以部分地将数学公式直接映射到代码上,代码简洁,思路清晰,学习效率很高。三管齐下,使初学者能多角度加深算法概念的理解,在实践应用中做到举一反三。

第二条路是从数学入手,一般针对研究所或科研院校的研究人员。他们喜欢那种有一定的理论高度,看明白了拿来就可以讲课或写论文用的书籍。这部分读者的特点是比较重理论,缺点是实践能力不强。本书可以通过丰富的算法代码弥补他们在此方面的不足。

最后,本书由本土作者编写。笔者翻译过几本国外的专业论文和书籍,也看过不少的本土经典。如果内容差异不大,从效率和接受程度上,看本土书籍要快很多,时间成本对任何一个人都是重要的;本土书籍的另一个优势是作者与大多数的读者都有相似的背景知识结构,因而没有文化差异性,思路上很好理解,容易被读者接受。本书内容多取材于实践,目标明确,针对性强,对读者而言学习效率高。本书内容及体系结构

本书的特点之一是从结构上阐明了研究机器学习理论和算法的方法。最重要的不是数学,也不是这些算法本身,而是思想的发展过程,这与之前所有的书籍有所不同。全书分为三条主线。

第一条主线是从第一代神经网络(线性分类器)、第二代神经网络(非线性)及其在预测领域的应用,到支持向量机,最后是深度学习。

从第5章开始我们深入讲解了感知器网络及Logisitic网络的算法及相关的理论基础。第6章,我们详细介绍了三种典型的神经网络:BP网络、SOM网络、玻尔兹曼机网络。这两章的内容主要集中在第二代神经网络的模型上。● 第8章我们从统计学习理论开始,深入探讨了支持向量机的模型,

并给出了文本分类的实例。支持向量机的出现结束了浅层机器学

习算法的大多数问题,使人工智能走向了一个新阶段。● 第9、10章我们详细介绍了认知分层理论,并探讨了人类神经系

统的两大重要机制:迭代和分层。由此引入了深度神经网络框架(深度学习),并以Theano框架为中心介绍了GPU运算的模型。

深度学习框架中的算法很多,我们介绍了多层感知器和卷积神经

网络两个算法,作为读者入门的基础。

第二条主线是贝叶斯理论,从朴素贝叶斯算法到贝叶斯网,最后是隐马尔科夫模型,这部分属于智能推理的范畴。● 第2章我们详细介绍了朴素贝叶斯算法在文本分类中的应用。由

于文本处理的大多数算法都是以贝叶斯网为基础的,而朴素贝叶

斯是其中最简单的算法,所以以此开篇。● 第11章,我们从随机过程开始,层层深入,相继介绍了马尔可

夫链、贝叶斯网络、隐马尔科夫模型。最后,我们给出了隐马尔

科夫模型的重要应用——自然语言处理的词性标注模块,并给

出详细的代码讲解和结巴分词及词性标注应用。

最后一条主线是矩阵降维、奇异值分解(SVD)和PCA算法,因为算法简单,本书都使用真实案例进行讲解。● 第4章,我们通过一个实例介绍了推荐系统的内容,并分析介绍

了协同过滤理论中的两个重要算法:KMeans和SVD隐语义分

析。我们不仅讲解了SVD的数学推导,而且给出了手工计算的代

码。● 第9章,我们讲解了主成分分析(PCA)的基本原理和算法,并

通过实例讲解,列出了PCA的算法实现和监测评估。● 第3、9章,我们介绍了决策时算法的发展历史,以及各个历史

时期的代表算法——ID3、C4.5、CART、AdaBoost,并给出基

本原理和代码实现。

目前机器学习主要由这三条主线贯穿始终,本书着力于讲解这三条主线的理论发展、思想变迁、数学原理,而具体算法就是其上的一颗颗明珠。希望读者在学习完本书之后,能够将机器学习的各种理论融会贯通。第1章机器学习的基础“基础决定高度,而不是高度决定基础。”

机器学习脱胎于人工智能,自诞生之日起,就充满了挑战。这个领域聚集了全世界顶尖的科学家,本书所讲述的正是他们多年的研究成果。对于普通读者而言,快速而全面地掌握各类算法技术并不是一件容易的事情。机器学习应用的领域涉及方方面面,从交通运输、医疗诊断到自然语言处理,几乎各行各业都有所涉猎。为了简化叙述,多数书籍偏重于数学理论,但即便完全形式化为数学概念,不仅不便于理解,所涉及的知识也很庞杂。毕竟几十年来,机器学习这座大厦是靠一砖一瓦坚实地构筑起来的。

本章是全书的第1章,主要从程序编码、数据结构、数学理论、数据处理与可视化等几个方面阐述了与机器学习相关的理论和技术实现。初看涉及内容比较多,为了避免混乱,我们以矩阵为中心贯穿本章各部分的知识讲解,然后扩展到概率论、数值分析、矩阵分析等知识来逐步引导读者进入机器学习的世界。

对于大多数读者而言,理解数学原理和推导过程起初会存在一些障碍,这也是初学者的一大壁垒,很多人虽有兴趣,但每到此处只能望而却步。因此,在数学理论方面,我们并没有罗列大量的公式和晦涩的术语,而是力求结合人们的日常生活,通过深入浅出的案例,使读者由浅入深、循序渐进地接触概念,最终真正领悟内涵。对象与维度、初识矩阵、理解随机性等章节完全不需要高等数学的基础,但是它们所阐述的方法和概念是整个机器学习大厦的基础。

幸运的是,由于软件编程方法的日新月异,矢量化编程方式(参见1.2节)能够将数学公式直观地转换为程序代码,这极大地降低了程序设计的难度,多数公式的程序代码仅有一两行。读者可以通过NumPy矩阵运算和Linalg线性代数库两节内容逐步熟悉矢量化编程的风格,各类距离公式是矢量化编程的应用。除程序设计的相关知识,这两节也可看作对线性代数中一些重要概念的回顾,如果读者对线性代数的概念生疏了,可以借此重温一下。总体而言,机器学习对程序设计的要求不高,除去矢量化编程,一般而言都是一些最基本的指令,只要掌握一定的编程技术和高等数学的基本概念,学好本书还是不难的。

各类距离公式、矩阵空间变换对于某些读者而言可能属于新知识。本章涉及的距离公式比较多,但总的来讲都不难,本书也都提供了程序代码。矩阵的空间变换是一个重点,后续章节中多有涉及,需要读者认真领会。如果理解上有困难,在具体算法上我们还会详细讲解。

总之,我们的目标是使程序设计变成一件轻松、快乐的事情。常言道:“千里之行,始于足下。”现在,就让我们开始激动人心的机器学习之旅吧!1.1 编程语言与开发环境1.1.1 搭建Python开发环境“工欲善其事,必先利其器”,还好Python语言还算锋利,一般拥有程序设计基础的读者,几周时间就可掌握本书中所需的语言技术。书中绝大多数程序代码都使用Python语言编写,原因有以下几点:● 免费、开源。Python语言是免费、开源的脚本语言。这两个词几

乎成为流行编程语言必不可少的特征。● Python编程更简单。相比于编译语言(C、C++)而言,Python

是一种跨平台的脚本语言,编写好的代码可以直接部署在各类操

作系统上(例如,Linux、Windows、Mac OS X)。● 开发和执行效率高。其各种库大多是基于C语言编写的(相对于

Java而言),并适用于32位和64位系统,性能损失小,适合大规

模数据处理。● 丰富的程序库,支持矢量编程。Python在机器学习和自然语言处

理方面提供了完备的程序库,包括机器学习、数学分析、可视化

库、GPU并行库等。● Python支持网络编程,写好的代码可以直接发布到Internet上。

Python开发环境可以搭建在Linux下,也可以搭建在Windows下;可以是32位的,也可以是64位的。这为开发者提供了很大的灵活性。为了便于初学者学习,本书在Windows 7下部署64位的Python开发环境,同时在1.5节中提供了Linux下的部署方式。

Python可在官方网站直接下载,网址为https://www.python.org/downloads/source/。本书使用的是2.7-64位版本,下载地址为https://www.python.org/downloads/release/python-279/。所装的库和代码也是以2.7版本为基础的,如果读者使用其他版本,需要做相应的修改。

下面给出在Windows系统下安装Python的简要步骤。(1)双击下载的安装程序python-2.7.9.amd64.msi,执行安装,如图1.1所示。如果其他用户不需要Python的话,可以选择第二个选项。不过我们一般都是单用户,所以没有差别。图1.1 Python安装步骤1(2)选择安装路径。可按默认路径安装,也可自己新建路径。新建路径一般用英文命名比较好,方便命令行访问。本书所用的安装路径为C:\Python64,单击Next按钮,如图1.2所示。图1.2 Python安装步骤2(3)依次单击Next按钮,程序开始复制安装文件,复制完成后单击Finish按钮,完成安装,如图1.3所示。图1.3 Python安装步骤31.1.2 安装Python算法库

最初,Python社区仿照MATLAB开发了类似的数学分析库,主要包括用NumPy和SciPy来处理数据,用Matplotlib来实现数据可视化。大多数Python数学和算法领域的应用广泛地将其作为基本的程序库。很快,为了适应处理大规模数据的需求,Python在此基础上开发了Scikit-Learn机器学习算法库(网址为http://scikit-learn.org/stable/);同时,还提供了深度学习算法库Theano(网址为http://deeplearning.net/software/theano/),并支持GPU运算。迄今为止,Python已经可以完整地提供基于C/C++语言的机器学习开发包,而且都是开源版的,有兴趣的朋友还可以下载源码包学习。后面的章节将详细讲解这些库的使用,这里就不再赘述了。

除此之外,Python还提供了大量的常用程序库,如数据库API(MysqlDB)、GUI图形界面库(WxPython)、高并发协程库(gevent)、中文分词库(jieba)等外部库。所有这些库都可以从下面两个网址查询到。● 官方下载地址:https://pypi.python.org/pypi。● 非官方下载地址:http://www.lfd.uci.edu/~gohlke/pythonlibs/。

最值得称道的是,这些算法库不仅安装非常简便,而且均提供32位和64位两个版本,并分别支持2.6、2.7、3.3、3.4版本的Python应用。

Python算法库的安装非常简单,执行“C:\Python64\Scripts\pip install库名(小写字母不加后缀)”命令即可。

Python算法库的安装顺序为:NumPy→SciPy→Matplotlib→Scikit-Learn。

上述每个库安装完成后,都会提示如下信息,表示此库安装成功。  Successfully installed xxx(库名)    Cleaning up..1.1.3 IDE配置及其安装测试

Python的各类算法库安装完成后,一般需要选择一个开发平台(IDE)编写代码。本书的核心内容偏重算法设计,对IDE要求不高,推荐使用UltraEdit高级文本编辑器,主要考虑其拥有资源占用较小、功能较强、支持多种文件编码转换、支持远程开发等优势(本地可同步远程Linux上的源代码,本地编写,远程上运行)。该编辑器下载完成后,需要进行如下配置。(1)选择“高级”→“工具栏配置”命令,如图1.4所示。图1.4 配置 UltraEdit 步骤1(2)如图1.5所示输入各项参数,然后单击“应用”按钮。图1.5 配置UltraEdit步骤2(3)按如图1.6所示进行设置,然后单击“确定”按钮。图1.6 配置UltraEdit步骤3

这样UltraEdit就配置完成了。下面我们开始编写一些测试代码。因为安装的模块比较多,简单的Hello World测试不能说明问题,过于复杂的程序又容易令人费解。为此,我们简单编写一个应用程序用于测试。运行下面的测试代码,可以检验安装的效果。

代码文件mytest1.py:  # -*- coding: utf-8 -*-  # Filename : mytest1.py    import numpy as np # 导入NumPy库  from numpy import * # 导入NumPy库  import matplotlib.pyplot as plt # 导入Matplotlib库    # 测试数据集——二维list  dataSet = [[-0.017612,14.053064],[-1.395634,4.662541],[-0.752157   ,6.538620],[-1.322371 ,7.152853],[0.423363 ,11.054677],[0.406704   ,7.067335],[0.667394 ,12.741452], [-2.460150 ,6.866805],[0.569411   ,9.548755],[-0.026632 ,10.427743],[0.850433 ,6.920334],[1.347183   ,13.175500],[1.176813 ,3.167020],[-1.781871 ,9.097953]]    dataMat = mat(dataSet).T # 将数据集转换为NumPy矩阵,并转置  plt.scatter(dataMat[0],dataMat[1],c='red',marker='o') # 绘制数据集散点图    # 绘制直线图形  X = np.linspace(-2,2,100) # 产生直线数据集  # 建立线性方程  Y = 2.8*X+9    plt.plot(X,Y) # 绘制直线图  plt.show() # 显示绘制后的结果

输出结果如图1.7所示。图1.7 显示执行结果

这说明主要模块安装成功。1.2 对象、矩阵与矢量化编程

有了工具,很多事情就变得方便了。现在,我们正式进入机器学习的基础知识。简单回忆一下绪论部分所提出的三种对象类型:文本、表格、图。乍一看,有点眼花缭乱,仔细分析下来,三种结构虽各有千秋,却存在着共性。1.2.1 对象与维度

对于大多数程序员而言,对象应该不是一个陌生的概念。在面向对象的程序设计思想中,对象就是一个类的实例。机器学习中的对象与之很相似。在机器学习中,对象是指含有一组特征的行向量。而行向量的集合最容易构造的结构就是表。下面我们来观察一张表(见表1.1),此表来源于现实中真实的统计数据。表1.1 大型动物与水果

表中第一行种属、重量(平均)、颜色(主)、生命周期/保质期表示特征名称。所有特征组合在一起构成一组行向量,也称为特征向量。为了区别线性代数中的特征值和特征向量,引入了对象这个名称。以非洲象、大白鲨等开头的数据行就是一组行向量,也就是一个对象。对象的维度就是行向量的列数,上述数据集的维度为5。

在实际计算中,除非特殊情况,特征名称不需要列明;含有字符串的对象名称因无法直接参与运算,一般情况下可以编码为数字,我们将种属特征转换为是否动物(用布尔值0、1替代),颜色特征转换为十六进制数。各列的特征值为了方便计算,应统一单位,区间值可以选择中间值。为了方便量化,表1.1删除第一列,大型动物与水果表就转换为表1.2。表1.2 大型动物与水果表15000#DCDCDC70×36513200#9D9D9D70×36500.25#FF00001000.3#FFFF007

此时,该表被转换为4行、4列的数据表,维度为4。有过一些线性代数知识的读者可以很简单地将此表转换为下面的矩阵,如表1.3所示。表1.3 大型动物与水果矩阵

一般而言,一个对象应被视作完整的个体,代表现实中有意义的事物,不能轻易拆分。它的表现形式可能多种多样,例如在图像识别中它可能是一张图片,如图1.8所示。图1.8 手写体识别中的“0”

图1.8是向量化的手写体图片。注意,图1.8的维度,即行向量的个数是32×32,整张图被当作一行或者一个对象。因为整张图仅代表一个完整的事物,表达了一个完整的意义。一般来说,图片数据集的维度都比较高。

文本类数据集有点特殊,需要首先生成词袋列表,再将每个词出现的词频数值化。例如,有如下文本数据集。

文本1:My dog ate my homework。

文本2:My cat ate the sandwich。

文本3:A dolphin ate the homework。

根据上述三段短文本中出现的词汇,生成词袋列表,该列表记录了上述文本中出现的每个不重复的词。  [a, ate, cat, dolphin, dog, homework, my, sandwich, the]

各段文本根据生成的词袋列表转换为对象,其维度就是词袋列表的长度,计算结果是32维。向量化后的文本称为词向量。

各段文本向量化后的词向量,其中0表示词袋中对应的词未出现在文本中;1表示该词出现在文本中1次;如果多次出现,则累加,如表1.4所示。表1.4 词向量空间1.2.2 初识矩阵

在线性代数中我们学过,矩阵是由m×n个数组成的一个m行n列的矩形表格,或者更深一点的定义,表示由方程组的系数及常数所构成的二维数据表。从机器学习的角度来看,这两个定义都合适,但又都不合适。

现在,我们重新考查一下矩阵。前面我们定义了表和对象的概念。对象是被特征化的客观事物,而表是容纳这些对象的容器。换句话说,对象是表中的元素,表是对象的集合。但这个集合有点特殊,即表中的每个对象都有相同的特征和维度,对象对于每个特征都有一定的取值。这里矩阵可以理解为具有相同特征和维度的对象集合。

总结一下:● 矩阵是具有相同特征和维度的对象集合,表现为一张二维数据

表。● 一个对象表示为矩阵中的一行,一个特征表示为矩阵中的一列,

每个特征都有数值型的取值。● 特征相同、取值相异的对象集合所构成的矩阵,使对象之间既相

互独立,又相互联系。● 由特征列的取值范围所有构成的矩阵空间应具有完整性,即能够

反映出事物的空间形式或变化。

关于第三点,我们再观察表1.4:动物种属和植物种属是两个风马牛不相及的概念,但如果放到一张表中,我们必须使用一组特征向量来衡量它们,比如种属、重量、颜色、生命周期等。但不能用味道这个特征来衡量,因为非洲象和大白鲨很难讲是酸是甜。这就是各类对象之间的联系。

如果不看实例名称,我们从是否动物、重量、颜色、生命周期几个特征也能很容易地分辨出两类对象的差异性。例如,非洲象重量和苹果重量的悬殊差异,或生命周期/保质期的悬殊差异。这反映了对象间的相互独立。

我们再扩展一下这个例子,如表1.5所示。表1.5 扩展表1.2

除差异性,表1.5中还有一类情况:苹果和梨、非洲象和大白鲨。在是否动物、重量和生命周期三个特征中,苹果和梨具有相似性,非洲象和大白鲨具有相似性。很明显,非洲象和大白鲨的重量较之苹果(或梨)的重量更相似;或者非洲象和大白鲨的寿命较之苹果(或梨)的保质期更相似。由于这种相似性,我们很自然地将苹果和梨分为一类——水果(区别于植物),非洲象和大白鲨分为一类——大型动物(区别于动物)。

由此可见,分类或聚类可以看作根据对象特征的相似性与差异性,对矩阵空间的一种划分。

下面我们再看另一个例子,如表1.6所示。表1.6 2~18岁正常男生身高、体重对照表

表1.6列举了2~18岁男生的正常身高、体重的变化,数值上呈现一种递增的趋势,每个对象都与上一行或下一行的对象在时间上相关,并且时间间隔相等,都为一年。这种时间上的相关性使矩阵反映出某一事物在时间上连续变化的过程。

由此可见,预测或回归可以看作根据对象在某种序列(时间)上的相关性,表现为特征取值变化的一种趋势。

分类、聚类和回归是机器学习最基本的主题。通过矩阵,可以构建客观事物的多维度数学模型,并通过条件概率分布、梯度、神经网络、协方差等运算方式,多角度地认识和分析事物。

具体来讲,矩阵有三个重要用途。第一个用途是解线性方程组,比如二维矩阵可以理解为一个平面直角坐标系内的点集,通过计算点与点之间的距离,完成聚类、分类或预测,类似的运算完全可以扩展到多维的情况。第二个用途是方程降次,也就是利用矩阵的二次型,通过升维将线性不可分的数据集映射到高维中,转换为线性可分的情形,这是支持向量机的基本原理之一。第三个用途是变换,矩阵可以通过特征值和特征向量完成维度约简,简化类似图片这种高维数据集的运算,主成分分析使用的就是这个原理。

在程序设计中,我们可以从形式上把矩阵理解为一个二维数组。以Python语言为例,矩阵就是嵌套着若干个list的一个大list。内部的每个list都是等长的,其中每个元素都是整型或浮点型的数值。内部的list就是行向量,即一个对象。

NumPy数据包提供了专门的矩阵数据结构和线性代数库。从下一节开始,我们将详细介绍NumPy的矩阵运算。1.2.3 矢量化编程与GPU运算

传统的计算机设计语言,例如C语言,是针对标量的,虽然也提供诸如数组、二维数组的数据结构,但这些结构的赋值、加法、数乘、转置、矩阵相乘还是要通过循环语句完成,十分麻烦,导致程序设计的复杂度也比较高。例如:  mylist = [1,2,3,4,5]  length = len(mylist)  a = 10  for indx in xrange(length):   mylist[indx] = a*mylist[indx]  print mylist

输出结果如下。  [10, 20, 30, 40, 50]

而基于矩阵的算法都是针对向量的,这里也称为矢量。为了简化程序的逻辑,需要一种新的编程方法,处理基于矩阵的基本运算,这就是所谓的矢量化编程。

随着程序设计的发展,使用计算机实现矩阵运算越来越方便。最早实现矢量化编程的语言是MATLAB的脚本语言,它极大地降低了数学领域程序设计的复杂度。因此,大量的人工智能算法最早都是用MATLAB语言编写的。

Python自带的List结构,提供的切片功能可以部分实现矢量化编程。其扩展包NumPy提供了专门的矩阵数据结构和线性代数库,完全实现了矢量化编程。例如:  import numpy as np    mylist = [1,2,3,4,5]  a = 10  mymatrix = np.mat(mylist)  print a*mymatrix

输出结果如下。  [[10 20 30 40 50]]

矢量化编程的一个重要特点就是可以直接将数学公式转换为相应的程序代码,极大地方便了程序的阅读和调试,使复杂数学公式的实现变得简单和方便。本节和下一节所用的矢量化程序的代码一般只有一两行,即可完成复杂的数学运算。

无论是MATLAB还是Python的矢量化编程,都可以无缝地调用底层的C函数,还可以提高算法速度。为了提升特定数值运算操作,例如矩阵相乘、矩阵相加、矩阵-向量乘法、浮点运算的速度,数值计算和并行计算的研究人员已经努力了几十年。这个领域最出色的技术就是使用图形处理器的GPU运算。

英伟达(NVIDIA)公司在1999年发布GeForce 256图形处理芯片时首先提出了GPU运算的概念。十几年的发展使单个GPU芯片在浮点运算、大规模并行计算方面,可以提供数十倍乃至上百倍于CPU的性能。GPU的流处理器也由几十个增加到最新的3000多个,浮点运算TFlops值也达到5以上(本书第10章的深度学习部分专门讲解了GPU运算的Python框架Theano)。

对GPU运算比较熟悉的读者也可以将本书中较大规模的矩阵运算交由GPU完成。1.2.4 理解数学公式与NumPy矩阵运算

为了便于理解后续章节算法部分的讲解,本节将常用的矩阵数学公式和程序代码对应出来,读者可根据自己的需求有选择地学习。由于使用了矢量编程的方法,矩阵的基本运算得到了极大的简化。1. 矩阵的初始化  import numpy as np # 导入NumPy包(1)创建一个3×5的全0矩阵和全1矩阵。  myZero = np.zeros([3,5]) # 3×5的全0矩阵   print myZero   myOnes = np.ones([3,5]) # 3×5的全1矩阵   print myOnes

输出结果如下。  [[ 0. 0. 0. 0. 0.]   [ 0. 0. 0. 0. 0.]   [ 0. 0. 0. 0. 0.]]   [[ 1. 1. 1. 1. 1.]   [ 1. 1. 1. 1. 1.]   [ 1. 1. 1. 1. 1.]](2)生成随机矩阵。  myRand = np.random.rand(3,4) # 3行4列的0~1之间的随机数矩阵  print myRand

输出结果如下。  [[ 0.79473503 0.4682515 0.53933591 0.94568244]   [ 0.52199975 0.81190881 0.41920671 0.16756969]   [ 0.57211218 0.53727222 0.83488426 0.30227915]](3)单位阵。  myEye = np.eye(3) # 3×3的单位阵  print myEye

输出结果如下。  [[ 1. 0. 0.]   [ 0. 1. 0.]   [ 0. 0. 1.]]2. 矩阵的元素运算

矩阵的元素运算是指矩阵在元素级别的加、减、乘、除运算。  from numpy import * #导入NumPy包(1)元素相加和相减。

条件:矩阵的行数和列数必须相同。

数学公式:(A ± B)i,j = Ai,j ± Bi,j。  myOnes = ones([3,3]) # 3×3的全1矩阵   myEye = eye(3) # 3×3的单位阵  print myOnes+myEye # 矩阵相加  print myOnes-myEye # 矩阵相减

输出结果如下。  [[ 2. 1. 1.]   [ 1. 2. 1.]   [ 1. 1. 2.]]  [[ 0. 1. 1.]   [ 1. 0. 1.]   [ 1. 1. 0.]](2)矩阵数乘:一个数乘以一个矩阵。

数学公式:(cA)i,j = c · Ai,j。  mymatrix = mat( [[1,2,3],[4,5,6],[7,8,9]])  a = 10  print a*mymatrix

输出结果如下。  [[10 20 30]   [40 50 60]   [70 80 90]](3)矩阵所有元素求和。

数学公式:sum(A)=Ai,j。其中,1

输出结果如下。  45(4)矩阵各元素的积:矩阵的点乘同维对应元素的相乘。当矩阵的维度不同时,会根据一定的广播规则将维数扩充到一致的形式。

数学公式:(A×B)ij = Aij×Bij。  mymatrix = mat( [[1,2,3],[4,5,6],[7,8,9]])  mymatrix2 = 1.5*ones([3,3])  print multiply(mymatrix,mymatrix2)

输出结果如下。  [[ 1.5 3. 4.5]   [ 6. 7.5 9. ]   [ 10.5 12. 13.5]](5)矩阵各元素的n次幂:n=2。

数学公式:= Aij×Aij。  mylist = mat( [[1,2,3],[4,5,6],[7,8,9]])  print power(mymatrix,2)

输出结果如下。  [[ 1 4 9]   [16 25 36]   [49 64 81]]3. 矩阵的乘法:矩阵乘矩阵

数学公式:[A,B]i,j=Ai,1B1,j+Ai,2B2,j+…Ai,nBn,j=Ai,rBr,j。  from numpy import *    mymatrix = mat([[1,2,3],[4,5,6],[7,8,9]])  mymatrix2 = mat([[1],[2],[3]])  print mymatrix*mymatrix2

输出结果如下。  [[14]   [32]   [50]]4. 矩阵的转置

数学公式:(AT)i,j = Aj,i。  from numpy import *    mymatrix = mat([[1,2,3],[4,5,6],[7,8,9]])  print mymatrix.T # 矩阵的转置  mymatrix.transpose() # 矩阵的转置  print mymatrix

输出结果如下。  [[1 4 7]   [2 5 8]   [3 6 9]]  [[1 2 3]   [4 5 6]   [7 8 9]]5. 矩阵的其他操作:行列数、切片、复制、比较  from numpy import *     mymatrix = mat([[1,2,3],[4,5,6],[7,8,9]])  [m,n]=shape(mymatrix) # 矩阵的行列数  print "矩阵的行数和列数:",m,n    myscl1 = mymatrix[0] # 按行切片  print "按行切片:",myscl1    myscl2 = mymatrix.T[0] # 按列切片  print "按列切片:",myscl2    mycpmat = mymatrix.copy() # 矩阵的复制  print "复制矩阵:\n",mycpmat    #比较  print "矩阵元素的比较:\n",mymatrix < mymatrix.T

输出结果如下。  矩阵的行数和列数: 3 3  按行切片: [[1 2 3]]  按列切片: [[1 4 7]]  复制矩阵:  [[1 2 3]   [4 5 6]   [7 8 9]]  矩阵元素的比较:  [[False True True]   [False False True]   [False False False]]1.2.5 Linalg线性代数库

在矩阵基本运算的基础之上,NumPy的Linalg库可以满足大多数的线性代数运算。本节所列的矩阵公式列表和代码如下:● 矩阵的行列式。● 矩阵的逆。● 矩阵的对称。● 矩阵的秩。● 可逆矩阵求解线性方程组。1. 矩阵的行列式  from numpy import *    # n阶方阵的行列式运算  A = mat( [[1,2,4,5,7,],[9,12,11,8,2,],[6,4,3,2,1,],[9,1,3,4,5],[0,2,3,4,1]])  print "det(A):",linalg.det(A); # 方阵的行列式

输出结果如下。  det(A): -812.02. 矩阵的逆  from numpy import *    A = mat( [[1,2,4,5,7,],[9,12,11,8,2,],[6,4,3,2,1,],[9,1,3,4,5],[0,2,3,4,1]])  invA = linalg.inv(A) # 矩阵的逆  print "inv(A):",invA

输出结果如下。  inv(A): [[ -7.14285714e-02 -1.23152709e-02 5.29556650e-02 9.60591133e-02   -8.62068966e-03]   [ 2.14285714e-01 -3.76847291e-01 1.22044335e+00 -4.60591133e-01   3.36206897e-01]   [ -2.14285714e-01 8.25123153e-01 -2.04802956e+00 5.64039409e-01   -9.22413793e-01]   [ 1.66901077e-16 -4.13793103e-01 8.79310345e-01 -1.72413793e-01   8.10344828e-01]   [ 2.14285714e-01 -6.65024631e-02 1.85960591e-01 -8.12807882e-02   -1.46551724e-01]]3. 矩阵的对称  from numpy import *    A = mat([[1,2,4,5,7,],[9,12,11,8,2,],[6,4,3,2,1,],[9,1,3,4,5],[0,2,3,4,1]])  AT = A.T #矩阵的对称  print A*AT

输出结果如下。  [[ 95 131 43 78 43]   [131 414 153 168 91]   [ 43 153 66 80 26]   [ 78 168 80 132 32]   [ 43 91 26 32 30]]4. 矩阵的秩  from numpy import *    A = mat([[1,2,4,5,7,],[9,12,11,8,2,],[6,4,3,2,1,],[9,1,3,4,5],[0,2,3,4,1]])  print linalg.matrix_rank(A) #矩阵的秩

输出结果如下。  55. 可逆矩阵求解  from numpy import *    A = mat([[1,2,4,5,7,],[9,12,11,8,2,],[6,4,3,2,1,],[9,1,3,4,5],[0,2,3,4,1]])  b = [1,0,1,0,1]   S = linalg.solve(A,T(b))  print S

输出结果如下。  [-0.0270936 1.77093596 -3.18472906 1.68965517 0.25369458]1.3 机器学习的数学基础

在1.2节中我们建立了矩阵的概念,并介绍了矩阵基本运算的Python实现。从本节开始,我们学习有关机器学习的一些最基本的数学概念。一谈到数学,大多数人的感觉就一个字:晕。其实,数学让人觉得难的地方不外乎两点:一是语言符号非常简练;二是理论描述比较抽象。长久以来,数学研究的是客观世界的空间形式与数量性质,即事物在时空中的普遍存在与运动的规律。因为反映本质,所以才精练;因为应用普遍,所有才抽象。

现代数学有三个重要的基石:概率论、数值分析、线性代数。概率论说明了事物可能会是什么样;数值分析揭示了它们为什么这样,以及如何变成这样;线性代数则告诉我们事物从来不只有一个样子,使我们能从多个角度来观察事物。1.3.1 相似性的度量

继续以1.1节的表1.5为例,我们做出如下的精简,如表1.7所示。表1.7 精简的大型动物和水果表

其中每个对象都是一个特征向量,从直觉上,我们可将其分为两大类。● 大型动物:非洲象、大白鲨。● 水果:苹果、梨。

因为非洲象和大白鲨都很大,生命周期也都很长,相比之下苹果和梨要小得多,保质期也都很短。很大、很长对很小、很短是在量上的比较,因此,利用初等数学的知识,这些给定数值的对象就可以看作一个n维坐标系下的点,并通过点与点之间的距离来度量。

两个向量之间的距离(此时向量作为n维坐标系中的点)计算,在数学上称为向量的距离(Distance),也称为样本之间的相似性度量(Similarity Measurement)。它反映为某类事物在距离上接近或远离的程度。直觉上,距离越近的就越相似,越容易归为一类;距离越远就越不同。但这个直觉的标准是什么呢?换句话说,这么划分的依据是什么呢?由此,我们引出向量间的各类距离公式。下面这些距离公式从不同角度对向量间的距离定义了衡量标准。

在引入距离公式之前,我们先看一个概念。

范数(来自百度百科):向量的范数可以简单、形象地理解为向量的长度,或者向量到坐标系原点的距离,或者相应空间内的两点之间的距离。

向量的范数定义:向量的范数是一个函数||x||,满足非负性||x||≥0,齐次性||cx|| = |c| ||x||,三角不等式||x+y||≤||x||+||y||。

L1范数:||x||为x向量各个元素绝对值之和。

L2范数:||x||为x向量各个元素平方和的开方。L2范数又称Euclidean范数或者Frobenius范数。

Lp范数:||x||为x向量各个元素绝对值p次方和的1/p次方。

L∞范数:||x||为x向量各个元素绝对值最大的那个元素,如下:

向量范数的运算如下。  A = [8,1,6]  # 手工计算  modA = sqrt(sum(power(A,2)))  print "modA:",modA  # 库函数  normA = linalg.norm(A)  print "norm(A):",normA

输出结果如下。  modA: 10.0498756211  norm(A): 10.04987562111.3.2 各类距离的意义与Python实现

本小节所列的距离公式列表和代码如下:● 闵可夫斯基距离(Minkowski Distance)。● 欧氏距离(Euclidean Distance)。● 曼哈顿距离(Manhattan Distance)。● 切比雪夫距离(Chebyshev Distance)。● 夹角余弦(Cosine)。● 汉明距离(Hamming Distance)。● 杰卡德相似系数(Jaccard Similarity Coefficient)。1. 闵可夫斯基距离(Minkowski Distance)

严格意义上讲,闵可夫斯基距离不是一种距离,而是一组距离的定义。

两个n维变量A(x11,x12,…,x1n)与B(x21,x22,…,x2n)间的闵可夫斯基距离定义为:

其中p是一个变参数。● 当p=1时,就是曼哈顿距离。● 当p=2时,就是欧氏距离。● 当p→∞时,就是切比雪夫距离。

根据变参数的不同,闵可夫斯基距离可以表示一类的距离。2. 欧氏距离(Euclidean Distance)

欧氏距离(L2范数)是最易于理解的一种距离计算方法,源自欧氏空间中两点间的距离公式,如图1.9所示。图1.9 A、B两点间的欧式距离dist(A,B)(1)二维平面上两点a(x1,y1)与b(x2,y2)间的欧氏距离:(2)三维空间两点A(x1,y1,z1)与B(x2,y2,z2)间的欧氏距离:(3)两个n维向量A(x11,x12,…,x1n)与B(x21,x22,…,x2n)间的欧氏距离:

表示为向量运算的形式:(4)Python实现欧式距离。  from numpy import *    vector1 = mat([1,2,3])  vector2 = mat([4,5,6])  print sqrt((vector1-vector2)*((vector1-vector2).T))

输出结果如下。  [[ 5.19615242]]3. 曼哈顿距离(Manhattan Distance)

从名字就可以猜出这种距离的计算方法了。想象你在曼哈顿要从一个十字路口开车到另外一个十字路口,驾驶距离是两点间的直线距离吗?显然不是,除非你能穿越大楼。实际驾驶距离就是这个“曼哈顿距离”(L1范数),而这也是曼哈顿距离名称的来源。曼哈顿距离也称为城市街区距离(City Block distance),如图1.10所示。图1.10 A、B两点间的曼哈顿距离为红色、蓝色、黄色线条(1)二维平面两点A(x1,y1)与B(x2,y2)间的曼哈顿距离:d12=|x1 - x2|+|y1 - y1|(2)两个n维向量A(x11,x12,…,x1n)与B(x21,x22,…,x2n)间的曼哈顿距离:(3)Python实现曼哈顿距离。  from numpy import *    vector1 = mat([1,2,3])  vector2 = mat([4,5,6])  print sum(abs(vector1-vector2))

输出结果如下。  94. 切比雪夫距离(Chebyshev Distance)

国际象棋玩过吗?国王走一步能够移动到相邻的8个方格中的任意一个,如图1.11所示。那么国王从格子(x1,y1)走到格子(x2,y2)最少需要多少步?自己走走试试。你会发现最少步数总是max(| x2>x1| , |y2>y1|)步。有一种类似的距离度量方法叫作切比雪夫距离(L∞范数)。图1.11 国际象棋与切比雪夫距离(1)二维平面两点A(x1,y1)与B(x2,y2)间的切比雪夫距离:d12 = max(| x1 - x2 |,| y1 - y2 |)(2)两个n维向量A(x11,x12,…,x1n)与B(x21,x22,…,x2n)间的切比雪夫距离:

这个公式的另一种等价形式是:(3)Python实现切比雪夫距离。  from numpy import *    vector1 = mat([1,2,3])  vector2 = mat([4,7,5])  print abs(vector1-vector2).max()

输出结果如下。  55. 夹角余弦(Cosine)

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载