数学建模三剑客 MSN

前言

不管是不是巴萨的球迷,只要你喜欢足球,就一定听说过梅西(Messi)、苏亚雷斯(Suarez)和内马尔(Neymar)这个MSN组合。在众多的数学建模辅助工具中,也有一个犀利无比的MSN组合,他们就是python麾下大名鼎鼎的 Matplotlib + Scipy + Numpy三剑客。

本文是我整理的MSN学习笔记,有些理解可能比较肤浅,甚至是错误的。如果因此误导了某位看官,在工作中造成重大失误或损失,我顶多只能赔偿一顿饭——还得是我们楼下的十元盒饭。特此声明。

文中代码均从我的这台时不时出点问题、闹个情绪的Yoga 3 pro上复制而来,这意味着所有的代码均可在下面的运行环境中顺利运行:

  • pyhton 2.7.8
  • numpy 1.11.1
  • scipy 0.16.1
  • matplotlib 1.5.1

三剑客之Numpy

numpy是一个开源的python科学计算库,包含了很多实用的数学函数,涵盖线性代数、傅里叶变换和随机数生成等功能。最初的numpy其实是scipy的一部分,后来才从scipy中分离出来。

numpy不是python的标准库,需要单独安装。假定你的运行环境已经安装了python包管理工具pip,numpy的安装就非常简单:

数组对象

ndarray是多维数组对象,也是numpy最核心的对象。在numpy中,数组的维度(dimensions)叫做轴(axes),轴的个数叫做秩(rank)。通常,一个numpy数组的所有元素都是同一种类型的数据,而这些数据的存储和数组的形式无关。

下面的例子,创建了一个三维的数组(在导入numpy时,一般都简写成np)。

数据类型

numpy支持的数据类型主要有布尔型(bool)、整型(integrate)、浮点型(float)和复数型(complex),每一种数据类型根据占用内存的字节数又分为多个不同的子类型。常见的数据类型见下表。

类型 描述
bool 用1位存储的布尔类型(值为TRUE或FALSE)
inti 由所在平台决定其精度的整数(一般为int32或int64)
int8 1字节整数
int16 2字节整数
int32 4字节整数
int64 8字节整数
uint8 1字节无符号整数
uint16 2字节无符号整数
uint32 4字节无符号整数
uint64 8字节无符号整数
float16 半精度浮点数(16位),1位符号,5位指数,10位尾数
float32 单精度浮点数(32位),1位符号,8位指数,23位尾数
float64/float 双精度浮点数(64位),1位符号,11位指数,52位尾数
complex64 复数,分别用32位表示实部和虚部
complex128/complex 复数,分别用64位表示实部和虚部

创建数组

通常,我们用np.array()创建数组。如果仅仅是创建一维数组,也可以使用np.arange()或者np.linspace()的方法。np.zeros()、np.ones()、np.eye()则可以构造特殊的数据。np.random.randint()和np.random.random()则可以构造随机数数组。

构造复杂数组

很多时候,我们需要从简单的数据结构,构造出复杂的数组。例如,用一维的数据生成二维格点。

重复数组: tile

一维数组网格化: meshgrid

指定范围和分割方式的网格化: mgrid

上面的例子中用到了虚数。构造虚数的方法如下:

数组的属性

numpy的数组对象除了一些常规的属性外,也有几个类似转置、扁平迭代器等看起来更像是方法的属性。扁平迭代器也许是遍历多维数组的一个简明方法,下面的代码给出了一个例子。

改变数组维度

numpy数组的存储顺序和数组的维度是不相干的,因此改变数组的维度是非常便捷的操作,除resize()外,这一类操作不会改变所操作的数组本身的存储顺序。

索引和切片

对于一维数组的索引和切片,numpy和python的list一样,甚至更灵活。

假设有一栋2层楼,每层楼内的房间都是3排4列,那我们可以用一个三维数组来保存每个房间的居住人数(当然,也可以是房间面积等其他数值信息)。

数组合并

数组合并除了下面介绍的水平合并、垂直合并、深度合并外,还有行合并、列合并,以及concatenate()等方式。假如你比我还懒,那就只了解前三种方法吧,足够用了。

数组拆分

拆分是合并的逆过程,概念是一样的,但稍微有一点不同:

数组运算

数组和常数的四则运算,是数组的每一个元素分别和常数运算;数组和数组的四则运算则是两个数组对应元素的运算(两个数组有相同的shape,否则抛出异常)。

特别提示:如果想对数组内符合特定条件的元素做特殊处理,下面的代码也许有用。

数组方法和常用函数

数组对象本身提供了计算算数平均值、求最大最小值等内置方法,numpy也提供了很多实用的函数。为了缩减篇幅,下面的代码仅以一维数组为例,展示了这些方法和函数用法。事实上,大多数情况下这些方法和函数对于多维数组同样有效,只有少数例外,比如compress函数。

矩阵对象

matrix是矩阵对象,继承自ndarray类型,因此含有ndarray的所有数据属性和方法。不过,当你把矩阵对象当数组操作时,需要注意以下几点:

  • matrix对象总是二维的,即使是展平(ravel函数)操作或是成员选择,返回值也是二维的
  • matrix对象和ndarray对象混合的运算总是返回matrix对象

创建矩阵

matrix对象可以使用一个Matlab风格的字符串来创建(以空格分隔列,以分号分隔行的字符串),也可以用数组来创建。

矩阵的特有属性

矩阵有几个特有的属性使得计算更加容易,这些属性有:

矩阵乘法

对ndarray对象而言,星号是按元素相乘,dot()函数则当作矩阵相乘。对于matrix对象来说,星号和dot()函数都是矩阵相乘。特别的,对于一维数组,dot()函数实现的是向量点乘(结果是标量),但星号实现的却不是差乘。

线性代数模块

numpy.linalg 是numpy的线性代数模块,可以用来解决逆矩阵、特征值、线性方程组以及行列式等问题。

计算逆矩阵

尽管matrix对象本身有逆矩阵的属性,但用numpy.linalg模块求解矩阵的逆,也是非常简单的。

计算行列式

如何计算行列式,我早已经不记得了,但手工计算行列式的痛苦,我依然记忆犹新。现在好了,你在手机上都可以用numpy轻松搞定(前提是你的手机上安装了python + numpy)。

计算特征值和特征向量

截至目前,我的工作和特征值、特征向量还有没任何关联。记录这一节,纯粹是为了我女儿,她正在读数学专业。

求解线性方程组

有线性方程组如下:

x – 2y + z = 0
2y -8z = 8
-4x + 5y + 9z = -9

求解过程如下:

三剑客之Matplotlib

matplotlib 是python最著名的绘图库,它提供了一整套和Matlab相似的命令API,十分适合交互式地进行制图。而且也可以方便地将它作为绘图控件,嵌入GUI应用程序中。matplotlib 可以绘制多种形式的图形包括普通的线图,直方图,饼图,散点图以及误差线图等;可以比较方便的定制图形的各种属性比如图线的类型,颜色,粗细,字体的大小等;它能够很好地支持一部分 TeX 排版命令,可以比较美观地显示图形中的数学公式。

Demo

pylot介绍

Matplotlib 包含了几十个不同的模块, 如 matlab、mathtext、finance、dates 等,而 pylot 则是我们最常用的绘图模块,这也是本文介绍的重点。

中文显示问题的解决方案

有很多方法可以解决此问题,但下面的方法恐怕是最简单的解决方案了(我只在windows平台上测试过,其他平台请看官自测)。如果想了解更多,也可以参考我N年前的一片博文:matplotlib显示中文的解决方案

绘制最简单的图形

最简单的正弦曲线

设置标题、坐标轴名称、坐标轴范围

如果你在python的shell中运行下面的代码,而shell的默认编码又不是utf-8的话,中文可能仍然会显示为乱码。你可以尝试着把 u’正弦曲线’ 写成 ‘正弦曲线’.decode(‘gbk’)或者‘正弦曲线’.decode(‘utf-8’)

设置标题和坐标轴

设置点和线的样式、宽度、颜色

plt.plot函数的调用形式如下:

  1. color指定线的颜色,可简写为“c”。颜色的选项为:
    • 蓝色: ‘b’ (blue)
    • 绿色: ‘g’ (green)
    • 红色: ‘r’ (red)
    • 墨绿: ‘c’ (cyan)
    • 洋红: ‘m’ (magenta)
    • 黄色: ‘y’ (yellow)
    • 黑色: ‘k’ (black)
    • 白色: ‘w’ (white)
    • 灰度表示: e.g. 0.75 ([0,1]内任意浮点数)
    • RGB表示法: e.g. ‘#2F4F4F’ 或 (0.18, 0.31, 0.31)
  2. linestyle指定线型,可简写为“ls”。线型的选项为:
    • 实线: ‘-’ (solid line)
    • 虚线: ‘–’ (dashed line)
    • 虚点线: ‘-.’ (dash-dot line)
    • 点线: ‘:’ (dotted line)
    • 无: ”或’ ‘或’None’
  3. linewidth指定线宽,可简写为“lw”。
  4. marker描述数据点的形状
    • 点线: ‘.’
    • 点线: ‘o’
    • 加号: ‘+
    • 叉号: ‘x’
    • 上三角: ‘^’
    • 上三角: ‘v’
  5. markerfacecolor指定数据点标记的表面颜色,可 简写为“ mfc”。
  6. markersize指定数据点标记的大小,可 简写为“ ms”。

文本标注和图例

我们分别使用不同的线型、颜色来绘制以10、e、2为基的一组幂函数曲线,演示文本标注和图例的使用。

这里写图片描述

在绘制图例时,loc用于指定图例的位置,可用的选项有:

  • best
  • upper right
  • upper left
  • lower left
  • lower right

绘制多轴图

在介绍如何将多幅子图绘制在同一画板的同时,顺便演示如何绘制直线和矩形。我们可以使用subplot函数快速绘制有多个轴的图表。subplot函数的调用形式如下:

subplot将整个绘图区域等分为numRows行 * numCols列个子区域,然后按照从左到右,从上到下的顺序对每个子区域进行编号,左上的子区域的编号为1。如果numRows,numCols和plotNum这三个数都小于10的话,可以把它们缩写为一个整数,例如subplot(323)和subplot(3,2,3)是相同的。subplot在plotNum指定的区域中创建一个轴对象。如果新创建的轴和之前创建的轴重叠的话,之前的轴将被删除。

绘制多轴图

常用绘图类型

直方图

用numpy随机生成一个符合正态分布的数据集,统计分段区域内数据的个数。

直方图

散点图

使用plot()绘图时,如果指定样式参数为仅绘制数据点(linestyle=’None’),那么所绘制的就是一幅散列图。这种方法所绘制的点无法单独指定数据点的颜色和大小,而使用scatter()绘制散列图就可以指定每个点的颜色和大小。

plt.scatter函数的调用形式如下:

scatter()的前两个参数是数组,分别指定每个点的X轴和Y轴的坐标。s参数指定点的大 小,值和点的面积成正比,它可以是一个数,指定所有点的大小,也可以是数组,分别对每个点指定大小。c参数指定每个点的颜色,可以是数值或数组。这里使用一维数组为每个点指定了一个数值。通过颜色映射表,每个数值都会与一个颜色相对应。默认的颜色映射表中蓝色与最小值对应,红色与最大值对应。当c参数是形状为(N,3)或(N,4)的二维数组时,则直接表示每个点的RGB颜色。marker参数设置点的形状,可以是个表示形状的字符串,也可以是表示多边形的两个元素的元组,第一个元素表示多边形的边数,第二个元素表示多边形的样式,取值范围为0、1、2、3。0表示多边形,1表示星形,2表示放射形,3表示忽略边数而显示为圆形。alpha参数设置点的透明度。facecolors参数为“none”时,表示散列点没有填充色。