1.3 Python简易教程
Python是一种非常简单易学的解释性语言。由于强大的开源库支持(NumPy、Scipy、Matplotlib),其广泛应用于科学计算中。如果你励志成为一名数据科学家或数据“攻城狮”,那么Python就是你必须要学会的工具之一。接下来我们将简短地介绍下Python、NumPy、Matplotlib的使用,如果你已经十分熟悉这些内容,可以轻松地跳过该章节,直接进入下一章节的学习。本章节教程内容主要参考于斯坦福大学cs228课程的Python教程,具体详情可以使用下列网址查看:
https://github.com/kuleshov/cs228-material/blob/master/tutorials/python/cs228-python-tutorial.ipynb。
1.3.1 Anaconda搭建
Anaconda是开发Python最常用的开源平台之一,已经为你安装了Python中最常用的工具库(NumPy、Matplotlib、Scipy、IPython等),使用起来非常方便,读者可以访问https://www.continuum.io/downloads/网址进行下载。本书的教程将使用Python2.7+版本,因此确保你下载的版本符合我们的要求。在本节中,将逐步学习以下内容。
- Python基本使用:基本数据类型(Containers、Lists、Dictionaries、Sets、Tuples),函数,类;
- NumPy:数组,数组索引,数据类型,数组运算,广播;
- Matplotlib:Plotting,Subplots,Images。
1.3.2 IPython Notebook使用
IPython Notebook(现改名Jupyter Notebook)是一种基于Web技术的交互式计算文档,使用浏览器作为客户端进行交互,其页面被保存为.ipynb的类JSON文件格式,是非常高效的教学演示工具。本书的教学教程主要就使用IPython Notebook进行分模块演示。安装Anaconda时,默认就安装了IPython Notebook,读者只需直接启动即可。
- 启动IPython Notebook
首先启动Jupyter:如图1-1所示,启动dos窗口,将路径转换到文件:“第1章练习-numpy.ipynb”所在路径,然后输入jupyter notebook(或ipython notebook)命令,再按Enter键确认。这时,浏览器会自动启动Jupyer。

图1-1 启动Jupyter Notebook命令行示意图
1.3.3 Python基本用法
Python是一种面向对象的解释型高级编程语言。很多时候,由于其代码具有高可读性,且只需要数行代码就可以表达复杂的功能,使Python看起来简直和伪代码一样。如下列代码所示,为Python实现经典的快速排序算法例子。

1.3.3.1 基本数据类型
和大多数编程语言一样,Python拥有一系列的基本数据类型,比如整型、浮点型、布尔型和字符串等。这些基本数据类型的使用方式和其他语言的使用方式类似。
- 整型和浮点型

- 布尔型
Python实现了所有的布尔逻辑,但使用的是英语单词(and、or、not和xor),而不是我们习惯的操作符(&&和||等)。

- 字符串

也可以将字符串当作是一个对象,有很多的方法,如下列代码所示。

如果想掌握更多关于字符串的应用与操作,有兴趣的读者可以访问以下网址来进行学习:
https://docs.python.org/2/library/stdtypes.html#string-methods。
Python有4种容器类型:列表(Lists)、字典(Dictionaries)、集合(Sets)和元组(Tuples)。
1.3.3.2 列表(Lists)
在Python中,列表相当于数组,但是列表长度可变,且能包含不同类型元素。

如果想掌握更多关于列表的应用与操作,有兴趣的读者可以访问以下网址来进行学习:
https://docs.python.org/2/tutorial/datastructures.html#more-on-lists。
- 切片(Slicing)
为了同时获取列表中的多个元素,Python提供了一种简洁的语法去访问子列表,这就是切片。

- 循环(Loops)
可以按以下方式遍历列表中的每一个元素。

如果想要在循环体内访问每个元素的指针,可以使用内置的枚举(enumerate)函数,注意:起始ID为0。

- 列表解析(List Comprehensions)
在编程的时候,我们常常要将列表中的每一元素使用特定的表达式进行转换。下面是一个简单例子,将列表中的每个元素转换成它的平方。

也可以使用更简单的列表解析(List Comprehension)。

列表解析也可以包含条件语句。

1.3.3.3 字典(Dictionaries)

字典用来存储(键,值)对,其和Java中的Map差不多。字典的详细用法可以访问https://docs.python.org/2/library/stdtypes.html#dict网址来进行学习。
- 迭代字典

也可以使用iteritems方法进行迭代。

- 字典解析(Dictionary Comprehensions)
和列表解析类似,字典解析允许你轻松地构造字典,如下列代码所示。

1.3.3.4 集合(Sets)
集合存放着无序的不同元素,在Python中,集合使用花括号表示,如果将一个序列转换为集合,那么该序列的重复元素将会被剔除,并且原有的顺序也将被打散。

- 集合循环
虽然集合中的循环语法和列表中的一样,但由于集合是无序的,因此访问集合元素的时候,不能做关于顺序的假设。

- 集合解析(Set Comprehensions)
和字典、列表一样,可以很方便地使用集合解析构建集合。

1.3.3.5 元组(Tuples)
元组是一个(不可改变)有序列表。元组和列表在很多方面都很相似,最大的区别在于元组可以像字典一样使用键/值对,并且还可以作为集合中的元素,而列表不行。如下列代码所示。

1.3.3.6 函数(Functions)
Python使用关键词def来定义函数,如下列代码所示。

也经常使用可选参数来定义函数,如下列代码所示。

1.3.3.7 类(Classes)
在Python中,定义类的语法很直接,如下列代码所示。

1.3.4 NumPy
NumPy是Python中用于科学计算的核心库,其提供了高性能的多维数组对象及相关工具,其用法和MATLAB比较相似,具体详情可以参考如下网址:
http://wiki.scipy.org/NumPy_for_Matlab_Users。
要使用NumPy,首先要导入numpy包:import numpy as np。
1.3.4.1 数组(Arrays)
NumPy中的数组是由相同数据类型组成的网格,可以通过非负整型的元组进行访问,数组维度数量也被称为数组的秩或阶(rank),数组的形状(shape)是一个由整数构成的元组,描述数组不同维度上的大小。我们可以从Python内嵌的列表中创建数组,然后利用方括号访问其中的元素,如下列代码所示。

NumPy同样提供了大量的方法创建数组,如下列代码所示。

- 数组索引
和Python列表类似,NumPy数组也可以使用切片语法,因为数组可以是多维的,所以必须为每个维度指定好切片,如下列代码所示。

切取的子数组实际上是原数组的一份浅备份,因此修改子数组,原始数组也将受到修改,如下列代码所示。

也可以混合整数索引以及切片索引访问数组,但是这会生成一个秩少于原始数组的子数组。注意这和MATLAB处理的数组切片有些不同,NumPy有两种数组切片方式,一是混合整数索引和切片,生成低秩子数组;二是仅使用切片,生成与原始数组同秩的子数组。

- 整型数组索引
当我们使用切片索引数组时,得到的总是原数组的子数组,而整型数组索引允许我们利用其他数组中的数据构建一个新的数组。如下列代码所示。

整型数组索引的一个小技巧是从矩阵的每一行中选择或改变元素,如下列代码所示。

- 布尔型数组索引
布尔型索引可以任意挑选数组中的元素,这种类型索引频繁地用于条件语句下的元素选取。如下列代码所示。

- 数据类型(Data Types)
NumPy提供了大量的数据类型去构造数组,NumPy会尝试猜测你创建的数组的数据类型,但构造函数的数组通常也可选择显式指明其数据类型。如下列代码所示。

更多有关数据类型详细的说明及其用法,有兴趣的读者可以访问如下网址来进行学习:
http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html。
1.3.4.2 数组运算
数组中基本的数学运算操作是按数组元素进行的,并且重载操作以及函数都可以使用,如下列代码所示。

注意:和MATLAB不同,*在NumPy中是按元素乘,而在MATLAB中是矩阵乘。在NumPy中我们使用dot函数计算向量内积(点积)、矩阵乘矩阵及矩阵乘向量等操作。dot可以当作函数在NumPy中使用,也可作为数组对象的实例方法,如下列代码所示。

NumPy还提供了许多有用的数组计算函数,其中最常用的是sum函数。

更多有关NumPy的数学函数的使用,感兴趣的读者可以参考如下网址来进行学习:
http://docs.scipy.org/doc/numpy/reference/routines.math.html。
除了使用数组进行数学计算,我们还频繁地使用reshape或者其他方法操纵数组数据。例如要转置一个矩阵,简单地使用数组对象的T属性即可,如下列代码所示。

1.3.4.3 广播(Broadcasting)
广播提供了强大的机制,允许NumPy在不同形状的数组中执行数学操作。我们经常会遇到小数组和大数组相乘的情况,比如图片数据矩阵与权重矩阵。使用广播机制可以提高代码质量及运算效率。例如要在矩阵的每一行中都加上一个常数向量,可以按如下代码进行操作。

这样操作是可行的,但当矩阵X特别大时,在Python中计算显式循环就将变得非常缓慢。其实将向量v加到矩阵X的每一行就相当于将向量v拷贝多次垂直堆叠成矩阵VV,然后对矩阵X与矩阵VV进行按元素求和操作,也可以实现同样的结果,如下列代码所示。

NumPy广播机制允许我们在不创建多次向量v备份的情况下执行该计算,如下列代码所示。

由于广播机制的原因,即使X的形状为(4,3),v的形状为(3,),表达式y = x + v依然可以执行;这就好像将v拷贝重塑为(4,3)的矩阵,然后进行按元素相加。对两个数组使用广播机制要遵守下列规则。
1.如果数组的秩不同,将秩较小的数组进行扩展,直到两个数组的尺寸长度都一样。
2.如果两个数组在某个维度上的长度是相同的,或者其中一个数组在该维度上的长度为1,那么我们就说这两个数组在该维度上是相容的。
3.如果两个数组在所有维度上都是相容的,它们就能使用广播。
4.广播之后,两个数组的尺寸将和较大的数组尺寸一样。
5.在任何一个维度上,如果一个数组的长度为1,另一个数组长度大于1,那么在该维度上,就好像是对第一个数组进行了复制。
如果感觉没有解释清楚,更多关于广播的详细说明文档可以参考以下网址:
http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html或者更具体的解释可以访问http://wiki.scipy.org/EricsBroadcastingDoc网址。
支持广播机制的函数也被称为通用函数(Universal Functions),可以访问http://docs.scipy.org/doc/numpy/reference/ufuncs.html#available-ufuncs网址来查看所有的通用函数。以下是广播的一些应用。

通过上面内容的介绍,发现广播可以使代码简洁而高效,因此应该尽可能地使用广播操作。以上仅仅是NumPy一些重要的用法,但其功能远不只这些。详细的文档请参考网址:http://docs.scipy.org/doc/numpy/reference/。
1.3.5 Matplotlib
Matplotlib是一个绘图工具库。下面我们简单地介绍下matplotlib.pyplot模块,其用法和MATLAB相似。

- 绘制(Plotting)
Matplotlib最重要的函数就是绘制函数plot,使用plot函数可以绘制2D数据,如下列代码所示,绘制好的图形如图1-2所示。


图1-2 使用plot函数绘制图形
添加标题、说明及坐标轴标记到图表中,如下列代码所示,绘制好的图形如图1-3所示。


图1-3 添加标题、说明与坐标轴标记
- 子图(Subplots)
还可以使用subplot函数在一幅图中绘制不同的子图,如下列代码所示,绘制的子图如图1-4所示。


图1-4 绘制子图
更多关于Matplotlib的内容及其使用,感兴趣的读者可以访问以下网址:http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.subplot来进行学习。