<用python进行科学计算>.pdf
用Python做科学计算 Release 1 HYRY Studio 2010/01/09 目录 I 基础篇 3 1 软件包的安装和介绍 1.1 安装软件包 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.1 5 安装 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Python(x,y) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Enthought Python Distribution (EPD) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.1.2 1.2 5 工具 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 iPython . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 spyder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 函数库介绍 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.2.1 数值计算库 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.2.2 符号计算库 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.2.3 界面设计 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.2.4 绘图与可视化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.2.5 图像处理和计算机视觉 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2 NumPy-快速处理数据 2.1 13 ndarray对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.1.1 创建 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.1.2 存取元素 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 2.1.3 多维数组 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 2.1.4 结构数组 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.1.5 内存结构 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 2.2 ufunc运算 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.2.1 广播 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 2.2.2 ufunc的方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 2.3 矩阵运算 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 i 2.4 文件存取 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 3 SciPy-数值计算库 3.1 最小二乘拟合 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 3.2 函数最小值 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 3.3 非线性方程组求解 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 3.4 B-Spline样条曲线 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 3.5 数值积分 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 3.6 解常微分方程组 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 3.7 滤波器设计 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 3.8 用Weave嵌入C语言 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 4 SymPy-符号运算好帮手 57 4.1 封面上的经典公式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 4.2 球体体积 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 5 matplotlib-绘制精美的图表 5.1 63 快速绘图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 5.1.1 配置属性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 5.2 绘制多轴图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 5.3 配置文件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 5.4 Artist对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 5.4.1 Artist的属性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 5.4.2 Figure容器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 5.4.3 Axes容器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 5.4.4 Axis容器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 6 Traits-为Python添加类型定义 83 6.1 背景 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 6.2 Traits是什么 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 6.3 动态添加Trait属性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 6.4 Property属性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 6.5 Trait属性监听 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 7 TraitsUI-轻松制作用户界面 95 7.1 缺省界面 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 7.2 自定义界面 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 7.2.1 Item对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 7.2.2 Group对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 7.3 配置视图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 7.3.1 ii 41 视图类型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 7.3.2 命令按钮 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 8 Chaco-交互式图表 105 8.1 面向脚本绘图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 8.2 面向应用绘图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 8.2.1 容器(Container)概述 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 8.2.2 编辑绘图属性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 9 TVTK-三维可视化数据 9.1 117 TVTK使用简介 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 9.1.1 显示圆锥 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 9.1.2 用ivtk观察流水线 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 9.1.3 从文件读取数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 9.1.4 过滤数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 9.1.5 控制照相机 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 9.1.6 控制照明 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 9.1.7 控制3D Props . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 9.2 TVTK的改进 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 9.2.1 TVTK的基本用法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 9.2.2 Trait属性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 9.2.3 序列化(Pickling) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 9.2.4 集合迭代 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 9.2.5 数组操作 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 9.2.6 TVTK是什么 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 10 Mayavi-更方便的可视化 135 10.1 用mlab快速绘图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 11 Visual-制作3D演示动画 141 11.1 场景、物体和照相机 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 11.2 简单动画 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143 11.3 盒子中反弹的球 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 12 OpenCV-图像处理和计算机视觉 149 12.1 读写图像和视频文件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 II 手册篇 153 13 Traits使用手册 155 13.1 traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 13.1.1 定义Traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 iii 预定义的Traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 Trait的元数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 13.1.2 Trait事件处理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 静态命名的事件处理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 13.2 traits.ui . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 13.2.1 设计自己的Trait编辑器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 Trait编辑器的工作原理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 制作matplotlib的编辑器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 CSV数据绘图工具 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 14 Visual使用手册 179 14.1 场景窗口 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 14.1.1 控制场景窗口 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 14.1.2 控制照相机 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 实战篇 185 15 声音的输入输出 187 III 15.1 读写Wave文件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 15.1.1 读Wave文件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 15.1.2 写Wave文件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 15.2 用pyAudio播放和录音 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 15.2.1 播放 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 15.2.2 录音 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 15.3 用pyMedia播放Mp3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 16 数字信号系统 195 16.1 FIR和IIR滤波器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 16.2 FIR滤波器设计 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 16.2.1 用firwin设计滤波器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 16.2.2 用remez设计滤波器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 16.2.3 滤波器级联 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206 16.3 IIR滤波器设计 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207 16.3.1 巴特沃斯低通滤波器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207 16.3.2 双线性变换 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 16.4 滤波器的频率响应 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 16.5 二次均衡器设计工具 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 17 FFT演示程序 219 17.1 FFT知识复习 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219 17.2 合成时域信号 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 iv 17.3 三角波FFT演示程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226 18 频域信号处理 233 18.1 观察信号的频谱 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 18.1.1 窗函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 18.1.2 频谱平均 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240 18.2 快速卷积 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242 18.2.1 分段运算 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 18.3 Hilbert变换 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247 19 Ctypes和NumPy 251 19.1 用ctypes加速计算 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251 19.2 用ctypes调用DLL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251 19.3 numpy对ctypes的支持 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 20 自适应滤波器和NLMS模拟 257 20.1 自适应滤波器简介 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 20.1.1 系统辨识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 20.1.2 信号预测 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258 20.1.3 信号均衡 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 20.2 NLMS计算公式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 20.3 NumPy实现 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 20.3.1 系统辨识模拟 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 20.3.2 信号均衡模拟 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266 20.3.3 卷积逆运算 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269 20.4 DLL函数的编写 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 20.5 ctypes的python接口 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 21 单摆和双摆模拟 273 21.1 单摆模拟 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 21.1.1 计算摆动周期 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 21.2 双摆模拟 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277 21.2.1 公式推导 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277 21.2.2 微分方程的数值解 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280 21.2.3 动画显示 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284 22 分形与混沌 287 22.1 Mandelbrot集合 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 22.1.1 连续的逃逸时间 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293 22.2 迭代函数系统(IFS) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 22.2.1 2D仿射变换 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298 v 22.2.2 迭代函数系统设计器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 22.3 L-System分形 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 IV 附录 307 23 关于本书的编写 309 23.1 本书的编写工具 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 23.2 问题与解决方案 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 23.2.1 代码中的注释 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 23.2.2 修改Sphinx的主题 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 23.2.3 关闭引号自动转换 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 23.2.4 用latex编写数学公式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 23.2.5 Leo的配置 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 23.2.6 让Matplotlib显示中文 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314 23.2.7 用Matplotlib生成图片 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314 23.2.8 用Graphviz绘图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315 23.2.9 制作CHM文档 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316 23.2.10 CHM中嵌入Flash动画 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317 23.2.11 制作PDF文档 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317 23.2.12 输出打包的批处理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319 23.3 ReST使用心得 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 23.3.1 为PDF的插图添加编号和标题 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 23.3.2 插入大段代码 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 23.4 未解决的问题 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 24 最近更新 323 V 325 源程序集 25 源程序集 327 25.1 三角波的FFT演示 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327 25.2 在traitsUI中使用的matplotlib控件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332 25.3 CSV文件数据图形化工具 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 25.4 NLMS算法的模拟测试 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339 25.5 频谱泄漏和hann窗 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341 25.6 FFT卷积的速度比较 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342 25.7 二次均衡器设计 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344 25.8 单摆摆动周期的计算 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350 25.9 双摆系统的动画模拟 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351 25.9.1 vi 用odeint解双摆系统 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 25.9.2 摆动动画 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 25.10绘制Mandelbrot集合 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355 25.10.1 纯Python计算版本 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356 25.10.2 Weave版本 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356 25.10.3 NumPy加速版本 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358 25.10.4 平滑版本 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359 25.11迭代函数系统的分形 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361 25.11.1 迭代函数系统设计器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363 25.12绘制L-System的分形图 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373 vii viii 用Python做科学计算 版权说明 本书的著作权归作者(HYRY Studio)所有。你可以: • 下载、保存以及打印本书 • 网络链接、转载本书的部分或者全部内容,但是必须在明显处提供读者访问本书发布网站的 链接 • 在你的程序中任意使用本书所附的程序代码,但是由本书的程序所引起的任何问题,作者不 承担任何责任 你不可以: • 以任何形式出售本书的电子版或者打印版 • 擅自印刷、出版本书 • 以纸媒出版为目的,改写、改编以及摘抄本书的内容 • 在课程设计、毕业设计以及作业中大段摘抄本书文字,或直接使用本书的程序代码 使用说明 本书使用reStructuredText编写,采用Sphinx发布。在此基础上添加了评论功能,你可以点击章 节标题前面的评论按钮对每个章节进行评论。推荐使用IE7.0以上、FireFox、Google Chome等 浏览器阅读本书。 请使用下面的链接下载各种打包版本,其中Html打包版本格式最为正确,CHM和PDF版都多少 有些问题。 下载Html打包版 下载CHM版 下载PDF版 下载源代码 本书有两个镜像地址: • http://hyry.dip.jp/pydoc (每日更新) • http://pyscin.appspot.com/html/index.html (每周更新) 如果上述地址均无法访问,你还可以通过Google文档下载PDF版本 请查看 最近更新 了解最新添加的内容 关于HYRY Studio • HYRY Studio首页: http://hyry.dip.jp • 博客地址: http://hyry.dip.jp/blogt.py Python是一种面向对象的、动态的程序设计语言。具有非常简洁而清晰的语法,适合于完成各种高层 任务。它既可以用来快速开发程序脚本,也可以用来开发大规模的软件。 随着NumPy, SciPy, Matplotlib, Enthought librarys等众多程序库的开发,Python越来越适合于做科 学计算、绘制高质量的2D和3D图像。和科学计算领域最流行的商业软件Matlab相比,Python是一门 通用的程序设计语言,比Matlab所采用的脚本语言的应用范围更广泛,有更多的程序库的支持。虽然 Matlab中的许多高级功能和toolbox目前还是无法替代的,不过在日常的科研开发之中仍然有很多的 目录 1 用Python做科学计算 工作是可以用Python代劳的。 本书将介绍如何用Python开发科学计算的应用程序,除了介绍数值计算之外,我们还将着重介绍如何 制作交互式的2D、3D图像;如何设计精巧的程序界面;如何和C语言所编写的高速计算程序结合;如 何编写声音、图像处理算法。 阅读本书你需要学习过Python语言的一些基础知识,对面向对象的程序开发有所了解。有关Python语 言基础的知识,可以参考: 啄木鸟社区的Python图书概览: http://wiki.woodpecker.org.cn/moin/PyBooks 本书中的所有示例均在Windows XP系统下采用Python(x,y)通过测试。如果你觉得安装众多的Python 程序库很麻烦,不妨下载安装Python(x,y)。请阅读:软件包的安装和介绍 2 目录 部分 I 基础篇 3 第 1 章 软件包的安装和介绍 1.1 安装软件包 1.1.1 安装 和Matlab不同,Python的科学软件包由众多的社区维护和发布,因此要一一将其收集齐安装到你的电 脑里是一件很费时间的事情。幸好这些工作已经有人帮我们整理好了。只需要下载一个文件,一次安 装就能拥有众多的函数库可供使用。 这里介绍两个科学计算Python合集的下载和安装过程。 Python(x,y) http://www.pythonxy.com 发布的Python(x,y)将近400M,收集了众多的函数库以及文档、教程。并 且提供了一个方便的启动界面: 5 用Python做科学计算 图 1.1 - Python(x,y)的启动画面 • Shortcuts:启动各种应用程序 • Documentation:打开各个软件包的文档 • About:查看所安装的程序库的版本信息 Enthought Python Distribution (EPD) 下载地址:http://www.enthought.com/products/getepd.php EPD是一个商业的Python发行版 本,同样包括了众多的科学软件包,而且作为教学使用是免费的,大小约为250M。 1.1.2 工具 安装好了之后先看看下面这些常用的工具,在以后的学习过程中会经常用到。 iPython ipython 是一个 python 的交互式 shell,比默认的 python shell 好用得多,支持变量自动补全,自动 缩近,支持 bash shell 命令,内置了许多很有用的功能和函数。 如果你安装了Python(x,y)的话,可以从Python(x,y)的启动界面中运行iPython。 6 第1章 软件包的安装和介绍 用Python做科学计算 图 1.2 - 通过Python(x,y) Home启动IPython的各种选项 从下拉选择框中选择你想运行的iPython,然后点击后面的①或者②按钮启动iPython。下拉选择框中 的IPython(x,y)、IPython(Qt)、IPython(wxPython)和IPython(mlab)等几个选项都是启动iPython, 只不过它们的启动方式不同。而Python选项则只启动单纯的Python Shell。 选项 参数 IPython(x,y) -pylab -p xy IPython(Qt) -q4thread IPython(wxPython) -wthread IPython(mlab) -wthread 含义 点击①按钮将用一个叫做Console的软件启动Shell,此软件在窗口中显示Shell,并且支持多标签,但 是不支持中文输入和显示。点击②按钮用Windows自带的Cmd启动Shell。 如果你用python(x,y)的启动界面通过IPython(x,y)运行iPython的话,那么在iPython打开之后自动运 行一个default.py脚本。此脚本缺省执行以下的函数库导入: import numpy import scipy from numpy import * 为了和numpy, scipy等社区的推荐的标准导入方式一致,请点击按钮③,然后在打开的文件夹中添加 一个名为numpy.py的文件,编辑此文件,添加以下几行推荐的导入: import numpy as np import scipy as sp import pylab as pl 1.1. 安装软件包 7 用Python做科学计算 此后运行IPython(x,y)的时候请记着要选择numpy.py为启动脚本。 如果要使用pylab,TraitsUI等在shell中和图形界面进行交互的话,需要选择带-wthread参数的选项 (-pylab也可以)。下面是一个用pylab绘制sin波形图的例子: 图 1.3 - 使用IPython交互式地绘制正弦波 在iPython的交互中可以方便地使用如下功能: • 自动补全:输入一部分文字之后按tab键,iPython将列出所有以输入补全信息。 • 查看文档:输入需要查看文档的函数,然后在后面添加?或者??,?表示查看函数的文档,??表示 查看其Python源代码,如果函数不是Python写的,则查看不到。 • 执行cmd命令:ls-列出当前目录下的所有文件,cd-显示或者更改当前路径 • 执行Python程序:用run *.py命令,在IPython中运行指定的py文件。如果加-i参数的话,则在 IPython的命名空间中执行。也就是说在文件中没有定义名称会直接使用在IPython中的。 • 执行剪切板中的程序:你可以从本书中复制代码,然后在IPython命令窗口中执行paste命令运行 复制的代码。如果执行paste foo的话,将把剪切板中的内容复制到变量foo中。变量foo是一个 IPython提供的SList列表类型,它提供了很多操作所复制的内容的方法。 • 执行系统命令:在要执行的系统名字之前添加一个!号。例如执行!test.py的话,那么将让系统运 行test.py文件。和run命令不同的是,test.py完全在另外的进程中运行。 spyder spyder是Python(x,y)的作者为它开发的一个简单的Python开发环境。和其它Python IDE相比它最大 的优点就是模仿MATLAB的workspace功能,可以很方便地观察和修改数组的值。 spyder的项目地址 8 第1章 软件包的安装和介绍 用Python做科学计算 下面是spyder的界面截图: 图 1.4 - 在Spyder中执行图像处理的程序 下面是Workspace的截图,列出了其中的变量名以及类型和大小等信息。鼠标右键可以显示出操作指 定变量的菜单: Warning: Workspace缺省配置不显示大写字母开头的变量,可以在Workspace菜单中修改这项 配置。 图 1.5 - 使用Workspace查看变量内容 选择Plot选项,将出现如下的绘图窗口: 1.1. 安装软件包 9 用Python做科学计算 图 1.6 - 在Workspace中将数组绘制成曲线图 如果Edit选项的话,将出现如下的编辑器对数组进行操作: 图 1.7 - 使用数组编辑器查看和编辑数组内容 1.2 函数库介绍 Python的科学计算方面的内容由许多库构成,在基础篇中让我们首先来了解一下编写科学计算软件时 经常使用的一些库。 1.2.1 数值计算库 NumPy为Python提供了快速的多维数组处理的能力,而SciPy则在NumPy基础上添加了众多的科学 计算所需的各种工具包,有了这两个库,Python就有几乎和Matlab一样的处理数据和计算的能力了。 NumPy和SciPy官方网址: http://www.scipy.org NumPy为Python带来了真正的多维数组功能,并且提供了丰富的函数库处理这些数组。它将常用的 数学函数都进行数组化,使得这些数学函数能够直接对数组进行操作,将本来需要在Python级别进行 的循环,放到C语言的运算中,明显地提高了程序的运算速度。 SciPy的核心计算部分都是一些久经考验的Fortran数值计算库,例如: 10 第1章 软件包的安装和介绍 用Python做科学计算 • 线性代数使用LAPACK库 • 快速傅立叶变换使用FFTPACK库 • 常微分方程求解使用ODEPACK库 • 非线性方程组求解以及最小值求解等使用MINPACK库 1.2.2 符号计算库 SymPy是一套进行符号数学运算的Python函数库,虽然它目前还没有到达1.0版本,但是已经足够好 用,可以帮助我们进行公式推导,进行符号求解。 SymPy官方网址: http://code.google.com/p/sympy 1.2.3 界面设计 制作界面一直都是一件十分复杂的工作,使用Traits库,你将再也不会在界面设计上耗费大量精力,从 而能把注意力集中到如何处理数据上去。 Traits官方网址: http://code.enthought.com/projects/traits Traits库分为Traits和TraitsUI两大部分,Traits为Python添加了类型定义的功能,使用它定义的traits 属性具有初始化、校验、代理、事件等诸多功能。 TraitsUI库基于Traits库,使用MVC结构快速地定义用户界面,在最简单的情况下,你甚至不需要写一 句关于界面的代码,就可以通过traits属性定义获得一个可以工作的用户界面。使用TraitsUI库编写的 程序自动支持wxPython和pyQt两个经典的界面库。 1.2.4 绘图与可视化 Chaco和matplotlib是很优秀的2D绘图库,Chaco库和Traits库紧密相连,方便制作动态交互式的图表 功能。而matplotlib库则能够快速地绘制精美的图表、以多种格式输出,并且带有简单的3D绘图的功 能。 Chaco官方网址: http://code.enthought.com/projects/chaco matplotlib官方网址: http://matplotlib.sourceforge.net TVTK库在标准的VTK库之上用Traits库进行封装,如果要在Python下使用VTK,用TVTK是再好不过的 选择。Mayavi2则在TVTK的基础上再添加了一套面向应用的方便工具,它既可以单独作为3D可视化程 序使用,也可以快速地嵌入到用户的程序中去。 Mayavi2官方网址: http://code.enthought.com/projects/mayavi 1.2. 函数库介绍 11 用Python做科学计算 VTK(Visualization Toolkit) 视觉化工具函式库(VTK, Visualization Toolkit)是一个开放源码,跨平台、支援平行处理 (VTK曾用于处理大小近乎1个Petabyte的资料,其平台为美国Los Alamos国家实验室所有的具 1024个处理器之大型系统)的图形应用函式库。2005年实曾被美国陆军研究实验室用于即时模 拟俄罗斯制反导弹战车ZSU23-4受到平面波攻击的情形,其计算节点高达2.5兆个之多。 -- 摘自 维基百科 此外,使用Visual库能够快速、方便地制作3D动画演示,使你的数据结果更有说服力。 Visual官方网址: http://vpython.org 1.2.5 图像处理和计算机视觉 OpenCV是由英特尔公司发起并参与开发,以BSD许可证授权发行,可以在商业和研究领域中免费使 用。OpenCV可用于开发实时的图像处理、计算机视觉以及模式识别程序。OpenCV提供的Python API方便我们快速实现算法,查看结果并且和其它的库进行数据交换。 12 第1章 软件包的安装和介绍 第 2 章 NumPy-快速处理数据 标准安装的Python中用列表(list)保存一组值,可以用来当作数组使用,不过由于列表的元素可以是任 何对象,因此列表中所保存的是对象的指针。这样为了保存一个简单的[1,2,3],需要有3个指针和三个 整数对象。对于数值运算来说这种结构显然比较浪费内存和CPU计算时间。 此外Python还提供了一个array模块,array对象和列表不同,它直接保存数值,和C语言的一维数组比 较类似。但是由于它不支持多维,也没有各种运算函数,因此也不适合做数值运算。 NumPy的诞生弥补了这些不足,NumPy提供了两种基本的对象:ndarray(N-dimensional array object)和 ufunc(universal function object)。ndarray(下文统一称之为数组)是存储单一数据类 型的多维数组,而ufunc则是能够对数组进行处理的函数。 2.1 ndarray对象 函数库的导入 本书的示例程序假设用以下推荐的方式导入NumPy函数库: import numpy as np 2.1.1 创建 首先需要创建数组才能对其进行其它操作。 13 用Python做科学计算 我们可以通过给array函数传递Python的序列对象创建数组,如果传递的是多层嵌套的序列,将创建多 维数组(下例中的变量c): >>> a = np.array([1, 2, 3, 4]) >>> b = np.array((5, 6, 7, 8)) >>> c = np.array([[1, 2, 3, 4],[4, 5, 6, 7], [7, 8, 9, 10]]) >>> b array([5, 6, 7, 8]) >>> c array([[1, 2, 3, 4], [4, 5, 6, 7], [7, 8, 9, 10]]) >>> c.dtype dtype('int32') 数组的大小可以通过其shape属性获得: >>> a.shape (4,) >>> c.shape (3, 4) 数组a的shape只有一个元素,因此它是一维数组。而数组c的shape有两个元素,因此它是二维数组, 其中第0轴的长度为3,第1轴的长度为4。还可以通过修改数组的shape属性,在保持数组元素个数不 变的情况下,改变数组每个轴的长度。下面的例子将数组c的shape改为(4,3),注意从(3,4)改为(4,3)并 不是对数组进行转置,而只是改变每个轴的大小,数组元素在内存中的位置并没有改变: >>> c.shape = 4,3 >>> c array([[ 1, 2, 3], [ 4, 4, 5], [ 6, 7, 7], [ 8, 9, 10]]) 当某个轴的元素为-1时,将根据数组元素的个数自动计算此轴的长度,因此下面的程序将数组c的 shape改为了(2,6): >>> c.shape = 2,-1 >>> c array([[ 1, 2, 3, 4, 4, 5], [ 6, 7, 7, 8, 9, 10]]) 使用数组的reshape方法,可以创建一个改变了尺寸的新数组,原数组的shape保持不变: 14 第2章 NumPy-快速处理数据 用Python做科学计算 >>> d = a.reshape((2,2)) >>> d array([[1, 2], [3, 4]]) >>> a array([1, 2, 3, 4]) 数组a和d其实共享数据存储内存区域,因此修改其中任意一个数组的元素都会同时修改另外一个数组 的内容: >>> a[1] = 100 # 将数组a的第一个元素改为100 >>> d # 注意数组d中的2也被改变了 array([[ [ 1, 100], 3, 4]]) 数组的元素类型可以通过dtype属性获得。上面例子中的参数序列的元素都是整数,因此所创建的数组 的元素类型也是整数,并且是32bit的长整型。可以通过dtype参数在创建时指定元素类型: >>> np.array([[1, 2, 3, 4],[4, 5, 6, 7], [7, 8, 9, 10]], dtype=np.float) array([[ 1., 2., 3., 4.], [ 4., 5., 6., 7.], [ 7., 8., 9., 10.]]) >>> np.array([[1, 2, 3, 4],[4, 5, 6, 7], [7, 8, 9, 10]], dtype=np.complex) array([[ 1.+0.j, 2.+0.j, 3.+0.j, 4.+0.j], [ 4.+0.j, 5.+0.j, 6.+0.j, 7.+0.j], [ 7.+0.j, 8.+0.j, 9.+0.j, 10.+0.j]]) 上面的例子都是先创建一个Python序列,然后通过array函数将其转换为数组,这样做显然效率不高。 因此NumPy提供了很多专门用来创建数组的函数。下面的每个函数都有一些关键字参数,具体用法请 查看函数说明。 • arange函数类似于python的range函数,通过指定开始值、终值和步长来创建一维数组,注意 数组不包括终值: >>> np.arange(0,1,0.1) array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]) • linspace函数通过指定开始值、终值和元素个数来创建一维数组,可以通过endpoint关键字指定 是否包括终值,缺省设置是包括终值: >>> np.linspace(0, 1, 12) array([ 0. 2.1. ndarray对象 , 0.09090909, 0.18181818, 0.27272727, 0.36363636, 15 用Python做科学计算 0.45454545, 0.54545455, 0.90909091, 1. 0.63636364, 0.72727273, 0.81818182, ]) • logspace函数和linspace类似,不过它创建等比数列,下面的例子产生1(10^0)到100(10^2)、 有20个元素的等比数列: >>> np.logspace(0, 2, 20) array([ 1. , 1.27427499, 1.62377674, 2.06913808, 2.6366509 , 3.35981829, 4.2813324 , 5.45559478, 6.95192796, 8.8586679 , 11.28837892, 14.38449888, 18.32980711, 23.35721469, 29.76351442, 37.92690191, 48.32930239, 61.58482111, 78.47599704, 100. ]) 此外,使用frombuffer, fromstring, fromfile等函数可以从字节序列创建数组,下面以fromstring为 例: >>> s = "abcdefgh" Python的字符串实际上是字节序列,每个字符占一个字节,因此如果从字符串s创建一个8bit的整数数 组的话,所得到的数组正好就是字符串中每个字符的ASCII编码: >>> np.fromstring(s, dtype=np.int8) array([ 97, 98, 99, 100, 101, 102, 103, 104], dtype=int8) 如果从字符串s创建16bit的整数数组,那么两个相邻的字节就表示一个整数,把字节98和字节97当作 一个16位的整数,它的值就是98*256+97 = 25185。可以看出内存中是以little endian(低位字节在 前)方式保存数据的。 >>> np.fromstring(s, dtype=np.int16) array([25185, 25699, 26213, 26727], dtype=int16) >>> 98*256+97 25185 如果把整个字符串转换为一个64位的双精度浮点数数组,那么它的值是: >>> np.fromstring(s, dtype=np.float) array([ 8.54088322e+194]) 显然这个例子没有什么意义,但是可以想象如果我们用C语言的二进制方式写了一组double类型的数 值到某个文件中,那们可以从此文件读取相应的数据,并通过fromstring函数将其转换为float64类型 的数组。 我们可以写一个Python的函数,它将数组下标转换为数组中对应的值,然后使用此函数创建数组: 16 第2章 NumPy-快速处理数据 用Python做科学计算 >>> def func(i): ... return i%4+1 ... >>> np.fromfunction(func, (10,)) array([ 1., 2., 3., 4., 1., 2., 3., 4., 1., 2.]) fromfunction函数的第一个参数为计算每个数组元素的函数,第二个参数为数组的大小(shape),因为 它支持多维数组,所以第二个参数必须是一个序列,本例中用(10,)创建一个10元素的一维数组。 下面的例子创建一个二维数组表示九九乘法表,输出的数组a中的每个元素a[i, j]都等于func2(i, j): >>> def func2(i, j): ... return (i+1) * ( j+1) ... >>> a = np.fromfunction(func2, (9,9)) >>> a array([[ 1., 2., 3., 4., 5., 6., 7., 8., 9.], [ 2., 4., 6., 8., 10., 12., 14., 16., 18.], [ 3., 6., 9., 12., 15., 18., 21., 24., 27.], [ 4., 8., 12., 16., 20., 24., 28., 32., 36.], [ 5., 10., 15., 20., 25., 30., 35., 40., 45.], [ 6., 12., 18., 24., 30., 36., 42., 48., 54.], [ 7., 14., 21., 28., 35., 42., 49., 56., 63.], [ 8., 16., 24., 32., 40., 48., 56., 64., 72.], [ 9., 18., 27., 36., 45., 54., 63., 72., 81.]]) 2.1.2 存取元素 数组元素的存取方法和Python的标准方法相同: >>> a = np.arange(10) >>> a[5] # 用整数作为下标可以获取数组中的某个元素 5 >>> a[3:5] # 用范围作为下标获取数组的一个切片,包括a[3]不包括a[5] array([3, 4]) >>> a[:5] # 省略开始下标,表示从a[0]开始 array([0, 1, 2, 3, 4]) >>> a[:-1] # 下标可以使用负数,表示从数组后往前数 array([0, 1, 2, 3, 4, 5, 6, 7, 8]) >>> a[2:4] = 100,101 # 下标还可以用来修改元素的值 >>> a array([ 0, 1, 100, 101, >>> a[1:-1:2] 2.1. ndarray对象 4, 5, 6, 7, 8, 9]) # 范围中的第三个参数表示步长,2表示隔一个元素取一个元素 17 用Python做科学计算 array([ 1, 101, 5, 7]) >>> a[::-1] # 省略范围的开始下标和结束下标,步长为-1,整个数组头尾颠倒 array([ 9, 8, 7, 6, 5, 4, 101, 100, 1, 0]) >>> a[5:1:-2] # 步长为负数时,开始下标必须大于结束下标 array([ 5, 101]) 和Python的列表序列不同,通过下标范围获取的新的数组是原始数组的一个视图。它与原始数组共享 同一块数据空间: >>> b = a[3:7] # 通过下标范围产生一个新的数组b,b和a共享同一块数据空间 >>> b array([101, 4, 5, 6]) >>> b[2] = -10 # 将b的第2个元素修改为-10 >>> b array([101, 4, -10, 6]) >>> a # a的第5个元素也被修改为10 array([ 0, 1, 100, 101, 4, -10, 6, 7, 8, 9]) 除了使用下标范围存取元素之外,NumPy还提供了两种存取元素的高级方法。 使用整数序列 当使用整数序列对数组元素进行存取时,将使用整数序列中的每个元素作为下标,整数序列可以是列 表或者数组。使用整数序列作为下标获得的数组不和原始数组共享数据空间。 >>> x = np.arange(10,1,-1) >>> x array([10, 9, 8, 7, 6, 5, 4, 3, 2]) >>> x[[3, 3, 1, 8]] # 获取x中的下标为3, 3, 1, 8的4个元素,组成一个新的数组 array([7, 7, 9, 2]) >>> b = x[np.array([3,3,-3,8])] #下标可以是负数 >>> b[2] = 100 >>> b array([7, 7, 100, 2]) >>> x # 由于b和x不共享数据空间,因此x中的值并没有改变 array([10, 9, 8, 7, 6, 5, 4, 3, 2]) >>> x[[3,5,1]] = -1, -2, -3 # 整数序列下标也可以用来修改元素的值 >>> x array([10, -3, 8, -1, 6, -2, 4, 3, 2]) 使用布尔数组 当使用布尔数组b作为下标存取数组x中的元素时,将收集数组x中所有在数组b中对应下标为True的 元素。使用布尔数组作为下标获得的数组不和原始数组共享数据空间,注意这种方式只对应于布尔数 组,不能使用布尔列表。 18 第2章 NumPy-快速处理数据 用Python做科学计算 >>> x = np.arange(5,0,-1) >>> x array([5, 4, 3, 2, 1]) >>> x[np.array([True, False, True, False, False])] >>> # 布尔数组中下标为0,2的元素为True,因此获取x中下标为0,2的元素 array([5, 3]) >>> x[[True, False, True, False, False]] >>> # 如果是布尔列表,则把True当作1, False当作0,按照整数序列方式获取x中的元素 array([4, 5, 4, 5, 5]) >>> x[np.array([True, False, True, True])] >>> # 布尔数组的长度不够时,不够的部分都当作False array([5, 3, 2]) >>> x[np.array([True, False, True, True])] = -1, -2, -3 >>> # 布尔数组下标也可以用来修改元素 >>> x array([-1, 4, -2, -3, 1]) 布尔数组一般不是手工产生,而是使用布尔运算的ufunc函数产生,关于ufunc函数请参照 ufunc运算 一节。 >>> x = np.random.rand(10) # 产生一个长度为10,元素值为0-1的随机数的数组 >>> x array([ 0.72223939, 0.95799412, 0.921226 , 0.7770805 , 0.2055047 , 0.17567449, 0.12015178, 0.7627083 , 0.43260184, 0.91379859]) >>> x>0.5 >>> # 数组x中的每个元素和0.5进行大小比较,得到一个布尔数组,True表示x中对应的值大于0.5 array([ True, True, True, False, False, True, False, True, False, True], dtype=bool) >>> x[x>0.5] >>> # 使用x>0.5返回的布尔数组收集x中的元素,因此得到的结果是x中所有大于0.5的元素的数组 array([ 0.72223939, 0.921226 , 0.7770805 , 0.95799412, 0.7627083 , 0.91379859]) 2.1.3 多维数组 多维数组的存取和一维数组类似,因为多维数组有多个轴,因此它的下标需要用多个值来表示, NumPy采用组元(tuple)作为数组的下标。 如下图所示,a为一个6x6的数组,图中用颜色区分了各个 下标以及其对应的选择区域。 2.1. ndarray对象 19 用Python做科学计算 组元不需要圆括号 虽然我们经常在Python中用圆括号将组元括起来,但是其实组元的语法定义只需要用逗号隔开即 可,例如 x,y=y,x 就是用组元交换变量值的一个例子。 图 2.1 - 使用数组切片语法访问多维数组中的元素 如何创建这个数组 你也许会对如何创建a这样的数组感到好奇,数组a实际上是一个加法表,纵轴的值为0, 10, 20, 30, 40, 50;横轴的值为0, 1, 2, 3, 4, 5。纵轴的每个元素都和横轴的每个元素求和,就得到图中 所示的数组a。你可以用下面的语句创建它,至于其原理我们将在后面的章节进行讨论: >>> np.arange(0, 60, 10).reshape(-1, 1) + np.arange(0, 6) array([[ 0, 1, 2, 3, 4, 5], [10, 11, 12, 13, 14, 15], [20, 21, 22, 23, 24, 25], [30, 31, 32, 33, 34, 35], [40, 41, 42, 43, 44, 45], [50, 51, 52, 53, 54, 55]]) 多维数组同样也可以使用整数序列和布尔数组进行存取。 图 2.2 - 使用整数序列和布尔数组访问多维数组中的元素 • a[(0,1,2,3,4),(1,2,3,4,5)] : 用于存取数组的下标和仍然是一个有两个元素的组元,组元中的每个 元素都是整数序列,分别对应数组的第0轴和第1轴。从两个序列的对应位置取出两个整数组成下 20 第2章 NumPy-快速处理数据 用Python做科学计算 标: a[0,1], a[1,2], ..., a[4,5]。 • a[3:, [0, 2, 5]] : 下标中的第0轴是一个范围,它选取第3行之后的所有行;第1轴是整数序列,它 选取第0, 2, 5三列。 • a[mask, 2] : 下标的第0轴是一个布尔数组,它选取第0,2,5行;第1轴是一个整数,选取第2 列。 2.1.4 结构数组 在C语言中我们可以通过struct关键字定义结构类型,结构中的字段占据连续的内存空间,每个结构体 占用的内存大小都相同,因此可以很容易地定义结构数组。和C语言一样,在NumPy中也很容易对这 种结构数组进行操作。只要NumPy中的结构定义和C语言中的定义相同,NumPy就可以很方便地读取 C语言的结构数组的二进制数据,转换为NumPy的结构数组。 假设我们需要定义一个结构数组,它的每个元素都有name, age和weight字段。在NumPy中可以如下 定义: import numpy as np persontype = np.dtype({ 'names':['name', 'age', 'weight'], 'formats':['S32','i', 'f']}) a = np.array([("Zhang",32,75.5),("Wang",24,65.2)], dtype=persontype) 我们先创建一个dtype对象persontype,通过其字典参数描述结构类型的各个字段。字典有两个关 键字:names,formats。每个关键字对应的值都是一个列表。names定义结构中的每个字段名,而 formats则定义每个字段的类型: • S32 : 32个字节的字符串类型,由于结构中的每个元素的大小必须固定,因此需要指定字符串的 长度 • i : 32bit的整数类型,相当于np.int32 • f : 32bit的单精度浮点数类型,相当于np.float32 然后我们调用array函数创建数组,通过关键字参数 dtype=persontype, 指定所创建的数组的元素类 型为结构persontype。运行上面程序之后,我们可以在IPython中执行如下的语句查看数组a的元素类 型 >>> a.dtype dtype([('name', '|S32'), ('age', '