提交 d0401ea2 编写于 作者: W wizardforcel

2020-07-24 17:40:58

上级 3517f0f4
......@@ -79,58 +79,3 @@ Out[8]: 4**
提示和技巧如下所示。
# 读者反馈
始终欢迎读者的反馈。 让我们知道您对这本书的看法-您喜欢或不喜欢的东西。 读者反馈对我们很重要,因为它可以帮助我们开发出您真正能充分利用的标题。
要向我们发送一般反馈,只需发送电子邮件`<[feedback@packtpub.com](mailto:feedback@packtpub.com)>`,然后在您的邮件主题中提及该书的标题。
如果您有专业知识的主题,并且对写作或撰写书籍感兴趣,请参阅 [www.packtpub.com/authors](https://www.packtpub.com/books/info/packt/authors) 上的作者指南。
# 客户支持
既然您是 Packt 书的骄傲拥有者,我们可以通过很多方法来帮助您从购买中获得最大收益。
## 下载示例代码
您可以从 [http://www.packtpub.com](http://www.packtpub.com) 的帐户中下载本书的示例代码文件。 如果您在其他地方购买了此书,则可以访问 [http://www.packtpub.com/support](http://www.packtpub.com/support) 并注册以将文件直接通过电子邮件发送给您。
您可以按照以下步骤下载代码文件:
1. 使用您的电子邮件地址和密码登录或注册到我们的网站。
2. 将鼠标指针悬停在顶部的 **SUPPORT** 选项卡上。
3. 单击**代码下载&勘误表**
4.**搜索**框中输入书籍的名称。
5. 选择您要下载其代码文件的书。
6. 从购买本书的下拉菜单中选择。
7. 点击**代码下载**
您还可以通过在 Packt Publishing 网站上的书籍网页上单击**代码文件**按钮来下载代码文件。 通过在**搜索**框中输入书名可以访问该页面。 请注意,您需要登录到 Packt 帐户。
下载文件后,请确保使用以下最新版本解压缩或解压缩文件夹:
* Windows 的 WinRAR / 7-Zip
* Mac 版 Zipeg / iZip / UnRarX
* 适用于 Linux 的 7-Zip / PeaZip
## 下载本书的彩色图像
我们还为您提供了一个 PDF 文件,其中包含本书中使用的屏幕截图/图表的彩色图像。 彩色图像将帮助您更好地了解输出中的变化。 您可以从 [https://www.packtpub.com/sites/default/files/downloads/NumPyEssentials_ColoredImages.pdf](https://www.packtpub.com/sites/default/files/downloads/NumPyEssentials_ColoredImages.pdf) 下载此文件。
## 勘误
尽管我们已尽一切努力确保内容的准确性,但还是会发生错误。 如果您发现我们的其中一本书中有错误-可能是文本或代码中的错误-如果您能向我们报告,我们将不胜感激。 这样,您可以使其他读者免于沮丧,并帮助我们改进本书的后续版本。 如果您发现任何勘误,请访问 [http://www.packtpub.com/submit-errata](http://www.packtpub.com/submit-errata) ,选择您的书,然后点击**勘误提交表格**进行报告。 链接,然后输入勘误的详细信息。 一旦您的勘误得到验证,您的提交将被接受,勘误将被上传到我们的网站或添加到该标题的勘误部分下的任何现有勘误列表中。
要查看先前提交的勘误,请转到 [https://www.packtpub.com/books/content/support](https://www.packtpub.com/books/content/support) ,然后在搜索字段中输入书籍的名称。 所需信息将出现在**勘误表**部分下。
## 盗版
互联网上版权材料的盗版在所有媒体中都是一个持续存在的问题。 在 Packt,我们非常重视版权和许可的保护。 如果您在 Internet 上以任何形式发现我们的作品的任何非法副本,请立即向我们提供位置地址或网站名称,以便我们寻求补救。
请通过`<[copyright@packtpub.com](mailto:copyright@packtpub.com)>`与我们联系,并提供指向可疑盗版材料的链接。
感谢您在保护我们的作者方面的帮助以及我们为您带来有价值的内容的能力。
## 问题
如果您对本书的任何方面都有疑问,可以通过`<[questions@packtpub.com](mailto:questions@packtpub.com)>`与我们联系,我们将尽力解决该问题。
\ No newline at end of file
# 一、NumPy 简介
|   | *“我宁愿使用通用语言进行数学运算,也不愿尝试使用数学语言进行通用编程。”* |   |
|   | - *John D Cook* |
> “我宁愿使用通用语言进行数学运算,也不愿尝试使用数学语言进行通用编程。”
>
> -- John D Cook
在过去的十年中,Python 已成为科学计算中最受欢迎的编程语言之一。 其成功的原因很多,随着您着手本书,这些原因将逐渐变得明显。 与许多其他数学语言(例如 MATLAB,R 和 Mathematica)不同,Python 是一种通用编程语言。 因此,它为构建科学应用程序并将其进一步扩展到任何商业或学术领域提供了合适的框架。 例如,考虑一个(某种)简单的应用程序,该应用程序要求您编写软件并预测博客文章的受欢迎程度。 通常,这些是您要执行此操作的步骤:
......@@ -10,13 +11,13 @@
3. 根据您在步骤 1 中找到的数据来训练模型。请继续进行此操作,直到您对模型的可靠性充满信心为止。
4. 将模型部署为 Web 服务。
通常,在执行这些步骤时,您会发现自己在不同的软件堆栈之间跳转。 第 1 步需要进行大量的网页抓取。 Web 抓取是一个非常普遍的问题,几乎每种编程语言都有一些工具可以抓取 Web(如果您已经在使用 Python,则可能会选择 Beautiful Soup 或 Scrapy)。 第 2 步和第 3 步涉及解决机器学习问题,并且需要使用复杂的数学语言或框架,例如 Weka 或 MATLAB,这只是提供机器学习功能的众多工具中的少数几种。 同样,步骤 4 可以使用许多不同的工具以多种方式实现。 没有一个正确的答案。 由于这个问题已经被许多科学家和软件开发人员充分研究和解决(在一定程度上),因此,找到可行的解决方案并不困难。 但是,诸如稳定性和可伸缩性之类的问题可能会严重限制您在问题的每个步骤中对编程语言,Web 框架或机器学习算法的选择。 这就是 Python 胜过大多数其他编程语言的地方。 前面的所有步骤(以及更多步骤)都只能使用 Python 和一些第三方 Python 库来完成。 这种使用 Python 开发软件的灵活性和便捷性正是使其成为科学计算生态系统的理想宿主。 在 *Python 数据分析**Ivan Idris* 和中可以找到关于 Python 作为成熟的应用程序开发语言的非常有趣的解释。 ] *Packt Publishing*精确地讲,Python 是一种用于快速原型制作的语言,并且由于其随着时间的推移而获得了广泛的科学生态系统,它也被用于构建生产质量的软件。 这个生态系统的基础是 NumPy。
通常,在执行这些步骤时,您会发现自己在不同的软件堆栈之间跳转。 第 1 步需要进行大量的网页抓取。 Web 抓取是一个非常普遍的问题,几乎每种编程语言都有一些工具可以抓取 Web(如果您已经在使用 Python,则可能会选择 Beautiful Soup 或 Scrapy)。 第 2 步和第 3 步涉及解决机器学习问题,并且需要使用复杂的数学语言或框架,例如 Weka 或 MATLAB,这只是提供机器学习功能的众多工具中的少数几种。 同样,步骤 4 可以使用许多不同的工具以多种方式实现。 没有一个正确的答案。 由于这个问题已经被许多科学家和软件开发人员充分研究和解决(在一定程度上),因此,找到可行的解决方案并不困难。 但是,诸如稳定性和可伸缩性之类的问题可能会严重限制您在问题的每个步骤中对编程语言,Web 框架或机器学习算法的选择。 这就是 Python 胜过大多数其他编程语言的地方。 前面的所有步骤(以及更多步骤)都只能使用 Python 和一些第三方 Python 库来完成。 这种使用 Python 开发软件的灵活性和便捷性正是使其成为科学计算生态系统的理想宿主。 在 *Ivan Idris* 所写的《Python 数据分析》中可以找到关于 Python 作为成熟的应用程序开发语言的非常有趣的解释。精确地讲,Python 是一种用于快速原型制作的语言,并且由于其随着时间的推移而获得了广泛的科学生态系统,它也被用于构建生产质量的软件。 这个生态系统的基础是 NumPy。
**数字 Python****NumPy** )是 Numeric 程序包的后续产品。 它最初由 Travis Oliphant 编写,是 Python 科学计算环境的基础。 它在 2005 年初从功能更广泛的 SciPy 模块分支出来,并于 2006 年中首次稳定发布。 从那以后,它在从事数学,科学和工程领域的 Python 爱好者中越来越受欢迎。 本书的目的是使您对 NumPy 足够熟悉,以便您能够使用它并使用它构建复杂的科学应用程序。
**数字 Python****NumPy**)是 Numeric 程序包的后续产品。 它最初由 Travis Oliphant 编写,是 Python 科学计算环境的基础。 它在 2005 年初从功能更广泛的 SciPy 模块分支出来,并于 2006 年中首次稳定发布。 从那以后,它在从事数学,科学和工程领域的 Python 爱好者中越来越受欢迎。 本书的目的是使您对 NumPy 足够熟悉,以便您能够使用它并使用它构建复杂的科学应用程序。
# 科学的 Python 堆栈
让我们首先简要浏览一下**科学 Python****SciPy** )堆栈。
让我们首先简要浏览一下 **Python 科学计算****SciPy**)堆栈。
### 注意
......@@ -40,18 +41,18 @@ IPython 的主要作者 Fernando Perez 在 2012 年加拿大 PyCon 的主题演
## 表示矩阵和向量
矩阵和向量的抽象数学概念是许多科学问题的核心。 数组为这些概念提供了直接的语义链接。 确实,每当一本数学文献提到矩阵时,就可以安全地将数组视为代表矩阵的软件抽象。 在科学文献中, *A <sub class="calibre25">ij</sub>* 等表达式通常用于表示 *i* 中的元素 <sup class="calibre26"></sup>*j* <sup class="calibre26">阵列 *A* 的列。 NumPy 中的相应表达将简单地是 *A [i,j]* 。 对于矩阵运算,NumPy 数组还支持矢量化(有关详细信息,请参见第 3 章,“使用 Numpy 数组”),这大大加快了执行速度。 向量化使代码更简洁,更易于阅读,并且更类似于数学符号。 像矩阵一样,数组也可以是多维的。 数组的每个元素都可以通过一组称为**索引**的整数来寻址,而访问具有整数集的数组的元素的过程称为**索引[** 。 确实可以在不使用数组的情况下实现此功能,但这将很麻烦并且非常不必要。</sup>
矩阵和向量的抽象数学概念是许多科学问题的核心。 数组为这些概念提供了直接的语义链接。 确实,每当一本数学文献提到矩阵时,就可以安全地将数组视为代表矩阵的软件抽象。 在科学文献中,`A[ij]`等表达式通常用于表示数组`A`的第`i`行和`j`列的元素。 NumPy 中的相应表达将简单地是`A[i, j]`。 对于矩阵运算,NumPy 数组还支持向量化(有关详细信息,请参见第 3 章,“使用 Numpy 数组”),这大大加快了执行速度。 向量化使代码更简洁,更易于阅读,并且更类似于数学符号。 像矩阵一样,数组也可以是多维的。 数组的每个元素都可以通过一组称为**索引**的整数来寻址,而使用整数集访问数组的元素的过程称为**索引**。 确实可以在不使用数组的情况下实现此功能,但这将很麻烦并且非常不必要。
## 效率
效率在软件中可能意味着很多事情。 该术语可用于指代程序的执行速度,其数据检索和存储性能,其内存开销(程序执行时消耗的内存)或其整体吞吐量。 就几乎所有这些特性而言,NumPy 数组都比大多数其他数据结构要好(只有少数例外,例如 pandas,DataFrame 或 SciPy 的稀疏矩阵,我们将在后面的章节中介绍)。 由于 NumPy 数组是静态类型且同质的,因此可以用编译语言实现快速数学运算(默认实现使用 C 和 Fortran)。 效率(在同类阵列上运行快速算法的可用性)使 NumPy 变得流行且重要。
效率在软件中可能意味着很多事情。 该术语可用于指代程序的执行速度,其数据检索和存储性能,其内存开销(程序执行时消耗的内存)或其整体吞吐量。 就几乎所有这些特性而言,NumPy 数组都比大多数其他数据结构要好(只有少数例外,例如 pandas,DataFrame 或 SciPy 的稀疏矩阵,我们将在后面的章节中介绍)。 由于 NumPy 数组是静态类型且同质的,因此可以用编译语言实现快速数学运算(默认实现使用 C 和 Fortran)。 效率(在同类数组上运行快速算法的可用性)使 NumPy 变得流行且重要。
## 易于开发
NumPy 模块是用于数学任务的现成功能的强大平台。 它极大地增加了 Python 的开发难度。 以下是该模块包含的内容的简要概述,我们将在本书中探讨其中的大部分内容。 有关 NumPy 模块的详细介绍,请参见权威的 *NumPy 指南**Travis Oliphat* 。 NumPy API 非常灵活,以至于科学 Python 社区已广泛采用它作为构建科学应用程序的标准 API。 可以在 *NumPy 数组:有效数值计算的结构**Van Der Walt* 以及其他
NumPy 模块是用于数学任务的现成功能的强大平台。 它极大地增加了 Python 的开发难度。 以下是该模块包含的内容的简要概述,我们将在本书中探讨其中的大部分内容。 有关 NumPy 模块的详细介绍,请参见 *Travis Oliphat* 所写的权威的《NumPy 指南》。 NumPy API 非常灵活,以至于科学 Python 社区已广泛采用它作为构建科学应用程序的标准 API。 可以参考 *Van Der Walt* 等人所写的《NumPy 数组:有效数值计算的结构》
<colgroup class="calibre9"><col class="calibre10"> <col class="calibre10"></colgroup>
| **子模块** | **内容** |
| --- | --- |
| `numpy.core` | 基本对象 |
| `lib` | 其他实用程序 |
| `linalg` | 基本线性代数 |
......@@ -75,7 +76,7 @@ Figure 2: Python versus other languages
现在,Python 和 NumPy 的信誉已经确立,让我们动手吧。
本书中所有 Python 代码使用的默认环境是 IPython。 下一节将介绍如何安装 IPython 和其他工具。 在整本书中,您只需在命令窗口或 IPython 提示符下输入输入即可。 除非另有说明,否则`code`将引用 Python 代码, **`command`** 将引用 bash 或 DOS 命令。
本书中所有 Python 代码使用的默认环境是 IPython。 下一节将介绍如何安装 IPython 和其他工具。 在整本书中,您只需在命令窗口或 IPython 提示符下输入输入即可。 除非另有说明,否则`code`将引用 Python 代码,`command`将引用 bash 或 DOS 命令。
所有 Python 输入代码都将按照以下代码段格式进行格式化:
......
......@@ -103,7 +103,7 @@ max 41.000000
在前面的示例中,我们仅获得`Age`列,并按`Age``DataFrame`进行排序。 当我们使用`describe()`时,它将计算所有数字字段的摘要统计信息(包括计数,均值,标准差,最小值,最大值和百分位数)。在本节的最后部分,我们将使用熊猫读取
在本节的最后部分,我们将使用熊猫读取`csv`文件并将一个字段值传递给`ndarray`以进行进一步的计算。 `example.csv`文件来自**国家统计局** **ONS** )。 请访问 [http://www.ons.gov.uk/ons/datasets-and-tables/index.html](http://www.ons.gov.uk/ons/datasets-and-tables/index.html) 了解更多详细信息。 我们将在 ONS 网站上使用*房屋类型和地方当局(英格兰和威尔士)的销售计数*。 您可以按主题名称搜索它,以访问下载页面或选择您感兴趣的任何数据集。在以下示例中,我们将示例数据集重命名为`sales.csv`
在本节的最后部分,我们将使用熊猫读取`csv`文件并将一个字段值传递给`ndarray`以进行进一步的计算。 `example.csv`文件来自**国家统计局****ONS**)。 请访问 [http://www.ons.gov.uk/ons/datasets-and-tables/index.html](http://www.ons.gov.uk/ons/datasets-and-tables/index.html) 了解更多详细信息。 我们将在 ONS 网站上使用*房屋类型和地方当局(英格兰和威尔士)的销售计数*。 您可以按主题名称搜索它,以访问下载页面或选择您感兴趣的任何数据集。在以下示例中,我们将示例数据集重命名为`sales.csv`
```py
In [15]: sales = pd.read_csv('sales.csv')
......@@ -308,7 +308,7 @@ In [31]: output.close()
```
上面的代码向您展示了 Python netCDF4 API 的用法,以便读取和创建`netCDF4`文件。 该模块不包含任何科学计算(因此它不包含在任何 Python 科学发行版中),但是目标位于文件 I / O 的接口中,该接口可以是研究和分析的第一阶段或最后阶段。
上面的代码向您展示了 Python netCDF4 API 的用法,以便读取和创建`netCDF4`文件。 该模块不包含任何科学计算(因此它不包含在任何 Python 科学发行版中),但是目标位于文件 I/O 的接口中,该接口可以是研究和分析的第一阶段或最后阶段。
# 科学
......
......@@ -4,8 +4,8 @@
本章将涉及的主题如下:
* **numpy.ndarray** 以及如何使用它-面向基本数组的计算
* numpy.ndarray 内存访问,存储和检索的性能
* `numpy.ndarray`以及如何使用它-面向基本数组的计算
* `numpy.ndarray`内存访问,存储和检索的性能
* 索引,切片,视图和副本
* 数组数据类型
......@@ -48,7 +48,7 @@ Out [5]: (2, 3)
```
这意味着该数组具有两行三列。 重要的是要注意,与 MATLAB 和 R 不同,NumPy 数组的索引是从零开始的。 也就是说,NumPy 数组的第一个元素索引为零,而最后一个元素索引为整数 n-1,其中 n 是数组沿相应维度的长度。 因此,对于我们刚刚创建的数组,可以使用一对零来访问数组左上角的元素,并且可以使用索引来访问右下角的元素( *1**2* ):
这意味着该数组具有两行三列。 重要的是要注意,与 MATLAB 和 R 不同,NumPy 数组的索引是从零开始的。 也就是说,NumPy 数组的第一个元素索引为零,而最后一个元素索引为整数 n-1,其中 n 是数组沿相应维度的长度。 因此,对于我们刚刚创建的数组,可以使用一对零来访问数组左上角的元素,并且可以使用索引来访问右下角的元素(`1``2`):
```py
In [6]: x
......@@ -67,7 +67,7 @@ Out[8]: 4
```
ndarray 对象具有许多有用的方法。 要获取可以在 ndarray 对象上调用的方法的列表,请在 IPython 提示符下键入`array`变量(在前面的示例中为`x`),然后按**选项卡** [ 。 这应该列出该对象可用的所有方法。 作为练习,尝试与其中一些玩耍。
ndarray 对象具有许多有用的方法。 要获取可以在 ndarray 对象上调用的方法的列表,请在 IPython 提示符下键入`array`变量(在前面的示例中为`x`),然后按`TAB`。 这应该列出该对象可用的所有方法。 作为练习,尝试与其中一些玩耍。
# 数组索引和切片
......@@ -94,9 +94,9 @@ In [11]: print(x[k, :])
```
冒号可以被认为是*所有元素*字符。 因此,前面的语句实际上意味着打印`k` <sup class="calibre26"></sup>行的所有字符。 同样,可以使用`x[:,k]`访问列。 反转数组也类似于反转列表,例如`x[::-1]`
冒号可以被认为是*所有元素*的字符。 因此,前面的语句实际上意味着打印第`k`行的所有字符。 同样,可以使用`x[:,k]`访问列。 反转数组也类似于反转列表,例如`x[::-1]`
数组的索引部分也称为数组的 *slice* ,它创建端口或整个数组的副本(我们将在后面的部分中介绍副本和视图) 。 在数组的上下文中,单词“切片”和“索引”通常可以互换使用。
数组的索引部分也称为数组的*切片*,它创建端口或整个数组的副本(我们将在后面的部分中介绍副本和视图) 。 在数组的上下文中,单词“切片”和“索引”通常可以互换使用。
下图显示了不同切片和索引技术的非常简洁的概述:
......@@ -124,7 +124,7 @@ Out[12]:
```
`flags`属性保存有关阵列的内存布局的信息。 输出中的`C_CONTIGUOUS`字段指示该数组是否为 C 样式数组。 这意味着该数组的索引就像 C 数组一样完成。 在 2D 数组的情况下,这也称为行优先索引。 这意味着,当在数组中移动时,行索引将首先增加,然后列索引将增加。 在多维 C 样式数组的情况下,最后一个维度首先递增,然后是最后一个,但最后一个递增,依此类推。
`flags`属性保存有关数组的内存布局的信息。 输出中的`C_CONTIGUOUS`字段指示该数组是否为 C 样式数组。 这意味着该数组的索引就像 C 数组一样完成。 在 2D 数组的情况下,这也称为行优先索引。 这意味着,当在数组中移动时,行索引将首先增加,然后列索引将增加。 在多维 C 样式数组的情况下,最后一个维度首先递增,然后是最后一个,但最后一个递增,依此类推。
同样,`F_CONTIGUOUS`属性指示该数组是否为 Fortran 样式的数组。 据说这样的数组具有列主索引(R,Julia 和 MATLAB 使用列主数组)。 这意味着,当在数组中移动时,第一个索引(沿着列)首先增加。
......@@ -159,7 +159,7 @@ In [16]: def sum_col(x):
return np.sum(x[:, 0])
```
现在,让我们使用 IPython 的`%timeit`魔术函数在两个阵列上测试这两个函数的性能:
现在,让我们使用 IPython 的`%timeit`魔术函数在两个数组上测试这两个函数的性能:
### 注意
......@@ -259,7 +259,7 @@ In [31]: print(x[:5, :])
# 创建数组
阵列可以通过多种方式创建,例如从其他数据结构,通过读取磁盘上的文件或从 Web 创建。 就本章而言,其目的是使我们熟悉 NumPy 数组的核心特性,我们将使用列表或各种 NumPy 函数创建数组。
数组可以通过多种方式创建,例如从其他数据结构,通过读取磁盘上的文件或从 Web 创建。 就本章而言,其目的是使我们熟悉 NumPy 数组的核心特性,我们将使用列表或各种 NumPy 函数创建数组。
## 从列表创建数组
......@@ -337,7 +337,7 @@ Out[44]: (2, 3, 4)
注意传递给两个函数的参数之间的细微差别。 随机函数接受*元组*作为参数,并创建维数等于元组长度的数组。 各个尺寸的长度等于元组的元素。 另一方面,`rand`函数采用任意数量的*整数参数*,并返回一个随机数组,使得其维数等于传递给该函数的整数参数的数量 ,并且各个维度的长度等于整数参数的值。 因此,前面的代码段中的`x`是三维数组(传递给函数的参数数量),并且`x`的三个维度中的每个维度的长度均为 *2* (每个参数的值)。 `rand``random`的便捷功能。 这两个函数可以互换使用,只要传递的参数分别对两个函数均有效即可。
但是,这两个函数的主要缺点是-它们只能创建浮点数组。 如果我们想要一个随机整数数组,则必须将这些函数的输出转换为整数。 但是,这也是一个重大问题,因为 NumPy 的`int`函数将浮点数截断为最接近 0 的整数(这与`floor`函数等效)。 因此,将`rand``random`的输出强制转换为整数将始终返回零数组,因为这两个函数都返回区间内的浮点数( *0* , [ *1*。 可以使用`randint`功能解决此问题,如下所示:
但是,这两个函数的主要缺点是-它们只能创建浮点数组。 如果我们想要一个随机整数数组,则必须将这些函数的输出转换为整数。 但是,这也是一个重大问题,因为 NumPy 的`int`函数将浮点数截断为最接近 0 的整数(这与`floor`函数等效)。 因此,将`rand``random`的输出强制转换为整数将始终返回零数组,因为这两个函数都返回`[0, 1)`区间内的浮点数。 可以使用`randint`功能解决此问题,如下所示:
```py
In [45]: LOW, HIGH = 1, 11
......@@ -357,9 +357,9 @@ Out[48]: [ 6 9 10 7 9 5 8 8 9 3]
[http://docs.scipy.org/doc/numpy/reference/routines.random.html](http://docs.scipy.org/doc/numpy/reference/routines.random.html)
## 其他阵列
## 其他数组
还有一些其他的数组创建函数,例如`zeros()``ones()``eye()`和其他一些函数(类似于 MATLAB 中的函数)可用于创建 NumPy 数组。 它们的使用非常简单。 阵列也可以从文件或从 Web 填充。 我们将在下一章中处理文件 I / O。
还有一些其他的数组创建函数,例如`zeros()``ones()``eye()`和其他一些函数(类似于 MATLAB 中的函数)可用于创建 NumPy 数组。 它们的使用非常简单。 数组也可以从文件或从 Web 填充。 我们将在下一章中处理文件 I/O。
# 数组数据类型
......
......@@ -11,7 +11,7 @@ NumPy 数组的优点在于您可以使用数组索引和切片来快速访问
# 向量化运算
所有 NumPy 操作都是量化的,您可以将操作应用于整个数组,而不是分别应用于每个元素。 与使用循环相比,这不仅整齐方便,而且还提高了计算性能。 在本节中,我们将体验 NumPy 向量化操作的强大功能。 在开始探索此主题之前,一个值得牢记的关键思想是始终考虑整个数组集而不是每个元素。 这将帮助您享受有关 NumPy 数组及其性能的学习。 让我们从标量和 NumPy 数组之间进行一些简单的计算开始:
所有 NumPy 操作都是量化的,您可以将操作应用于整个数组,而不是分别应用于每个元素。 与使用循环相比,这不仅整齐方便,而且还提高了计算性能。 在本节中,我们将体验 NumPy 向量化操作的强大功能。 在开始探索此主题之前,一个值得牢记的关键思想是始终考虑整个数组集而不是每个元素。 这将帮助您享受有关 NumPy 数组及其性能的学习。 让我们从标量和 NumPy 数组之间进行一些简单的计算开始:
```py
In [1]: import numpy as np
......@@ -80,7 +80,7 @@ Out[20]: dtype('int32')
```
两个变量`x``y`完全相同:都是`numpy.int32`数组,范围从 *1**8* (如果使用 64 位计算机,则可能会得到`numpy.int64`)并除以`float 10.0`。 但是,当`x`除以浮点数时,将使用`dtype = numpy.float64`创建一个新的 NumPy 数组。 这是一个全新的数组,但是具有相同的变量名`x`,因此`x`中的`dtype`进行了更改。 另一方面,`y`使用`/=`符号,该符号始终沿用`y`数组的`dtype`值。 因此,当它除以`10.0`时,不会创建新的数组; 仅更改`y`元素中的值,但`dtype `仍为`numpy.int32`。 这就是`x``y`最终具有两个不同阵列的原因。 请注意,从 1.10 版本开始,NumPy 不允许将浮点结果强制转换为整数。 因此,必须提高`TypeError`
两个变量`x``y`完全相同:都是`numpy.int32`数组,范围从 *1**8* (如果使用 64 位计算机,则可能会得到`numpy.int64`)并除以`float 10.0`。 但是,当`x`除以浮点数时,将使用`dtype = numpy.float64`创建一个新的 NumPy 数组。 这是一个全新的数组,但是具有相同的变量名`x`,因此`x`中的`dtype`进行了更改。 另一方面,`y`使用`/=`符号,该符号始终沿用`y`数组的`dtype`值。 因此,当它除以`10.0`时,不会创建新的数组; 仅更改`y`元素中的值,但`dtype `仍为`numpy.int32`。 这就是`x``y`最终具有两个不同数组的原因。 请注意,从 1.10 版本开始,NumPy 不允许将浮点结果强制转换为整数。 因此,必须提高`TypeError`
# 通用功能(ufuncs)
......@@ -142,7 +142,7 @@ Out[31]: array([ 5., 6., 7., 8., 9.])
```
我们可以不使用`axis`参数就可以看到`numpy.median()`函数默认情况下会展平数组并返回中值元素,因此仅返回一个值。 使用`axis`自变量,如果将其应用于 0,则该操作将基于该列; 因此,我们获得了一个新的 NumPy 数组,其长度为 *3* `z`变量中总共有 *3* 列 )。 虽然`axis = 1`,它基于行执行操作,所以我们有了一个包含五个元素的新数组。
我们可以不使用`axis`参数就可以看到`numpy.median()`函数默认情况下会展平数组并返回中值元素,因此仅返回一个值。 使用`axis`自变量,如果将其应用于 0,则该操作将基于该列; 因此,我们获得了一个新的 NumPy 数组,其长度为 *3*`z`变量中总共有 *3* 列 )。 虽然`axis = 1`,它基于行执行操作,所以我们有了一个包含五个元素的新数组。
ufuncs 不仅提供可选参数来调整操作,而且其中许多还具有一些内置方法,从而提供了更大的灵活性。 以下示例使用`numpy.add()`中的`accumulate()`累积对所有元素应用`add()`的结果:
......@@ -152,7 +152,7 @@ Out[32]: array([ 5, 11, 18, 26, 35])
```
第二个示例将`numpy.multiply()`上的矩阵外部运算应用于来自两个输入数组的所有元素对。 在此示例中,两个数组来自`x``multiply()`的外部产品的最终形状为 *5**5*
第二个示例将`numpy.multiply()`上的矩阵外部运算应用于来自两个输入数组的所有元素对。 在此示例中,两个数组来自`x``multiply()`的外部产品的最终形状为`5x5`
```py
In [33]: np.multiply.outer(x, x)
......@@ -165,15 +165,15 @@ array([[25, 30, 35, 40, 45],
```
如果您需要更高级的功能,则可以考虑构建自己的 ufunc,这可能需要使用 Python-C API,或者您也可以使用 Numba 模块(矢量化装饰器)来实现自定义的 ufunc。 在本章中,我们的目标是了解 NumPy ufunc,因此我们将不介绍自定义的 ufunc。 有关更多详细信息,请参阅 NumPy 的联机文档,名为*编写自己的 ufunc* ,位于 [http://docs.scipy.org/doc/numpy/user/c- info.ufunc-tutorial.html](http://docs.scipy.org/doc/numpy/user/c-info.ufunc-tutorial.html) 或称为的 Numba 文档*在[上创建 Numpy 通用函数](http://numba.pydata.org/numba-doc/dev/user/vectorize.html)* http://numba.pydata.org/numba-doc/ dev / user / vectorize.html
如果您需要更高级的功能,则可以考虑构建自己的 ufunc,这可能需要使用 Python-C API,或者您也可以使用 Numba 模块(向量化装饰器)来实现自定义的 ufunc。 在本章中,我们的目标是了解 NumPy ufunc,因此我们将不介绍自定义的 ufunc。 有关更多详细信息,请参阅 NumPy 的联机文档,名为[编写自己的`ufunc`](http://docs.scipy.org/doc/numpy/user/c-info.ufunc-tutorial.html)或 Numba 文档,[创建 Numpy 通用函数](http://numba.pydata.org/numba-doc/dev/user/vectorize.html)
# 广播和形状处理
NumPy 操作大部分是按元素进行的,这需要一个操作中的两个数组具有相同的形状。 但是,这并不意味着 NumPy 操作不能采用两个形状不同的数组(请参阅我们在标量中看到的第一个示例)。 NumPy 提供了在较大的阵列上广播较小尺寸的阵列的灵活性。 但是我们不能将数组广播成几乎任何形状。 它需要遵循某些约束; 我们将在本节中介绍它们。 要记住的一个关键思想是广播涉及在两个不同形状的阵列上执行有意义的操作。 但是,不当广播可能会导致内存使用效率低下,从而减慢计算速度。
NumPy 操作大部分是按元素进行的,这需要一个操作中的两个数组具有相同的形状。 但是,这并不意味着 NumPy 操作不能采用两个形状不同的数组(请参阅我们在标量中看到的第一个示例)。 NumPy 提供了在较大的数组上广播较小尺寸的数组的灵活性。 但是我们不能将数组广播成几乎任何形状。 它需要遵循某些约束; 我们将在本节中介绍它们。 要记住的一个关键思想是广播涉及在两个不同形状的数组上执行有意义的操作。 但是,不当广播可能会导致内存使用效率低下,从而减慢计算速度。
## 广播规则
广播的一般规则是确定两个阵列是否与尺寸兼容。 需要满足两个条件:
广播的一般规则是确定两个数组是否与尺寸兼容。 需要满足两个条件:
* 两个数组的大小应相等
* 其中之一是 1
......@@ -193,7 +193,7 @@ array([[ 1, 2, 3],
```
让我们将前面的代码制作成图表,以帮助我们理解广播。 `x`变量的形状为`(3, 3)`,而`y`的形状仅为 3。但是在 NumPy 广播中,`y`的形状转换为 *3**1* ; 因此,该规则的第二个条件已得到满足。 通过重复将`y`广播到`x`的相同形状。 `+`操作可以按元素应用。
让我们将前面的代码制作成图表,以帮助我们理解广播。 `x`变量的形状为`(3, 3)`,而`y`的形状仅为 3。但是在 NumPy 广播中,`y`的形状转换为`1x3`; 因此,该规则的第二个条件已得到满足。 通过重复将`y`广播到`x`的相同形状。 `+`操作可以按元素应用。
![Broadcasting rules](img/00005.jpeg)
......@@ -216,7 +216,7 @@ array([[ 1, 2, 3],
```
前面的示例向您展示`x``y`的广播方式。 `x`按列广播,而`y`按行广播,因为它们的形状在形状上均等于 *1* 。 满足第二个广播条件,并且新结果数组是 *3* 数组的 *3*
前面的示例向您展示`x``y`的广播方式。 `x`按列广播,而`y`按行广播,因为它们的形状在形状上均等于 *1*。 满足第二个广播条件,并且新结果数组是`3x3`
![Broadcasting rules](img/00006.jpeg)
......@@ -232,13 +232,13 @@ ValueError: operands could not be broadcast together with shapes (3,3) (4)
```
在第三个示例中,由于`x``y`在行维度上具有不同的形状,并且它们都不等于 *1* ,因此无法执行广播。 因此,不能满足任何广播条件。 NumPy 抛出`ValueError`,告诉您形状不兼容。
在第三个示例中,由于`x``y`在行维度上具有不同的形状,并且它们都不等于 *1*,因此无法执行广播。 因此,不能满足任何广播条件。 NumPy 抛出`ValueError`,告诉您形状不兼容。
![Broadcasting rules](img/00007.jpeg)
## 重塑 NumPy 数组
了解广播规则之后,这里的另一个重要概念是重塑 NumPy 数组,尤其是在处理多维数组时。 通常只在一个维度上创建一个 NumPy 数组,然后将其重塑为多维,反之亦然。 这里的一个关键思想是,您可以更改数组的形状,但不应更改元素的数量。 例如,您无法通过 *3* 数组将 *3* 整形为 *10* [ *1* 阵列中的。 整形前后,元素的总数(或 ndarray 内部组织中的所谓数据缓冲区)应保持一致。 或者,您可能需要调整大小,但这是另一回事了。 现在,让我们看一些形状操作:
了解广播规则之后,这里的另一个重要概念是重塑 NumPy 数组,尤其是在处理多维数组时。 通常只在一个维度上创建一个 NumPy 数组,然后将其重塑为多维,反之亦然。 这里的一个关键思想是,您可以更改数组的形状,但不应更改元素的数量。 例如,您无法`3xe`数组整形为`10x1`数组。 整形前后,元素的总数(或 ndarray 内部组织中的所谓数据缓冲区)应保持一致。 或者,您可能需要调整大小,但这是另一回事了。 现在,让我们看一些形状操作:
```py
In [44]: x = np.arange(24)
......@@ -254,7 +254,7 @@ array([[[ 0, 1, 2, 3],
```
基本的重塑技术会更改`numpy.shape`属性。 在前面的示例中,我们有一个形状为`(24,1)`的数组,更改了 shape 属性后,我们获得了一个相同大小的数组,但是形状已更改为 *2**3**4* 组成。 注意, *-1* 的形状是指转移阵列的剩余形状尺寸。
基本的重塑技术会更改`numpy.shape`属性。 在前面的示例中,我们有一个形状为`(24,1)`的数组,更改了 shape 属性后,我们获得了一个相同大小的数组,但是形状已更改为 *2**3**4* 组成。 注意, *-1* 的形状是指转移数组的剩余形状尺寸。
```py
In [47]: x = np.arange(1000000)
......@@ -266,11 +266,11 @@ In [50]: %timeit x.ravel()
```
前面的示例是将 100 x 100 x 100 阵列整形为一个尺寸; 在这里,我们应用`numpy.flatten()``numpy.ravel()`这两个函数来折叠数组,同时我们还比较了执行时间。 我们注意到`numpy.flatten()``numpy.ravel()`之间的速度差异很大,但是它们都比三层 Python 循环快得多。 两种功能在性能上的差异是`np.flatten()`从原始数组创建副本,而`np.ravel()`只是更改视图(如果您不记得副本和视图之间的区别,请回到第 2 章, “NumPy `ndarray`对象”)。
前面的示例是将 100 x 100 x 100 数组整形为一个尺寸; 在这里,我们应用`numpy.flatten()``numpy.ravel()`这两个函数来折叠数组,同时我们还比较了执行时间。 我们注意到`numpy.flatten()``numpy.ravel()`之间的速度差异很大,但是它们都比三层 Python 循环快得多。 两种功能在性能上的差异是`np.flatten()`从原始数组创建副本,而`np.ravel()`只是更改视图(如果您不记得副本和视图之间的区别,请回到第 2 章, “NumPy `ndarray`对象”)。
这个例子只是向您展示了 NumPy 提供了许多功能,其中一些可以产生相同的结果。 选择满足您目的的功能,同时为您提供优化的性能。
## 量叠加
## 量叠加
重塑会更改一个数组的形状,但是如何通过大小相等的行向量构造二维或多维数组呢? NumPy 为这种称为向量堆叠的解决方案提供了解决方案。 在这里,我们将通过三个示例使用三个不同的堆栈函数来实现基于不同维度的两个数组的组合:
......@@ -307,7 +307,7 @@ array([[[ 0, 0],
`numpy.dstack()`有点不同:它沿三维方向在深度方向上按顺序堆叠数组,因此新数组是三维的。
在下面的代码中,如果您使用`numpy.resize()`更改数组大小,则您正在放大数组,它将重复自身直到达到新大小; 否则,它将把数组截断为新的大小。 这里要注意的一点是`ndarray`也具有`resize()`操作,因此在此示例中,您还可以通过键入`x.resize(8)`来使用它来更改阵列的大小; 但是,您会注意到放大部分填充了零,而不是重复数组本身。 另外,如果您已将数组分配给另一个变量,则无法使用`ndarray.resize()``Numpy.resize()`创建一个具有指定形状的新数组,该数组的限制比`ndarray.resize()`少,并且是在需要时用于更改 NumPy 数组大小的更可取的操作:
在下面的代码中,如果您使用`numpy.resize()`更改数组大小,则您正在放大数组,它将重复自身直到达到新大小; 否则,它将把数组截断为新的大小。 这里要注意的一点是`ndarray`也具有`resize()`操作,因此在此示例中,您还可以通过键入`x.resize(8)`来使用它来更改数组的大小; 但是,您会注意到放大部分填充了零,而不是重复数组本身。 另外,如果您已将数组分配给另一个变量,则无法使用`ndarray.resize()``Numpy.resize()`创建一个具有指定形状的新数组,该数组的限制比`ndarray.resize()`少,并且是在需要时用于更改 NumPy 数组大小的更可取的操作:
```py
In [56]: x = np.arange(3)
......@@ -318,7 +318,7 @@ Out[57]: array([0, 1, 2, 0, 1, 2, 0, 1])
# 布尔掩码
在 NumPy 中,索引和切片非常方便且功能强大,但是使用 boolean 掩码,效果会更好! 让我们首先创建一个布尔数组。 请注意,NumPy 中有一种特殊的数组,称为*蒙版数组*。 在这里,我们不讨论它,但是我们还将解释如何使用 NumPy 数组扩展索引和切片:
在 NumPy 中,索引和切片非常方便且功能强大,但是使用布尔掩码,效果会更好! 让我们首先创建一个布尔数组。 请注意,NumPy 中有一种特殊的数组,称为*掩码数组*。 在这里,我们不讨论它,但是我们还将解释如何使用 NumPy 数组扩展索引和切片:
```py
In [58]: x = np.array([1,3,-1, 5, 7, -1])
......@@ -373,4 +373,4 @@ numpy.resize
使用 NumPy 数组的最好方法是尽可能地消除循环,并在 NumPy 中使用 ufuncs。 请记住广播规则,并谨慎使用它们。 将切片和索引与掩码一起使用可提高代码效率。 最重要的是,在使用时要玩得开心。
在接下来的几章中,我们将介绍 NumPy 的核心库,包括日期/时间和文件 I / O,以帮助您扩展 NumPy 的使用体验。
\ No newline at end of file
在接下来的几章中,我们将介绍 NumPy 的核心库,包括日期/时间和文件 I/O,以帮助您扩展 NumPy 的使用体验。
\ No newline at end of file
......@@ -7,13 +7,13 @@
* NumPy 数组的核心:内存布局
* 结构数组(记录数组)
* NumPy 数组中的日期时间
* NumPy 数组中的文件 I / O
* NumPy 数组中的文件 I/O
# 大步向前
# 步幅
跨步是 NumPy 数组中的索引方案,它指示要跳转以查找下一个元素的字节数。 我们都知道 NumPy 的性能改进来自具有固定大小项的同构多维数组对象`numpy.ndarray`对象。 我们已经讨论了`ndarray`对象的`shape`(维度),数据类型和顺序(C 风格的行主要索引数组和 Fortran 风格的列主要数组)。现在该讨论 仔细看看**大步前进**
步幅是 NumPy 数组中的索引方案,它指示要跳转以查找下一个元素的字节数。 我们都知道 NumPy 的性能改进来自具有固定大小项的同构多维数组对象`numpy.ndarray`对象。 我们已经讨论了`ndarray`对象的`shape`(维度),数据类型和顺序(C 风格的行主要索引数组和 Fortran 风格的列主要数组)。现在该讨论 仔细看看**步幅**
让我们首先创建一个 NumPy 数组并更改其形状以查看跨步的差异。
让我们首先创建一个 NumPy 数组并更改其形状以查看步幅的差异。
1. Create a NumPy array and take a look at the strides:
......@@ -28,7 +28,7 @@
      Out[5]: '\x00\x01\x02\x03\x04\x05\x06\x07'
```
创建一维数组`x`,其数据类型为 NumPy 整数`8`,这意味着数组中的每个元素都是 8 位整数(每个 1 字节,总共 8 个字节)。 跨步表示遍历数组时在每个维度上步进的字节元组。 在上一个示例中,它是一个维度,因此我们将元组获得为(1,)。 每个元素与其前一个元素相距 1 个字节。 当我们打印出`x.data`时,我们可以获得指向数据开头的 Python 缓冲区对象,在示例中从`x01` 到`x07`。
创建一维数组`x`,其数据类型为 NumPy 整数`8`,这意味着数组中的每个元素都是 8 位整数(每个 1 字节,总共 8 个字节)。 步幅表示遍历数组时在每个维度上步进的字节元组。 在上一个示例中,它是一个维度,因此我们将元组获得为(1,)。 每个元素与其前一个元素相距 1 个字节。 当我们打印出`x.data`时,我们可以获得指向数据开头的 Python 缓冲区对象,在示例中从`x01` 到`x07`。
2. Change the shape and see the stride change:
......@@ -52,7 +52,7 @@
现在我们将`x`的尺寸更改为 2 乘以 4,然后再次检查步幅。 我们可以看到它变为`(4, 1)`,这意味着第一维中的元素相隔四个字节,并且数组需要跳转四个字节才能找到下一行,但是第二维中的元素仍相隔 1 个字节, 跳一个字节以查找下一列。 让我们再次打印出`x.data`,我们可以看到数据的内存布局保持不变,但是步幅改变了。 当我们将形状更改为三维时,会发生相同的行为:1 x 4 x 2 数组。 (如果我们的数组是按照 Fortran 样式顺序构建的,会怎样?由于形状的变化,步幅将如何变化?尝试创建一个以列为主的数组,并执行相同的操作来检验这一点。)
3. 所以现在我们知道了什么是步幅,以及它与`ndarray`对象的关系,但是步幅如何改善我们的 NumPy 体验? 让我们进行一些跨步操作以更好地理解这一点:两个数组的内容相同,但步幅却有所不同:
3. 所以现在我们知道了什么是步幅,以及它与`ndarray`对象的关系,但是步幅如何改善我们的 NumPy 体验? 让我们进行一些步幅操作以更好地理解这一点:两个数组的内容相同,但步幅却有所不同:
```py
In [13]: x = np.ones((10000,))
......@@ -65,7 +65,7 @@
```
4. 我们创建两个 NumPy 数组`x``y`并进行比较; 我们可以看到两个数组相等。 它们具有相同的形状,所有元素都是一个,但是实际上这两个数组在内存布局方面是不同的。 让我们简单地使用您在第 2 章, “NumPy `ndarray`对象”中了解的 flags 属性来检查两个阵列的内存布局。
4. 我们创建两个 NumPy 数组`x``y`并进行比较; 我们可以看到两个数组相等。 它们具有相同的形状,所有元素都是一个,但是实际上这两个数组在内存布局方面是不同的。 让我们简单地使用您在第 2 章, “NumPy `ndarray`对象”中了解的 flags 属性来检查两个数组的内存布局。
```py
In [17]: x.flags
......@@ -106,7 +106,7 @@
```
通常,在固定的高速缓存大小的情况下,当跨步大小变大时,命中率(在高速缓存中找到数据的内存访问量的百分比)相对较低,而未命中率(必须访问的内存访问量的百分比) 到内存)将会更高。 缓存命中时间和未命中时间构成了平均数据访问时间。 让我们尝试从缓存的角度再次来看我们的示例。 步幅较小的数组`x`快于`y`步幅较大的数组。 性能差异的原因是 CPU 将数据从主存储器分块地拉到其缓存中,步幅越小意味着需要的传输越少。 有关详细信息,请参见下图,其中红线表示 CPU 缓存的大小,蓝框表示包含数据的内存布局。
通常,在固定的高速缓存大小的情况下,当步幅大小变大时,命中率(在高速缓存中找到数据的内存访问量的百分比)相对较低,而未命中率(必须访问的内存访问量的百分比) 到内存)将会更高。 缓存命中时间和未命中时间构成了平均数据访问时间。 让我们尝试从缓存的角度再次来看我们的示例。 步幅较小的数组`x`快于`y`步幅较大的数组。 性能差异的原因是 CPU 将数据从主存储器分块地拉到其缓存中,步幅越小意味着需要的传输越少。 有关详细信息,请参见下图,其中红线表示 CPU 缓存的大小,蓝框表示包含数据的内存布局。
显然,如果同时需要`x``y`,则 100 个蓝色框的数据将减少`x`所需的缓存时间。
......@@ -132,7 +132,7 @@ array([(1, 0.5, 'NumPy'), (10, -0.5, 'Essential')],
您可以看到`x`的打印输出,该输出现在包含三种不同类型的记录,并且我们还在`dtype`中获得了默认字段名称:`f0``f1``f2`。 当然,您可以指定字段名称,如以下示例所示。
这里要注意的一件事是,我们使用了打印输出数据类型-`i4``f4`前面有一个`<`,而`<`代表字节顺序 *big-endian [* (指示内存地址增加顺序):
这里要注意的一件事是,我们使用了打印输出数据类型-`i4``f4`前面有一个`<`,而`<`代表字节顺序*大端*(指示内存地址增加顺序):
```py
In [23]: x[0]
......@@ -168,14 +168,14 @@ array([(10, 0.5, 'NumPy'), (100, -0.5, 'Essential')],
NumPy 可以接受多种形式的字符串参数(有关详细信息,请参见 [http://docs.scipy.org/doc/numpy/user/basics.rec.html](http://docs.scipy.org/doc/numpy/user/basics.rec.html) ); 最优选的可以选自以下之一:
<colgroup class="calibre9"><col class="calibre10"> <col class="calibre10"></colgroup>
| **数据类型** | **表示形式** |
| `b1` | 字节数 |
| --- | --- |
| `b1` | 字节 |
| `i1``i2``i4``i8` | 具有 1、2、4 和 8 个字节的带符号整数 |
| `u1``u2``u4``u8` | 1、2、4 和 8 个字节的无符号整数 |
| `f2``f4``f8` | 浮点数为 2、4 和 8 个字节 |
| `c8``c16` | 复杂的 8 和 16 个字节 |
| `a<n>` | 定长字符串,长度为 *n* |
| `a<n>` | 定长字符串,长度为`n` |
您也可以在字符串参数前面加上重复的数字或形状,以定义字段的维,但是在记录数组中,它仍仅被视为一个字段。 在下面的示例中,让我们尝试使用形状作为字符串参数的前缀:
......@@ -309,7 +309,7 @@ Out[56]:
我们可以看到带有`for`循环的`numpy.datetime64.tolist()``numpy.datetime64.item()`可以实现相同的目标,即将数组转换为 Python `datetime`对象的列表。 但是不用说,我们都知道哪种方法更适合进行转换(如果您不知道答案,请快速浏览第 3 章,“使用 Numpy 数组”。)另一方面,如果您已经有了 Python `datetime`的列表,并想将其转换为 NumPy `datetime64`数组,则只需使用`numpy.array()`函数。
## 文件 I / O 和 NumPy
## 文件 I/O 和 NumPy
现在我们可以执行 NumPy 数组计算和操作,并且知道如何构造记录数组,现在是时候进行一些实际的分析了,方法是将文件读入 NumPy 数组并将结果数组输出到文件中以进行进一步的分析 分析。
......
......@@ -80,7 +80,7 @@ matrix([[32 2 32]
您可以从前面的示例中看到,当我们使用`*`表示法时,当您为`ndarray`使用`numpy.dot()`时,它会应用矩阵乘法(我们将在下一节中讨论)。 同样,`**`功率符号以矩阵方式完成。 我们还根据随机函数创建了一个矩阵`z`,以显示该矩阵何时可逆(非奇异)。 您可以使用`numpy.matrix.I`获得逆矩阵。 我们还可以使用`numpy.matrix.H`进行共轭(Hermitian)转置。
现在我们知道了如何创建矩阵对象并执行一些基本操作,是时候进行一些练习了。 让我们尝试求解一个简单的线性方程。 假设我们有一个线性方程 *A x = b* ,我们想知道 *x* 的值。 可能的解决方案如下:
现在我们知道了如何创建矩阵对象并执行一些基本操作,是时候进行一些练习了。 让我们尝试求解一个简单的线性方程。 假设我们有一个线性方程`A x = b`,我们想知道`x`的值。 可能的解决方案如下:
```py
A-1A x = A-1 b
......@@ -139,7 +139,7 @@ Out[25]: array([3, 1, 4, 1, 5, 9, 2, 6, 5])
# NumPy 中的线性代数
在进入 NumPy 的线性代数类之前,我们将在本节的开头介绍五种量积。 让我们从`numpy.dot()`产品开始逐一回顾它们:
在进入 NumPy 的线性代数类之前,我们将在本节的开头介绍五种量积。 让我们从`numpy.dot()`产品开始逐一回顾它们:
```py
In [26]: x = np.array([[1, 2], [3, 4]])
......@@ -195,7 +195,7 @@ Out[34]: array([ 0, 0, -1])
```
下图显示了详细的计算,并且两个向量`a``b`的叉积由 *a x b* 表示:
下图显示了详细的计算,并且两个向量`a``b`的叉积由`a x b`表示:
![Linear algebra in NumPy](img/00013.jpeg)
......@@ -228,7 +228,7 @@ matrix([[-0.45, 0.4 ],
```
从前面的示例中,我们可以看到`numpy.linalg.inv()`提供与`numpy.matrix.I`相同的结果。 唯一的区别是`numpy.linalg`返回`ndarray`。 接下来,我们将再次回到线性方程式 *A x = b* ,以了解如何使用`numpy.linalg.solve()`获得与使用矩阵对象相同的结果:
从前面的示例中,我们可以看到`numpy.linalg.inv()`提供与`numpy.matrix.I`相同的结果。 唯一的区别是`numpy.linalg`返回`ndarray`。 接下来,我们将再次回到线性方程式`A x = b`,以了解如何使用`numpy.linalg.solve()`获得与使用矩阵对象相同的结果:
```py
In [39]: x = np.linalg.solve(A,b)
......@@ -246,7 +246,7 @@ matrix([[ 0.2667],
# 分解
`numpy.linalg`提供了分解,在本节中,我们将介绍两种最常用的分解:**奇异值分解** **svd** )和 **QR** 因式分解。 让我们首先计算**特征值****特征向量**。 在我们开始之前,如果您不熟悉特征值和特征向量,可以在 [https://en.wikipedia.org/wiki/Eigenvalues_and_eigenvectors](https://en.wikipedia.org/wiki/Eigenvalues_and_eigenvectors) 进行检查。 开始吧:
`numpy.linalg`提供了分解,在本节中,我们将介绍两种最常用的分解:**奇异值分解****svd**)和 **QR** 因式分解。 让我们首先计算**特征值****特征向量**。 在我们开始之前,如果您不熟悉特征值和特征向量,可以在 [https://en.wikipedia.org/wiki/Eigenvalues_and_eigenvectors](https://en.wikipedia.org/wiki/Eigenvalues_and_eigenvectors) 进行检查。 开始吧:
```py
In [41]: x = np.random.randint(0, 10, 9).reshape(3,3)
......@@ -290,9 +290,9 @@ Out[48]:
```
`ndarrayz`是实型(`numpy.float64`),因此在计算特征值时会自动四舍五入。 从理论上讲,特征值应为 *1 +/- 1e-* *10* ,但从第一个`np.linalg.eig()`可以看出 特征值都向上舍入为 *1*
`ndarrayz`是实型(`numpy.float64`),因此在计算特征值时会自动四舍五入。 从理论上讲,特征值应为`1 ± 1e-10`,但从第一个`np.linalg.eig()`可以看出 特征值都向上舍入为 *1*
`svd`可以认为是特征值的扩展。 我们可以使用`numpy.linalg.svd()`分解 M x N 数组,所以让我们从一个简单的例子开始:
`svd`可以认为是特征值的扩展。 我们可以使用`numpy.linalg.svd()`分解`M x N`数组,所以让我们从一个简单的例子开始:
```py
In [51]: np.set_printoptions(precision = 4)
......@@ -313,7 +313,7 @@ Out[56]: array([ 13.5824, 2.8455, 2.3287])
```
在此示例中,`numpy.linalg.svd()`返回了三个元组数组,我们将其解压缩为三个变量:`u``sigma``vh`,其中`u`代表`A`的左奇异矢量( *AA-1* 的特征向量,`vh``A`的右奇异向量(*(A-1A)的特征向量)的逆矩阵 1* ),`sigma``A`的非零奇异值( *AA-1**的特征值 A-1A* )。 在该示例中,存在三个特征值,它们按顺序返回。 您可能会对结果感到怀疑,所以让我们做一些数学运算来验证它:
在此示例中,`numpy.linalg.svd()`返回了三个元组数组,我们将其解压缩为三个变量:`u``sigma``vh`,其中`u`代表`A`的左奇异向量(`AA-1`的特征向量),`vh``A`的右奇异向量(`A-1A`的特征向量的逆矩阵),`sigma``A`的非零奇异值(`AA-1``A-1A`的特征值)。 在该示例中,存在三个特征值,它们按顺序返回。 您可能会对结果感到怀疑,所以让我们做一些数学运算来验证它:
```py
In [57]: diag_sigma = np.diag(sigma)
......@@ -333,9 +333,9 @@ Out[61]: True
```
输入数组`A`可以转换为`svd`中的 *U ∑ V ** ,其中 ** 是奇异向量 价值观。 但是,从 NumPy 返回的 sigma 是具有非零值的数组,我们需要将其设为向量,因此在此示例中,形状为( *3* , *3*。 我们首先使用`numpy.diag()`制作`sigma`对角矩阵`diag_sigma`。 然后我们只需在`u``diag_sigma``vh`之间执行矩阵乘法,以检查计算结果(`Av`)是否与原始输入`A`相同,这意味着我们验证了 svd 结果。
输入数组`A`可以转换为`svd`中的`U ∑ V*`,其中`∑`是奇异向量的值。 但是,从 NumPy 返回的`sigma`是具有非零值的数组,我们需要将其设为向量,因此在此示例中,形状为`(3, 3)`。 我们首先使用`numpy.diag()`制作`sigma`对角矩阵`diag_sigma`。 然后我们只需在`u``diag_sigma``vh`之间执行矩阵乘法,以检查计算结果(`Av`)是否与原始输入`A`相同,这意味着我们验证了 svd 结果。
QR 分解(有时称为极坐标分解)可用于任何 M x N 数组,并将其分解为正交矩阵(Q)和上三角矩阵(R)。 让我们尝试使用它来解决先前的 *Ax = b* 问题:
QR 分解(有时称为极坐标分解)可用于任何`M x N`数组,并将其分解为正交矩阵(`Q`)和上三角矩阵(`R`)。 让我们尝试使用它来解决先前的`Ax = b`问题:
```py
In [62]: b = np.array([1,2,3]).reshape(3,1)
......@@ -349,7 +349,7 @@ array([[ 0.2667],
```
我们使用`numpy.linalg.qr()`分解`A`以获得`q``r`。 因此现在将原始方程式转换为*(q * r)x = b* 。 我们可以使用`r``q``b`的逆矩阵乘法(点积)获得`x`。 由于`q`是一个 unit 矩阵,因此我们使用了转置而不是逆。 如您所见,结果`x`与我们使用矩阵和`numpy.linalg.solve()`时的结果相同; 这是解决线性问题的另一种方法。
我们使用`numpy.linalg.qr()`分解`A`以获得`q``r`。 因此现在将原始方程式转换为`(q * r) x = b`。 我们可以使用`r``q``b`的逆矩阵乘法(点积)获得`x`。 由于`q`是一个 unit 矩阵,因此我们使用了转置而不是逆。 如您所见,结果`x`与我们使用矩阵和`numpy.linalg.solve()`时的结果相同; 这是解决线性问题的另一种方法。
### 注意
......@@ -370,7 +370,7 @@ Out[67]: array([ 1, -10, 35, -50, 24])
```
`numpy.poly()`返回一阶多项式系数数组,其根是从最高到最低指数的给定数组`root`。 在此示例中,我们采用根数组`[1,2,3,4]`并返回多项式,等效于 x4-10 * 3 + 35 * 2-50x + 24
`numpy.poly()`返回一阶多项式系数数组,其根是从最高到最低指数的给定数组`root`。 在此示例中,我们采用根数组`[1,2,3,4]`并返回多项式,等效于`x^4 - 10x^3 + 35x^2 - 50x + 24`
我们需要注意的一件事是输入根数组应该是一维或正方形二维数组,否则会触发`ValueError`。 当然,我们也可以执行相反的操作:使用`numpy.roots()`根据系数计算根:
......@@ -380,7 +380,7 @@ Out[68]: array([ 4., 3., 2., 1.])
```
现在,假设我们有方程式 *y = x4-10 * 3 + 35 * 2-50x + 24* ,我们想知道*的值 y**x = 5*。 我们可以使用`numpy.polyval()`来计算:
现在,假设我们有方程式`y = x^4 - 10x^3 + 35x^2 - 50x + 24`,当`x = 5`时我们想知道`y`的值。 我们可以使用`numpy.polyval()`来计算:
```py
In [69]: np.polyval([1,-10,35,-50,24], 5)
......@@ -390,7 +390,7 @@ Out[69]: 24
`numpy.polyval()`具有两个输入参数,第一个是多项式的系数数组,第二个是用于评估给定多项式的特定点值。 我们也可以输入`x`的序列,结果将返回`ndarray`,其值对应于给定的`x`序列。
接下来我们将讨论**积分****导数**。 我们将继续以 *x <sup class="calibre26">4</sup> -10x <sup class="calibre26">3</sup> + 35x <sup class="calibre26">2</sup> -50x + 24* 的示例为例:
接下来我们将讨论**积分****导数**。 我们将继续以`x^4 - 10x^3 + 35x^2 - 50x + 24`的示例为例:
```py
In [70]: coef = np.array([1,-10,35,-50,24])
......@@ -500,7 +500,7 @@ array([
```
现在我们有了年龄和睡眠得分,每个变量都有 100 次事件。 接下来,我们将计算回归线: *y = mx + c* ,其中 *y* 代表`sleeping_score`,而 *x* 代表`age`。 回归线的 NumPy 函数为`numpy.linalg.lstsq()`,它将系数矩阵和因变量值作为输入。 因此,我们要做的第一件事是将变量年龄打包到一个系数矩阵中,我们称之为`AGE`
现在我们有了年龄和睡眠得分,每个变量都有 100 次事件。 接下来,我们将计算回归线:`y = mx + c`,其中`y`代表`sleeping_score`,而`x`代表`age`。 回归线的 NumPy 函数为`numpy.linalg.lstsq()`,它将系数矩阵和因变量值作为输入。 因此,我们要做的第一件事是将变量年龄打包到一个系数矩阵中,我们称之为`AGE`
```py
In [87]: AGE = np.vstack([age, np.ones(len(age))]).T
......@@ -512,11 +512,11 @@ Out[92]: 6.30307651938
```
现在我们有斜率`m`和常数`c`。 我们的回归线是 *y =* *-0.0294x + 6.3031* ,这表明,随着年龄的增长,人的年龄会略有下降 在他们的睡眠分数/质量中,如下图所示:
现在我们有斜率`m`和常数`c`。 我们的回归线是`y = -0.0294x + 6.3031`,这表明,随着年龄的增长,人的年龄会略有下降 在他们的睡眠分数/质量中,如下图所示:
![Application - regression and curve fitting](img/00015.jpeg)
您可能认为回归线方程看起来很熟悉。 还记得我们在矩阵部分求解的第一个线性方程吗? 是的,您也可以使用`numpy.linalg.lstsq()`来求解 *Ax = b* 方程,实际上这将是本章的第四个解决方案。 自己尝试; 用法与您使用`numpy.linalg.solve()`时非常相似。
您可能认为回归线方程看起来很熟悉。 还记得我们在矩阵部分求解的第一个线性方程吗? 是的,您也可以使用`numpy.linalg.lstsq()`来求解`Ax = b`方程,实际上这将是本章的第四个解决方案。 自己尝试; 用法与您使用`numpy.linalg.solve()`时非常相似。
但是,并非每个问题都能简单地通过绘制回归线来回答,例如按年的房价。 它显然不是线性关系,可能是平方或三次关系。 那么我们如何解决这个问题呢? 让我们使用房价指数(国家统计局 [http://ons.gov.uk/ons/taxonomy/index.html?nscl=House+Price+Indices#tab-data-tables)中的统计数据](http://ons.gov.uk/ons/taxonomy/index.html?nscl=House+Price+Indices#tab-data-tables) ),然后选择 2004 年至 2013 年。我们将平均房价(英镑)调整为通胀因素; 我们想知道明年的平均价格。
......@@ -530,7 +530,7 @@ Out[95]: array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
```
现在我们有了年份和价格数据,我们假设它们之间的关系是平方的。 我们的目标是找到多项式: *y = ax2 + bx + c* 表示关系(一种典型的最小二乘法)。 *y* 代表 *x* `year``price`。 这里我们将使用`numpy.polyfit()`帮助我们找到该多项式的系数:
现在我们有了年份和价格数据,我们假设它们之间的关系是平方的。 我们的目标是找到多项式:`y = ax^2 + bx + c`表示关系(一种典型的最小二乘法)。`y`代表`price``x`代表`year`。 这里我们将使用`numpy.polyfit()`帮助我们找到该多项式的系数:
```py
In [97]: a, b, c = np.polyfit(year, price, 2)
......
# 六、NumPy 中的傅立叶分析
除其他事项外,傅立叶分析通常用于数字信号处理。 这要归功于它在将输入信号(时域)分离为以离散频率(频域)起作用的分量方面如此强大。 开发了另一种快速算法来计算**离散傅里叶变换** **DFT** ),这就是众所周知的 **Fast 傅里叶变换****FFT** ),它为分析及其应用提供了更多可能性。 NumPy 针对数字计算,也支持 FFT。 让我们尝试使用 NumPy 在应用程序上进行一些傅立叶分析! 注意,本章假定不熟悉信号处理或傅立叶方法。
除其他事项外,傅立叶分析通常用于数字信号处理。 这要归功于它在将输入信号(时域)分离为以离散频率(频域)起作用的分量方面如此强大。 开发了另一种快速算法来计算**离散傅里叶变换****DFT**),这就是众所周知的**快速傅里叶变换****FFT**),它为分析及其应用提供了更多可能性。 NumPy 针对数字计算,也支持 FFT。 让我们尝试使用 NumPy 在应用程序上进行一些傅立叶分析! 注意,本章假定不熟悉信号处理或傅立叶方法。
本章将涉及的主题是:
......@@ -39,7 +39,7 @@ def show(ori_func, ft, sampling_period = 5):
```
这是一个名为`show()`的显示函数,它具有两个输入参数:第一个是原始信号函数(`ori_func`),第二个是其傅里叶变换(`ft`)。 此方法将使用`matplotlib.pyplot`模块创建两个折线图:顶部带有黑线的原始信号,其中 *x* 轴表示时间间隔(我们设置了默认值 在我们所有的示例中,信号采样周期为 5 秒), *y* 轴代表信号的幅度。 图表的下部是带有红线的傅里叶变换,其中 *x* 轴表示频率, *y* 代表振幅频谱。
这是一个名为`show()`的显示函数,它具有两个输入参数:第一个是原始信号函数(`ori_func`),第二个是其傅里叶变换(`ft`)。 此方法将使用`matplotlib.pyplot`模块创建两个折线图:顶部带有黑线的原始信号,其中 *x* 轴表示时间间隔(我们设置了默认值 在我们所有的示例中,信号采样周期为 5 秒), *y* 轴代表信号的幅度。 图表的下部是带有红线的傅里叶变换,其中 *x* 轴表示频率, *y* 轴代表振幅频谱。
在下一节中,我们将简单地介绍不同类型的信号波,并使用`numpy.fft`模块计算傅立叶变换。 然后我们调用`show()`函数以提供它们之间的视觉比较。
......@@ -57,7 +57,7 @@ In [4]: show(x, y)
```
在此示例中,我们首先创建了采样时间间隔并将其保存到名为`time``ndarray`中。 然后,我们将`time`阵列乘以 2π并将其频率设为 1 Hz 传递给`numpy.sin()`方法,以创建正弦波(`x`)。 然后将傅立叶变换应用于`x`并将其保存到`y`。 最后,我们使用预定义的方法`show()`与正弦波及其归一化的 Fourier 变换进行视觉比较,如下图所示:
在此示例中,我们首先创建了采样时间间隔并将其保存到名为`time``ndarray`中。 然后,我们将`time`数组乘以 2π并将其频率设为 1 Hz 传递给`numpy.sin()`方法,以创建正弦波(`x`)。 然后将傅立叶变换应用于`x`并将其保存到`y`。 最后,我们使用预定义的方法`show()`与正弦波及其归一化的 Fourier 变换进行视觉比较,如下图所示:
![Signal processing](img/00018.jpeg)
......@@ -82,7 +82,7 @@ In [12]: show(x, y)
从这两个示例中,您必须能够对傅立叶变换有所了解。 接下来,我们将演示另外三种信号处理:一种用于正方形信号,一种用于脉冲,另一种用于随机信号。
首先,我们使用`numpy.zeros()`以相同的时间间隔(`time`)创建方波信号。 我们希望方波频率为 10 Hz,幅度为 1,因此我们将每 20 <sup class="calibre26"></sup>时间间隔( *200/10* )设置为 值 1 可以模拟波浪并将其传递给傅立叶变换,如下面的代码块所示:
首先,我们使用`numpy.zeros()`以相同的时间间隔(`time`)创建方波信号。 我们希望方波频率为 10 Hz,幅度为 1,因此我们将每 20 个时间间隔(`200/10`)设置为值 1,来模拟波浪并将其传递给傅立叶变换,如下面的代码块所示:
```py
In [13]: x = np.zeros(len(time))
......@@ -136,7 +136,7 @@ In [24]: show(x, y)
![Fourier analysis](img/00023.jpeg)
*A* <sub class="calibre25">*k*</sub> 代表离散傅里叶变换, *a <sub class="calibre25">m [</sub>* 代表原始功能。 从 *a <sub class="calibre25">m</sub> -> A <sub class="calibre25">k</sub>* 的转换是从配置空间到频率空间的转换。 让我们手动计算此方程,以更好地了解转换过程。 我们将使用具有 500 个值的随机信号:
`A[k]`代表离散傅里叶变换,`a[m]`代表原始功能。 `a[m] -> A[k]`的转换是从配置空间到频率空间的转换。 让我们手动计算此方程,以更好地了解转换过程。 我们将使用具有 500 个值的随机信号:
```py
In [25]: x = np.random.random(500)
......@@ -148,7 +148,7 @@ In [30]: y = np.dot(M, x)
```
在此代码块中,`x`是我们的模拟随机信号,其中包含 500 个值,并且在公式中对应于 *a <sub class="calibre25">m</sub>* 。 根据`x`的大小,我们计算出:
在此代码块中,`x`是我们的模拟随机信号,其中包含 500 个值,并且在公式中对应于`a[m]`。 根据`x`的大小,我们计算出:
![Fourier analysis](img/00024.jpeg)
......@@ -182,7 +182,7 @@ In [33]: %timeit np.fft.fft(x)
![Fourier analysis](img/00025.jpeg)
我们可以看到反方程与 DFT 方程的不同之处在于指数参数的符号和通过 *1 / n* 进行归一化。 让我们再次进行手动计算。 由于指数参数的符号更改,我们可以重复使用先前代码中的`m``k``n`变量,只需重新计算`M`
我们可以看到反方程与 DFT 方程的不同之处在于指数参数的符号和通过`1 / n`进行归一化。 让我们再次进行手动计算。 由于指数参数的符号更改,我们可以重复使用先前代码中的`m``k``n`变量,只需重新计算`M`
```py
In [34]: M2 = np.exp(2j * np.pi * k * m / n)
......@@ -236,7 +236,7 @@ Out[44]: (1-2.4424906541753444e-15j)
```
在此示例中,`a`是我们的原始随机信号,`A``a`的傅立叶变换。 当我们调用`numpy.fft.fft(a)`时,结果`ndarray`遵循“标准”顺序,其中第一个值`A[0]`包含零频率项(信号的均值)。 进行归一化处理(将其除以原始信号阵列的长度(`A[0]` / 10))时,我们得到的值与计算信号阵列的平均值(`a.mean()`)时的值相同。
在此示例中,`a`是我们的原始随机信号,`A``a`的傅立叶变换。 当我们调用`numpy.fft.fft(a)`时,结果`ndarray`遵循“标准”顺序,其中第一个值`A[0]`包含零频率项(信号的均值)。 进行归一化处理(将其除以原始信号数组的长度(`A[0]` / 10))时,我们得到的值与计算信号数组的平均值(`a.mean()`)时的值相同。
然后`A[1:n/2]`包含正频率项,`A[n/2 + 1: n]`包含负频率项。 在我们的示例中,当输入为偶数时,`A[n/2]`代表正数和负数。 如果要将零频率分量移到频谱中心,可以使用`numpy.fft.fftshift()` 例程。 请参见以下示例:
......@@ -303,7 +303,7 @@ In [57]: plt.show()
![Fourier transform application](img/00028.jpeg)
预处理部分完成。 我们将图像读取到三维`ndarray``img`)中,并应用[亮度]公式使用 *0.21R + 0.72G + 0.07B* 将 RGB 图像转换为灰度图像 。 我们使用`matplotlib`中的`pyplot`模块显示灰度图像。 这里我们在图中未应用任何轴标签,但是从轴比例可以看到`ndarray gray_img`代表 317 x 661 像素的图像。
预处理部分完成。 我们将图像读取到三维`ndarray``img`)中,并应用[亮度]公式使用`0.21R + 0.72G + 0.07B`将 RGB 图像转换为灰度图像 。 我们使用`matplotlib`中的`pyplot`模块显示灰度图像。 这里我们在图中未应用任何轴标签,但是从轴比例可以看到`ndarray gray_img`代表`317 x 661`像素的图像。
接下来,我们将进行傅立叶变换并显示频谱:
......@@ -320,7 +320,7 @@ In [61]: plt.show()
![Fourier transform application](img/00029.jpeg)
首先,我们对`gray_img`使用二维傅立叶变换,并使用对数刻度色图绘制幅度谱。 我们可以看到,由于零频率分量,拐角有所不同。 请记住,当我们使用`numpy.fft.fft2()`时,该顺序遵循*标准*的顺序,并且我们希望将零频分量置于中心。 因此,让我们使用 shift 例程:
首先,我们对`gray_img`使用二维傅立叶变换,并使用对数刻度色图绘制幅度谱。 我们可以看到,由于零频率分量,拐角有所不同。 请记住,当我们使用`numpy.fft.fft2()`时,该顺序遵循*标准*的顺序,并且我们希望将零频分量置于中心。 因此,让我们使用`shift`例程:
```py
In [62]: fft_shift = np.fft.fftshift(fft)
......@@ -354,7 +354,7 @@ In [74]: plt.show()
![Fourier transform application](img/00031.jpeg)
在上一个代码块中,我们首先获取了`fft_shift`数组的形状(大小与`gray_img`相同)。 然后我们创建了两个零`ndarrays`并将它们沿四个方向填充到`fft_shift`数组中以将其放大。 因此,当我们将修改后的`fft_shift`阵列逆回到标准阶数时,零频率将完美地位于中间。 当我们进行逆变换时,您可以看到形状已经加倍。 为了让`pyplot`模块绘制新数组,我们需要将数组转换为实数。 绘制新数组后,我们可以看到轴刻度是其大小的两倍。 而且,我们几乎不会丢失任何细节或图像模糊。 已使用傅立叶变换对图像进行插值。
在上一个代码块中,我们首先获取了`fft_shift`数组的形状(大小与`gray_img`相同)。 然后我们创建了两个零`ndarrays`并将它们沿四个方向填充到`fft_shift`数组中以将其放大。 因此,当我们将修改后的`fft_shift`数组逆回到标准阶数时,零频率将完美地位于中间。 当我们进行逆变换时,您可以看到形状已经加倍。 为了让`pyplot`模块绘制新数组,我们需要将数组转换为实数。 绘制新数组后,我们可以看到轴刻度是其大小的两倍。 而且,我们几乎不会丢失任何细节或图像模糊。 已使用傅立叶变换对图像进行插值。
# 摘要
......
# 七、构建和分发 NumPy 代码
在现实世界中,您将编写一个应用程序,以将其分发到 World 或在其他各种计算机上重用。 为此,您希望应用程序以标准方式打包,以便社区中的每个人都能理解和遵循。 正如您现在已经注意到的那样,Python 用户主要使用名为`pip`的程序包管理器来自动安装其他程序员创建的模块。 Python 具有一个称为 **PyPI****Python 软件包索引**)的打包平台,该平台是 50,000 多个 Python 软件包的官方中央存储库。 一旦在 PyPi(又名 *Cheese Shop* )中注册了软件包,世界各地的其他用户都可以在使用`pip`等软件包管理系统对其进行配置后进行安装。 Python 随附了许多解决方案,可帮助您构建代码以准备分发给 *Cheese Shop* ,并且在本章中,我们将重点介绍两个此类工具,`setuptools``Distutils` 除了这两个工具之外,我们还将研究 NumPy 提供的称为`numpy.distutils`的特定模块。 该模块使程序员更容易构建和分发特定于 NumPy 的代码。 该模块还提供了其他功能,例如用于编译 Fortran 代码,调用`f2py,`等的方法。 在本章中,我们将通过以下步骤来学习包装工作流程:
在现实世界中,您将编写一个应用程序,以将其分发到 World 或在其他各种计算机上重用。 为此,您希望应用程序以标准方式打包,以便社区中的每个人都能理解和遵循。 正如您现在已经注意到的那样,Python 用户主要使用名为`pip`的程序包管理器来自动安装其他程序员创建的模块。 Python 具有一个称为 **PyPI****Python 软件包索引**)的打包平台,该平台是 50,000 多个 Python 软件包的官方中央存储库。 一旦在 PyPi(又名 *Cheese Shop*)中注册了软件包,世界各地的其他用户都可以在使用`pip`等软件包管理系统对其进行配置后进行安装。 Python 随附了许多解决方案,可帮助您构建代码以准备分发给 *Cheese Shop* ,并且在本章中,我们将重点介绍两个此类工具,`setuptools``Distutils` 除了这两个工具之外,我们还将研究 NumPy 提供的称为`numpy.distutils`的特定模块。 该模块使程序员更容易构建和分发特定于 NumPy 的代码。 该模块还提供了其他功能,例如用于编译 Fortran 代码,调用`f2py,`等的方法。 在本章中,我们将通过以下步骤来学习包装工作流程:
* 我们将建立一个小的但可行的设置
* 我们将说明将 NumPy 模块集成到您的设置中的步骤
......@@ -101,7 +101,7 @@ setup(
* `install_required`-这是用于添加安装依赖性的列表。 您将添加代码中使用的第三方模块的名称和版本。 请注意遵循约定以在此处指定版本。
* `classifiers`-当您在 PyPI 网站上上传软件包时,将选中此选项。 您应该从以下网站提供的选项中进行选择: [https://pypi.python.org/pypi?:action=list_classifiers](https://pypi.python.org/pypi?:action=list_classifiers)
现在,使用 **build** 选项运行`setup.py`应该不会给您任何错误,并生成带有`.egg-info`后缀的文件夹。 此时,您可以使用 **sdist** 选项运行`setup.py`,并创建一个可以与世界共享的软件包。
现在,使用`build`选项运行`setup.py`应该不会给您任何错误,并生成带有`.egg-info`后缀的文件夹。 此时,您可以使用`sdist`选项运行`setup.py`,并创建一个可以与世界共享的软件包。
您应该看到最终消息为**创建 tar 归档文件**,如下所示:
......@@ -256,4 +256,4 @@ if __name__ == "__main__":
# 摘要
在本章中,我们介绍了用于打包和分发应用程序的工具。 我们首先看了一个更简单的`setup.py`文件。 您研究了功能设置的属性以及这些参数如何链接到最终安装程序。 接下来,我们添加了与 NumPy 相关的代码,并添加了一些异常处理代码。 最后,我们构建了安装程序并学习了如何在 *Cheese Shop* (PyPI 网站)上上传它。 在下一章中,您将研究通过将 Python 代码的一部分转换为 Cython 来进一步加速 Python 代码的方法。
\ No newline at end of file
在本章中,我们介绍了用于打包和分发应用程序的工具。 我们首先看了一个更简单的`setup.py`文件。 您研究了功能设置的属性以及这些参数如何链接到最终安装程序。 接下来,我们添加了与 NumPy 相关的代码,并添加了一些异常处理代码。 最后,我们构建了安装程序并学习了如何在 *Cheese Shop*(PyPI 网站)上上传它。 在下一章中,您将研究通过将 Python 代码的一部分转换为 Cython 来进一步加速 Python 代码的方法。
\ No newline at end of file
......@@ -124,7 +124,7 @@ cmdclass={'build_ext': build_ext}
# 多线程代码
您的应用程序可能会使用多线程代码。 由于**全局解释器锁** **GIL** ),Python 不适合多线程代码。 好消息是,在 Cython 中,您可以显式解锁 GIL,并使您的代码真正成为多线程。 只需在您的代码中放置一个`with nogil:`语句即可。 您以后可以在代码中使用`with gil`获取 GIL:
您的应用程序可能会使用多线程代码。 由于**全局解释器锁****GIL**),Python 不适合多线程代码。 好消息是,在 Cython 中,您可以显式解锁 GIL,并使您的代码真正成为多线程。 只需在您的代码中放置一个`with nogil:`语句即可。 您以后可以在代码中使用`with gil`获取 GIL:
```py
with nogil:
......@@ -136,7 +136,7 @@ function_name(args) with gil:
# NumPy 和 Cython
Cython 具有内置支持,可提供对 NumPy 阵列的更快访问。 这些功能使 Cython 成为优化 NumPy 代码的理想人选。 在本节中,我们将研究用于计算欧式期权价格的代码,欧式期权是一种使用蒙特卡洛技术的金融工具。 不期望有金融知识; 但是,我们假设您对蒙特卡洛模拟有基本的了解:
Cython 具有内置支持,可提供对 NumPy 数组的更快访问。 这些功能使 Cython 成为优化 NumPy 代码的理想人选。 在本节中,我们将研究用于计算欧式期权价格的代码,欧式期权是一种使用蒙特卡洛技术的金融工具。 不期望有金融知识; 但是,我们假设您对蒙特卡洛模拟有基本的了解:
```py
defprice_european(strike = 100, S0 = 100, time = 1.0,
......
......@@ -152,7 +152,7 @@ return Py_BuildValue("f", answer);
# 使用 NumPy C-API 创建数组平方函数
在本节中,我们将创建一个函数以对 NumPy 数组的所有值求平方。 这里的目的是演示如何在 C 语言中获取 NumPy 数组,然后对其进行迭代。 在现实世界中,可以使用地图或通过量化平方函数以更简单的方式完成此操作。 我们正在使用与`O!`格式字符串相同的`PyArg_ParseTuple`函数。 该格式字符串具有`(object) [typeobject, PyObject *]`签名,并以 Python 类型对象作为第一个参数。 用户应阅读官方 API 文档,以查看允许使用其他格式的字符串以及哪种字符串适合他们的需求:
在本节中,我们将创建一个函数以对 NumPy 数组的所有值求平方。 这里的目的是演示如何在 C 语言中获取 NumPy 数组,然后对其进行迭代。 在现实世界中,可以使用地图或通过量化平方函数以更简单的方式完成此操作。 我们正在使用与`O!`格式字符串相同的`PyArg_ParseTuple`函数。 该格式字符串具有`(object) [typeobject, PyObject *]`签名,并以 Python 类型对象作为第一个参数。 用户应阅读官方 API 文档,以查看允许使用其他格式的字符串以及哪种字符串适合他们的需求:
### 注意
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册