精通-Python-科学计算-全-

精通 Python 科学计算(全)

原文:Mastering Python Scientific Computing

协议:CC BY-NC-SA 4.0

零、前言

|   | “我绝对相信,几十年后,科学历史学家将把我们现在所处的时期描述为科学结构发生深刻而重大转变的时期。在这个过程中,免费公开可用工具的兴起起到了核心作用。” |   |
|   | - 费尔南多·佩雷斯,IPython 的创造者 |

这本书涵盖了用于执行科学计算的 Python APIs 和工具包。强烈推荐给执行计算机化工程或科学计算的读者。科学计算是一个跨学科的分支,需要计算机科学、数学、普通科学(至少是物理、化学、环境科学、生物学和其他学科的任何一个分支)和工程学的背景。Python 由大量的包、API 和工具包组成,用于支持这些不同的科学和工程领域所需的功能。

庞大的用户社区、大量的帮助和文档、大量的科学库和环境、出色的性能和良好的支持使 Python 成为科学计算的绝佳选择。

这本书涵盖了什么

第 1 章科学计算的景观——为什么是 Python?,介绍科学计算的基本概念。还讨论了 Python 的背景、指导原则,以及为什么使用 Python 进行科学计算是有效的。

第 2 章更深入地探讨科学工作流和科学计算秘籍的成分,讨论解决科学问题通常需要的数学和数值分析的各种概念。它还简要介绍了用 Python 语言执行科学计算的包、工具包和 API。

第 3 章高效制造和管理科学数据,讨论了科学应用底层数据的所有方面,包括基本概念、各种操作以及用于存储数据的格式和软件。它还介绍了标准数据集和准备合成数据的技术。

第 4 章Python 的科学计算 API,涵盖了各种科学计算 API 和工具包的基本概念、特性和精选示例程序,包括 NumPy、SciPy 和 SymPy。本章还使用 IPython、matplotlib 和 pandas 讨论了交互式计算、数据分析和数据可视化的基本介绍。

第 5 章执行数值计算,讨论如何使用 Python 的 NumPy 和 SciPy 包执行数值计算。本章从数值计算的基础知识开始,涵盖了许多高级概念,如优化、插值、傅里叶变换、信号处理、线性代数、统计学、空间算法、图像处理、文件输入/输出等。

第 6 章将 Python 应用于符号计算,从计算机化代数系统(CAS)的基础知识开始,并使用 SymPy 执行符号计算。它涵盖了 CAS 的广泛主题,从使用简单表达式和基本算术到数学和物理的高级概念。

第 7 章数据分析与可视化,介绍 matplotlib 和 pandas 的概念及在数据分析与可视化中的应用。

第 8 章并行和大规模科学计算讨论了使用 IPython(使用 MPI 完成)的高性能科学计算、使用 StarCluster 的 Amazon EC2 集群的管理、多处理、多线程、Hadoop 和 Spark 的概念。

第 9 章重温真实案例研究,说明了使用 Python 语言开发的科学计算应用、库和工具的几个案例研究。本章介绍了从不同工程和科学领域研究的一些案例。

第 10 章科学计算的最佳实践,讨论了科学计算的最佳实践。它包括设计、编码、数据管理、应用部署、高性能计算、安全性、数据隐私、维护和支持方面的最佳实践。我们还介绍了基于 Python 的一般开发的最佳实践。

这本书你需要什么

本书给出的示例程序需要一台 Python 2.7.9 或更高版本的计算机,以及几个 Python APIs 包/工具包。您还将需要一些 Python 库(即 NumPy、SciPy、SymPy、matplotlib、pandas、IPython)、IPython.parallel 包、pyzmq、用于安全性的 SSH(如果需要)和 Hadoop。

这本书是给谁的

这本书是为那些愿意亲自接触科学计算的 Python 程序员准备的。这本书期望你已经接触了 Python 编程的各种概念。

惯例

在这本书里,你会发现许多区分不同种类信息的文本样式。以下是这些风格的一些例子和对它们的意义的解释。

文本中的码字、数据库表名、文件夹名、文件名、文件扩展名、路径名、伪 URL、用户输入和 Twitter 句柄如下所示:“随机模块的函数是random.Random类的隐藏实例的绑定方法。”

代码块设置如下:

import random
print random.random()
print random.uniform(1,9)
print random.randrange(20)
print random.randrange(0, 99, 3) 
print random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ') # Output 'P'
items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
random.shuffle(items)
print items
print random.sample([1, 2, 3, 4, 5, 6, 7, 8, 9, 10],  5)   
weighted_choices = [('Three', 3), ('Two', 2), ('One', 1), ('Four', 4)]
population = [val for val, cnt in weighted_choices for i in range(cnt)]
print random.choice(population)

警告或重要提示会出现在这样的框中。

型式

提示和技巧是这样出现的。

读者反馈

我们随时欢迎读者的反馈。让我们知道你对这本书的看法——你喜欢或不喜欢什么。读者反馈对我们来说很重要,因为它有助于我们开发出你真正能从中获益的标题。

要给我们发送一般反馈,只需发送电子邮件<[feedback@packtpub.com](mailto:feedback@packtpub.com)>,并在您的邮件主题中提及书名。

如果你对某个主题有专业知识,并且对写作或投稿感兴趣,请参见我们位于www.packtpub.com/authors的作者指南。

客户支持

现在,您已经自豪地拥有了一本书,我们有许多东西可以帮助您从购买中获得最大收益。

下载示例代码

您可以从您在http://www.packtpub.com的账户下载您购买的所有 Packt Publishing 书籍的示例代码文件。如果您在其他地方购买了这本书,您可以访问http://www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给您。

下载本书的彩色图片

我们还为您提供了一个 PDF 文件,其中包含本书中使用的截图/图表的彩色图像。彩色图像将帮助您更好地理解输出中的变化。您可以从https://www . packtpub . com/sites/default/files/downloads/8823 OS . pdf下载此文件。

勘误表

尽管我们尽了最大努力来确保我们内容的准确性,但错误还是会发生。如果你在我们的某本书里发现了错误——可能是文本或代码中的错误——如果你能向我们报告,我们将不胜感激。通过这样做,你可以让其他读者免受挫折,并帮助我们改进这本书的后续版本。如果您发现任何勘误表,请访问http://www.packtpub.com/submit-errata,选择您的书籍,点击勘误表提交表链接,并输入您的勘误表的详细信息。一旦您的勘误表得到验证,您的提交将被接受,勘误表将上传到我们的网站或添加到该标题勘误表部分下的任何现有勘误表列表中。

要查看之前提交的勘误表,请前往https://www.packtpub.com/books/content/support并在搜索栏中输入图书名称。所需信息将出现在勘误表部分。

盗版

互联网上版权材料的盗版是所有媒体的一个持续问题。在 Packt,我们非常重视版权和许可证的保护。如果您在互联网上遇到任何形式的我们作品的非法拷贝,请立即向我们提供位置地址或网站名称,以便我们寻求补救。

请通过<[copyright@packtpub.com](mailto:copyright@packtpub.com)>联系我们,获取疑似盗版资料的链接。

我们感谢您在保护我们的作者方面的帮助,以及我们为您带来有价值内容的能力。

问题

如果您对本书的任何方面有问题,可以在<[questions@packtpub.com](mailto:questions@packtpub.com)>联系我们,我们将尽最大努力解决问题。

一、科学计算的前景——为什么是 Python?

使用计算机化的数学建模和数值分析技术来分析和解决科学和工程领域的问题被称为科学计算。科学问题包括来自各个科学分支的问题,如地球科学、空间科学、社会科学、生命科学、物理科学和形式科学。这些分支几乎涵盖了现有的所有科学领域,从传统科学到现代工程科学,如计算机科学。工程问题包括从土木和电气到(最新的)生物医学工程的问题。

在本章中,我们将涵盖以下主题:

  • 科学计算基础
  • 科学计算过程的流程
  • 科学和工程领域的例子
  • 解决复杂问题的策略
  • 近似值、误差和相关术语
  • 误差分析的概念
  • 计算机算术和浮点数
  • Python 的背景
  • 为什么选择 Python 进行科学计算?

数学建模是指涉及数学术语来表示设备、对象、现象和概念的行为的建模活动。一般来说,它有助于更好地理解概念、设备或对象的行为或观察。它可能有助于解释对某些未来行为的观察和可能的预测,或者还有待观察或测量的结果。数值分析是计算机科学和数学的一个领域,它设计、分析并最终实现算法,以数值方式解决自然科学(例如,物理、生物和地球科学)、社会科学(例如,经济学、心理学、社会学和政治学)、工程、医学和商业的问题。有一个名为Python Dynamics(PyDy)的包和工作流,用于研究多体动力学。它是一个工作流和一个软件包,是在 Sympymechanism 软件包的基础上开发的。PyDy 扩展了 SymPy,便于多体动力学的仿真。

科学计算的定义

科学计算也可称为计算科学科学计算。它主要是发展数学模型、使用定量分析技术和使用计算机解决科学问题的思想。

|   | “科学计算是在计算机上解决科学和工程问题的数学模型所需的工具、技术和理论的集合。” |   |
|   | - 吉恩·h·戈鲁伯和詹姆斯·m·奥尔特加 |

简单来说,科学计算可以被描述为一个跨学科的领域,如下图所示:

Definition of scientific computing

作为跨学科领域的科学计算

科学计算需要对要解决的潜在问题的主题有所了解(一般来说,这将是一个来自科学或工程领域的问题),具有各种数值分析技术的合理想法的数学建模能力,以及最终使用计算技术的高效和高性能实现。它还要求应用计算机;各种外围设备,包括网络设备、存储单元、处理单元以及数学和数值分析软件;编程语言;和任何数据库以及对问题领域的良好了解。计算和相关技术的使用使更新的应用成为可能,科学家可以从现有的数据和过程中推断出新的知识。

就计算机科学而言,科学计算可以被认为是数学模型和领域数据/信息的数值模拟。模拟背后的目标取决于被模拟应用的领域。目标可以是了解事件背后的原因、重建特定情况、优化流程或预测事件的发生。有几种情况下,数值模拟是唯一的选择,或者最好的选择。有些现象或情况下,进行实验几乎是不可能的,例如,气候研究、天体物理学和天气预报。在其他一些情况下,实际实验并不可取,例如,检查某些材料或产品的稳定性或强度。有些实验在时间/经济方面非常昂贵,例如车祸或生命科学实验。在这种情况下,科学计算可以帮助用户分析和解决问题,而无需花费太多时间或成本。

科学计算过程的简单流程

下图描述了一个科学应用的简单计算流程图。第一步是为所考虑的问题设计一个数学模型。数学模型制定后,下一步是开发其算法。然后使用合适的编程语言和合适的实现框架来实现该算法。选择编程语言是一个关键的决定,它取决于应用的性能和处理要求。另一个接近的决定是最终确定用于实施的框架。在确定了语言和框架之后,实现了算法并进行示例模拟。然后分析仿真结果的性能和正确性。如果实施的结果或绩效不符合预期,应确定其原因。然后我们需要回到要么重新制定数学模型,要么重新设计算法或其实现,并再次选择语言和框架。

一个数学模型是由一组合适的方程来表达的,这些方程将大多数问题描述得非常详细。该算法以单独的步骤表示求解过程,这些步骤将使用合适的编程语言或脚本来实现。

实现之后,有一个重要的步骤要执行——对实现的代码进行模拟运行。这包括设计实验基础设施、准备或安排用于模拟的数据/情况、准备要模拟的场景等等。

在完成模拟运行后,下一步需要收集结果并呈现出来,以分析结果,从而测试模拟的有效性。如果结果不像预期的那样,那么这可能需要返回到该过程的先前步骤之一来纠正和重复它们。这种情况在下图中以虚线的形式回到前面的一些步骤。如果一切进展顺利,那么分析将是工作流程的最后一步,在此图中用双线表示:

A simple flow of the scientific computation process

科学计算工作流程中的各个步骤

解决任何数学问题的算法的设计和分析,特别是关于科学和工程的,被称为数值分析,现在也被称为科学计算。在科学计算中,考虑的问题主要涉及连续值,而不是离散值。后者在其他计算机科学问题中处理。一般来说,科学计算解决的问题涉及具有连续变量的函数和方程,例如时间、距离、速度、重量、高度、大小、温度、密度、压力、应力等等。

一般来说,连续数学的问题都有近似解,因为它们的精确解并不总是可以在有限的步骤中得到。因此,这些问题通过迭代过程来解决,最终收敛到一个可接受的解。可接受的解决方案取决于具体问题的性质。一般来说,迭代过程不是无限的,每次迭代后,为了模拟的目的,当前解会更接近期望解。回顾解的准确性和对解的快速收敛形成了科学计算过程的要点。

有一些成熟的科学领域使用科学计算来解决问题。它们如下:

  • 计算流体动力学语言
  • 大气科学
  • 地震学
  • 结构分析
  • 化学
  • 磁流体力学
  • 油藏建模
  • 全球海洋/气候建模
  • 天文学/天体物理学
  • 宇宙学
  • 环境研究
  • 核工程

最近,一些新兴领域也开始利用科学计算的力量。它们包括:

  • 生物
  • 经济学
  • 材料研究
  • 医学成像
  • 畜牧学

来自科学/工程领域的示例

让我们来看看使用科学计算可能解决的一些问题。第一个问题是研究两个黑洞碰撞的行为,这在理论和实践上都很难理解。从理论上讲,这个过程极其复杂,在实验室里进行并进行现场研究几乎是不可能的。但是这种现象可以在计算实验室中用爱因斯坦广义相对论的数学公式的适当和有效的实现来模拟。然而,这需要非常高的计算能力,这可以使用先进的分布式计算基础设施来实现。

第二个问题与工程和设计有关。考虑一个与汽车测试相关的问题,叫做碰撞测试。为了降低进行有风险的实际碰撞测试的成本,工程师和设计师更喜欢进行计算机模拟碰撞测试。最后,考虑设计大房子或工厂的问题。有可能构建提议的基础设施的虚拟模型。但这需要合理的时间,而且成本高昂。然而,这种设计可以使用架构设计工具来完成,这将节省大量的时间和成本。生物信息学和医学科学中也可以有类似的例子,比如蛋白质结构折叠和传染病建模。研究蛋白质结构折叠是一个非常耗时的过程,但可以使用大型超级计算机或分布式计算系统高效地完成。同样,传染病建模将节省分析各种参数对该疾病疫苗接种计划影响的努力和成本。

选择这三个例子是因为它们代表了可以使用科学计算解决的三类不同的问题。第一个问题几乎不可能。第二个问题是可能的,但在一定程度上是有风险的,可能会导致严重的损害。最终的问题可以在没有任何模拟的情况下解决,并且有可能在现实生活中复制它。然而,它比它的模拟更加昂贵和耗时。

解决复杂问题的策略

为复杂的计算问题寻找解决方案的简单策略是首先确定解决方案中的困难区域。现在,一个接一个地,开始用它们的解决方案替换这些小的困难部分,这些解决方案将导致相同的解决方案或在特定问题的允许限度内的解决方案。换句话说,最好的想法是将一个大的、复杂的问题简化为一组较小的问题。它们中的每一个都可能复杂或简单。现在,每个复杂的子问题都可能被一个类似的简单问题所取代,这样,我们最终会得到一个更简单的问题来解决。基本思想是将各个击破的技术与变小的复杂问题与类似的简单问题相结合。

采纳这个想法时,我们应该注意两个要点。第一个是我们需要搜索一个相似的问题或者一个有同一个类的解的问题。第二个是,就在用一个问题替换另一个问题之后,我们需要确定最终解决方案是否保留在公差范围内,如果不是完全保留的话。一些例子可能如下:

  • 为简单起见,将问题中的无限维空间改为有限维空间
  • 用有限过程改变无限过程,如用有限和或有限差的导数代替积分或无穷级数
  • 如果可行,那么代数方程可以用来代替微分方程
  • 尝试用线性问题代替非线性问题,因为线性问题很容易解决
  • 如果可行,可以将复杂的功能更改为多个简单的功能,以实现简单性

近似值、误差以及相关的概念和术语

这些科学计算解通常产生近似解。通过近似解,我们的意思是代替精确的期望解,获得的解将与它几乎相似。几乎相似,我们的意思是,这将是一个足够接近的解决方案,认为实际或模拟成功,因为他们完成了目的。这种近似或类似的解决方案是由多种原因造成的。这些来源可以分为两类:在计算开始前出现的来源和在计算过程中出现的来源。

计算开始前出现的近似值可能是由以下一个或多个因素引起的:

  • 建模过程中的假设或忽略:建模过程中可能存在假设,同样建模过程中忽略或忽略概念或现象的影响,这可能导致近似或可容忍的不准确性。
  • 来自观测或实验的数据:不准确的地方可能是从一些精度较低的设备获得的数据。在计算过程中,有一些常数,如 pi,其值必须近似,这也是偏离正确结果的一个重要原因。
  • 先决条件计算:数据可能是从以前的实验结果中获得的,或者模拟可能有微小的、可接受的不准确性,最终导致进一步的近似。这种预先处理可能是后续实验的先决条件。

计算过程中的近似是由以下一个或多个来源引起的:

  • 问题的简化:正如我们在本章中已经建议的,解决大而复杂的问题,应该采用“分而治之”的组合,用更简单的问题代替小而复杂的问题。这可能导致近似值。考虑到我们用有限级数代替无限级数可能会导致近似。
  • 舍位与舍位:多种情况要求中间结果舍位与舍位。同样,计算机中浮点数的内部表示及其算术也会导致微小的不准确性。

计算问题最终结果的近似值可能是前面讨论的各种来源的任意组合的结果。最终输出的精度可能会降低或提高,这取决于所解决的问题和解决问题的方法。

Approximation, errors, and associated concepts and terms

计算中误差和近似值的分类

误差分析

误差分析是用于观察这种近似对算法或计算过程精度的影响的过程。在随后的文本中,我们将讨论与错误分析相关的基本概念。

从前面关于近似值的讨论中可以观察到,误差可以被认为是输入数据中的误差,并且它们是在对该输入数据进行计算的过程中出现的。

在类似的路径上,计算误差可以再次分为两类:截断误差和舍入误差。截断误差是将复杂问题简化为简单问题的结果,例如,在达到所需精度之前迭代的不成熟终止。舍入误差是用于计算机计算的数字系统中表示数字的精度的结果,也是对这些数字进行算术运算的结果。

最终,显著或可忽略的误差量取决于数值的大小。例如,最终值 15 的误差 10 是非常显著的,而最终值 785 的误差 10 不是那么显著。此外,在获得 17,685 的最终值时,同样的误差 10 是可以忽略的。通常,误差值的影响与结果值有关。如果我们知道要获得的最终值的大小,那么在查看误差值后,我们可以决定是忽略它还是认为它是显著的。如果错误很大,那么我们应该开始采取纠正措施。

条件、稳定性和准确性

让我们讨论问题和算法的一些重要性质。灵敏度或条件是一个问题的属性。正在考虑的问题可以被称为敏感或不敏感,也可以被称为条件反射良好或条件反射不良。如果对于给定的输入相对变化,数据将对结果产生成比例的相对最终影响,则称问题不敏感或条件良好。另一方面,如果最终结果的相对影响比输入数据的相对变化大得多,则该问题将被视为敏感或病态问题。

前后向误差分析

假设我们通过 f 映射数据 x 得到了近似值 y* ,例如 y=f(x)* 。现在,如果实际结果是 y ,那么小数量 y' =y-y* 称为一个 正向误差,其估计称为正向误差分析。一般来说,很难获得这个估计。另一种方法是将 y* 视为修改后数据的相同问题的精确解,即y * = f(x’)。现在,数量 x=x'-x* 在 y* 中被称为向后误差。后向误差分析是×的估计过程。

忽略这些错误可以吗?

这个问题的答案取决于你将应用科学计算的领域和应用。例如,如果是计算发射导弹的时间,0.1 秒的误差将导致严重的损坏。另一方面,如果是计算一列火车的到达时间,40 秒的误差不会导致大问题。同样,药物剂量的微小变化也会对患者产生灾难性的影响。一般来说,如果应用中的计算错误与人命损失无关,或者不涉及大的成本,那么它可以被忽略。否则,我们需要采取适当的努力来解决这个问题。

计算机算术和浮点数

由于实数在计算机中的表示,引入了科学计算中的一种近似。通过对这些实数进行算术运算,这个近似值被进一步放大。在这一节中,我们将讨论实数的这种表示,对这些数的算术运算,以及它们对计算结果的可能影响。然而,这些近似误差不仅出现在计算机计算中;它们可能出现在非计算机化的手动计算中,因为舍入是为了降低复杂性。然而,并非只有在计算机计算的情况下才会出现这些近似值。它们也可以在非计算机化的手动计算中观察到,因为四舍五入是为了降低计算的复杂性。

在继续讨论实数的计算机化表示之前,让我们先回顾一下数学中使用的著名的科学符号。在科学记数法中,为了把一个很大或很小的数的表示简化成一个简短的形式,我们把几乎相同的量乘以 10 的某些幂。同样,在科学符号中,数字以“ a 乘以 10 的形式表示为幂 b ,即 a X 10b 。例如,0.000000987654 和 987,654 可以分别表示为 9.87654 x 10^-79.87654 x 10^5 。在该表示中,指数是一个整数,系数是一个实数,称为尾数

电气和电子工程师协会 ( IEEE ) 已经标准化了 IEEE 754 中的浮点数表示。大多数现代机器使用这个标准,因为它解决了各种浮点数表示中发现的大多数问题。该标准的最新版本于 2008 年发布,被称为 IEEE 754-2008 。该标准定义了算术格式、交换格式、舍入规则、运算和异常处理。它还包括对高级异常处理、附加操作和表达式求值的建议,并告诉我们如何获得可再现的结果。

Python 编程语言的背景

Python 是一种通用的高级编程语言,支持大多数编程范例,包括过程式、面向对象、命令式、面向方面和函数式编程。它还支持使用扩展的逻辑编程。它是一种解释语言,帮助程序员用比 C++、Java 或其他语言中相同概念的代码更少的行组成一个程序。Python 支持动态类型和自动内存管理。它有一个大而全面的标准库,现在它还支持许多特定任务的许多自定义库。使用包管理器(如pipeasy_installhomebrew (OS X)、apt-get (Linux)等)安装包非常容易。

Python 是一种开源语言;它的解释器适用于大多数操作系统,包括 Windows、Linux、OS X 和其他操作系统。有许多工具可以将 Python 程序转换为不同操作系统的可执行形式,例如 Py2exe 和 PyInstaller。这种可执行形式是独立的代码,不需要 Python 解释器来执行。

Python 语言的指导原则

Python 的指导原则由吉多·范·罗苏姆(他也被称为 【一生的仁慈独裁者】(【BDFL】)编写,蒂姆·皮特斯(Tim Peters)将其转换成了一些格言,并在https://www.python.org/dev/peps/pep-0020/发布。让我们用一些解释来讨论这些,如下所示:

  • 美胜于丑:这背后的哲学是为人类读者编写程序,简单的表达语法,所有程序的语法和行为一致。
  • 显式比隐式好:大多数概念都保持显式,就像显式布尔类型一样。我们对布尔变量使用了一个显式的文字值——真或假,而不是依赖于零或非零整数。尽管如此,它确实支持基于整数的布尔概念。非零值被视为布尔值。同样,它的for循环可以在不管理变量的情况下操作数据结构。同一个循环可以遍历字符串中的元组和字符。
  • 简单胜于复杂:内存分配和垃圾收集器管理内存的分配或释放,避免复杂性。在简单的 print 语句中引入了另一个简单性。这避免了使用文件描述符进行简单打印。此外,对象会自动转换为逗号分隔值的可打印形式。
  • 复杂总比复杂好:科学计算概念复杂,但这并不意味着程序会复杂。Python 程序并不复杂,即使对于非常复杂的应用也是如此。“Pythonic”的方式本来就很简单,SciPy 和 NumPy 包就是很好的例子。
  • 扁平化优于嵌套 : Python 在其标准库中提供了种类繁多的模块。Python 中的名称空间保持扁平结构,不需要使用很长的名称,比如java.net.socket而不是 Python 中的简单套接字。Python 的标准库遵循电池包含的理念。这个标准库提供了适用于许多任务的工具。例如,为开发丰富的互联网应用,支持各种网络协议的模块。类似地,图形用户界面编程、数据库编程、正则表达式、高精度算术、单元测试等模块都捆绑在标准库中。库中的部分模块包括网络(socketselectSocketServerBaseHTTPServerasyncoreasynchatxmlrpclibSimpleXMLRPCServer)、互联网协议(urllibhttplibftplibsmtpdsmtplibpoplibimaplibjson)、数据库(anydbmpickleshelvesqlite3mongodb)以及并行处理(subprocess
    *** 稀疏总比密集好:Python 标准库保持浅,Python 包索引维护着旨在支持某个主题的深度操作的第三方包的详尽列表。我们可以使用pip安装定制的 Python 包。* 可读性计数:你的程序的块结构应该使用空格创建,Python 在语法中使用最少的标点符号。当分号引入块时,行尾不需要分号。允许使用分号,但并不是每一行代码都需要分号。同样,在大多数情况下,表达式不需要括号。Python 引入了用于生成 API 文档的内联文档。Python 的文档可以在运行时和在线获得。* 特例还没有特殊到可以打破规则:这背后的哲学就是 Python 中的一切都是对象。所有内置类型都实现为对象。表示数字的数据类型有方法。甚至函数本身也是带有方法的对象。* 虽然实用性胜过纯粹性 : Python 支持多种编程风格,让用户可以选择最适合自己问题的风格。它支持面向对象、过程、函数和更多类型的编程。* 错误永远不应该无声无息地传递:它使用异常处理的概念来避免在低级别的 API 上处理错误,以便在编写使用这些 API 的程序时,可以在更高级别的 API 上处理错误。它支持具有特定含义的标准异常的概念,并且允许用户为自定义错误处理定义异常。为了支持代码调试,提供了回溯的概念。在 Python 程序中,默认情况下,错误处理机制会打印指向stderr中错误的完整回溯。回溯包括源文件名、行号和源代码(如果有的话)。* 除非明确沉默:为了处理某些情况,有一些选项可以让错误无声无息地过去。对于这些情况,我们可以使用try语句而不用except。还有一个将异常转换为字符串的选项。* 面对歧义,拒绝猜测的诱惑:只有在不意外的情况下才会进行自动类型转换。例如,整数操作数和浮点操作数之间的运算会产生浮点值。* 应该有一个,最好只有一个显而易见的做法:这个非常明显。它要求消除所有冗余。因此,更容易学习和记忆。* 虽然一开始这种方式可能不明显,除非你是荷兰人:我们在前面讨论的方式适用于标准库。当然,第三方模块也会有冗余。例如,我们支持多个图形用户界面,如 GTK、wxPython 和 KDE。类似地,对于网络编程,我们有 Django、AppEngine 和金字塔。* 现在总比没有好:这个说法是为了激励用户采用 Python 作为自己喜欢的工具。有一个 ctypes 的概念,意在包装现有的 C/C++共享库,以便在 Python 程序中使用。* 虽然从来没有比现在更好的了::基于这一理念, Python 增强提案 ( PEP ) 对语法、语义和内置组件的所有更改进行了一段时间的临时暂停(暂停),以促进替代发展的追赶。* 如果实现很难解释,那是个坏主意如果实现很容易解释,那可能是个好主意:在 Python 中,对语法、新的库模块和 API 的所有更改都将通过高度严格的审查和批准过程来处理。**

**## 为什么用 Python 进行科学计算?

坦率地说,如果我们单独谈论 Python 语言,那么我们需要考虑一些选项。幸运的是,我们支持 NumPy、SciPy、IPython 和 matplotlib,这使得 Python 成为最佳选择。我们将在后续章节中讨论这些库。以下是 Python 及其相关库的综合特性,这些特性使 Python 比其他替代语言(如 MATLAB、R 和其他编程语言)更受欢迎。大多数情况下,没有一个单一的替代方案具备所有这些特征。

简洁可读的代码

与科学计算的替代代码相比,Python 代码通常更紧凑,内在可读性更强。正如 Python 指导原则中所讨论的,这是 Python 设计哲学的影响。

整体语言设计

总的来说,Python 语言的设计对于科学计算来说非常方便,因为 Python 支持多种编程风格,包括过程式、面向对象、函数式和逻辑式编程。用户有广泛的选择,他们可以选择最适合他们的问题。大多数可用的替代方案都不是这样。

免费开放源码

Python 和相关的工具是免费提供使用的,它们是作为开源工具发布的。这带来了一个额外的优势,他们的内部源代码的可用性。另一方面,大多数竞争工具都是昂贵的专有产品,其内部算法和概念不会向用户发布。

语言互操作性

Python 支持与大多数现有技术的互操作性。我们可以调用或使用用不同语言编写的函数、代码、包和对象,如 MATLAB、C、C++、R、Fortran 等。有许多选项可以支持这种互操作性,例如 Ctypes、Cython 和 SWIG。

便携可扩展

Python 支持大多数平台。所以,它是一种可移植的编程语言,它为一个平台编写的程序将在任何其他平台上产生几乎相同的输出,如果 Python 工具包可用于该平台的话。Python 背后的设计原则使它成为一种高度可扩展的语言,这就是为什么我们有大量高级库可用于许多不同的任务。

分层模块系统

Python 支持模块化系统在一个命名空间中以函数和类的形式组织程序。命名空间系统非常简单,以便轻松学习和记忆概念。这也支持增强的代码可重用性和维护。

图形用户界面包

Python 语言在图形包和工具集中提供了广泛的选择。这些工具包和包支持图形设计、用户界面设计、数据可视化和各种其他活动。

数据结构

Python 支持数据结构的详尽范围,这是设计和实现执行科学计算的程序中最重要的组件。支持字典是 Python 语言数据结构功能中最突出的特性。

Python 的测试框架

Python 的单元测试框架名为 PyUnit,支持完整的单元测试功能,以便与mypython程序集成。它支持各种重要的单元测试概念,包括测试夹具、测试用例、测试套件和测试运行器。

可用库

由于电池- 包含 Python 的哲学,它在其捆绑库中支持广泛的标准包。由于它是一种可扩展的语言,许多经过良好测试的定制专用库可供广大用户使用。让我们简单地讨论几个用于科学计算的库。

NumPy/SciPy 是一个包,支持任何科学计算所需的大多数数学和统计操作。SymPy 库为基本符号算术、代数、微积分、离散数学、量子物理等的符号计算提供功能。PyTables 是一个包,用于以分层数据库的形式高效地处理具有大量数据的数据集。IPython 促进了 Python 的交互计算特性。它是一个命令外壳,支持多种编程语言的交互式计算。matplotlib 是一个支持 Python/NumPy 绘图功能的库。它支持绘制各种类型的图形,如线图、直方图、散点图和三维图。SQLAlchemy 是一个用于 Python 编程的对象关系映射库。通过使用这个库,我们可以非常方便地使用数据库功能进行科学计算。最后,是时候介绍一个在我们刚刚讨论的包和许多其他开源库和工具包的基础上编写的工具包了。这个工具包叫做 SageMath。它是一个开源的数学软件。

蟒蛇的缺点

在讨论了很多关于替代方案的 Python 的优点之后,如果我们开始寻找一些缺点,我们会注意到一些重要的东西:与替代方案相比,Python 的集成开发环境 ( IDE ) 并不是最强大的 IDE。由于 Python 工具包是以离散包和工具包的形式排列的,所以其中一些工具包具有命令行界面。因此,在这个特性的比较中,Python 在特定平台上落后于一些替代品,例如,Windows 上的 MATLAB。然而,这并不意味着 Python 没有那么方便;它同样具有可比性,并且支持易用性。

总结

在这一章中,我们讨论了科学计算的基本概念及其定义。然后我们讲述了科学计算过程的流程。接下来,我们简要讨论了一些科学和工程领域的例子。举例之后,我们解释了解决复杂问题的有效策略。之后,我们讨论了近似值、误差和相关术语的概念。

我们还讨论了 Python 语言的背景及其指导原则。最后,我们讨论了为什么 Python 是最适合科学计算的选择。

在下一章中,我们将讨论科学计算中涉及的各种数学/数值分析概念。我们还将介绍用于科学计算的各种 Python 包、工具包和 API。**

二、对科学工作流和科学计算秘籍要素的更深入研究

科学工作流 是用来描述解决科学计算问题所需的一系列结构化活动和计算步骤的术语。科学计算中涉及的计算非常密集,非常复杂,并且具有复杂的依赖性。在本章的剩余部分,我们将继续使用科学计算问题词来表示科学工作流。让我们讨论大多数科学计算问题所需的各种数学和计算组件。

在本章中,我们将涵盖以下主题:

  • 科学计算的数学部分
  • Python 的科学计算库
  • NumPy 简介
  • SciPy 简介
  • 利用熊猫进行数据分析
  • 交互 Python ( IPython )进行交互编程
  • 使用 SymPy 的符号计算
  • 利用 Matplotlib 实现数据可视化

科学计算的数学成分

首先,我们将简要讨论科学计算问题中可能出现的各种数学成分。我们还将寻找解决问题的可能方法。然而,在这次讨论中,我们将不研究任何方法的细节。在后面的部分,我们将讨论与这些概念相关的 Python APIs。

线性方程组

在科学计算和应用数学的大多数应用中,最常见的数学成分是线性代数方程组。通常,该系统可能由于线性方程的非线性方程或代数方程的微分方程的近似而出现。

线性方程组是包含一组变量的联立线性方程组的集合,例如:

2 x1  +  1 x2  + 1 x3  =  1
1 x1   -  2 x2  - 1 x3  =  2
1 x1  +  1 x2  + 2 x3  =  2

这是一个包含三个未知变量的线性方程组:x1x2x3。这个系统的一个解决方案是给这些未知变量赋值,使得这些值同时满足所有三个方程。这些方程的解如下所示:

x1  =  (1/2)
x2  =  (-3/2)
x3  =  (3/2)

这个解满足所有三个方程。这就是为什么我们称这些线性方程为线性方程组——这些方程被认为是一个系统,而不是单个的方程。通常,迭代方法是需要重复步骤来计算解的方法。在编程中,这种重复使用任何可用的循环来执行。另一方面,非迭代方法使用计算公式来寻找解。求解线性方程组的方法有很多种。有迭代和非迭代方法。例如,高斯 LU 分解法和消元法是非迭代方法的两个例子。雅可比迭代法和高斯-塞德尔迭代法是两种常用的迭代法。

非线性方程组

方程的非线性系统是一组联立方程,其中未知变量表现为次数大于 1 的多项式。该系统可以是一维的或多维的。一般来说,线性方程的形式如下。对于给定的函数f,我们需要找到这个条件成立的值x:

*f(x) = 0*

x的这个值叫做方程的 或零。

求解线性方程时有两种不同的情况,如下所示。在第一种情况下,有一个单变量的非线性方程:

*f: RàR (scalar)*

这个方程的解是一个标量x,对于这个标量f(x) = 0。第二种情况是具有未知变量的n非线性方程组:

*f: Rn à Rn (vector)*

这类方程的解是一个向量x,对于所有f(x) = 0,函数 f 的所有分量同时为零。

例如,一维非线性方程如下:

*3x + sin(x) -ex = 0*

其近似解到两位小数为0.36。这里给出了一个二维非线性方程组的例子:

*3-x2=y*
*x+1=y*

前一系统的解向量为[1, 2][-2, -1]

有许多方法可以求解非线性方程和非线性方程组。对于一维方程,方法如下:

  • 等分法
  • 牛顿法
  • 割线法
  • 插值法
  • 逆插值法
  • 逆二次插值
  • 线性分数插值

类似地,对于一个非线性方程组,我们也有许多方法,如下所示:

  • 牛顿法
  • 割线更新法
  • 阻尼牛顿法
  • 布赖登方法

由于这些方法是迭代方法,它们的收敛速度是一个需要观察的重要性质。所谓收敛,我们指的是这些方法从近似解开始,并朝着获得精确解的方向前进。向解收敛的速度称为收敛速度。更快的收敛方法更有利于获得精确的解,因为它将花费更少的时间。对于一些较快的方法,如牛顿法,选择初始近似是重要的一步。如果某些方法的初始近似与解不够接近,则总有可能无法收敛到解。有一些混合方法作为性能和保证解决方案之间的折衷;阻尼牛顿法就是这种方法的一个例子。 SciPy 包实现了许多求解非线性方程组的方法。您可以参考http://docs . scipy . org/doc/scipy-0 . 14 . 0/reference/generated/scipy . optimize . Newton . html获取更多关于牛顿-拉夫森方法及其实现的信息。

优化

优化是试图获得最佳可能解的过程。通常,它将是所有解中具有最大值或最小值的解。例如,如果我们需要知道组织正在进行的任何项目的成本,那么给出最小成本的选项将是优化选项。同样,如果比较的是各种销售策略,那么产生最大利润的策略将是优化的选择。SciPy 有一个优化技术包。您可以参考http://docs.scipy.org/doc/scipy/reference/optimize.html了解更多详情和这些方法的实施。优化在各种科学和工程领域都有应用。其中一些如下:

  • 力学和工程学
  • 经济学
  • 运筹学
  • 控制工程
  • 石油钻采工程
  • 分子建模

插值

在科学和工程领域,用户有许多从采样或一些实验中获得的数据点。这些数据点代表自变量特定值的函数值。现在,通常需要为范围内的剩余点估计这个函数的值。这个估计过程叫做插值。这可以通过曲线拟合或回归分析来实现。

例如,考虑独立变量x的以下值和函数f的相应值:

x  4  5   6  7  8  9  10
f(x)  48   75  108  147  192  243  300

使用插值方法,我们可以为变量的其他值估计这个函数的值,如x=7.5,即f(7.5)f(5.25)。虽然前面例子中给出的函数非常简单(f(x) = 3x2),但是它可以是现实例子中的任何函数。例如,该函数可以是电子商务组织的互联网数据中心的服务器机房的温度读数。这些温度读数可以在不同的时间点获取。温度读数的时间可以是两次读数之间的固定时间间隔,也可以是完全随机的。在本例中,函数是独立可变时间离散值的服务器机房温度。我们需要估算或内插一天剩余时间的温度。

另一个的例子可以如下:该函数是被研究用户基于年龄在使用脸书或 WhatsApp 上投入/浪费的平均每天小时数。根据这些数据,我们可以估计除了数据点中的年龄之外的某个年龄的用户使用脸书或 WhatsApp 的小时数。

外推

另一个密切相关的问题是外推。顾名思义,它是内插在自变量取值范围之外的延伸。例如,如果我们得到了 12 岁至 65 岁用户年龄值的脸书/WhatsApp 使用小时数的值,那么估计 12 岁以下和 65 岁以上用户花费小时数的问题就属于外推范围。这是因为它超出了自变量给定数据点的范围。

我们有许多方法可以用于插值和外推。以下是一些插值方法的名称:

  • 分段常数插值
  • 线性内插法
  • 多项式插值
  • 样条插值
  • 高斯过程插值

以下是一些外推方法:

  • 线性外推
  • 多项式外推
  • 圆锥外推
  • 法国曲线外推

数值积分

数值积分是使用任何数值技术逼近积分值的过程。积分的数值计算也称为求积。我们需要近似数值积分,因为有些函数不能解析积分。即使有公式存在,它也可能不是计算积分最有效的方法。在某些情况下,我们应该对一个未知函数进行积分,而这个未知函数只有一些样本是已知的。利用数值积分,我们逼近定积分的值。这也是基于通过指定的一组点的多项式拟合,然后积分逼近函数。在 Python 中,SciPy 包有一个用于集成的模块。集成模块及其实现详见http://docs.scipy.org/doc/scipy/reference/integrate.html。有许多方法可以求解数值积分,如下所示:

  • 辛普森公式
  • 梯形法则
  • 精细梯形法则
  • 高斯求积法则
  • 牛顿-柯特斯求积法则
  • 高斯-勒让德积分

数值微分

数值微分是利用函数的已知值来估计函数的导数的过程。它在几种情况下非常有用。一般来说,在某些情况下,我们不太清楚底层函数是否存在,我们只有一个离散的数据集。在这种情况下,用户有兴趣研究与衍生品相关的数据变化。有时,为了性能和简单起见,我们更喜欢近似导数,而不是计算其精确值,因为精确公式是可用的,但求解起来非常复杂。微分经常被用来解决优化问题。机器学习技术大部分时间也依赖于数值微分。

数值微分的方法如下:

  • 差分逼近
  • 微分求积
  • 有限差分系数
  • 插值微分

微分方程

一个微分方程是一个数学方程,可以将一个函数与其导数联系起来。函数代表一个物理量,导数对应这个量的变化率,方程是两者的关系。例如,自由下落物体在重力作用下的运动通常用一组微分方程来表示。微分方程在很多领域都有应用,包括纯数学和应用数学、物理、工程和其他学科。这些科目主要涉及各种类型的微分方程。

微分方程主要用于模拟每一个物理、技术和生物过程。在许多情况下,微分方程可能无法直接求解。因此,应使用数值方法近似求解。大多数物理基本定律(例如牛顿第二定律和爱因斯坦场方程)和化学基本定律,如速率定律或速率方程,都被表述为微分方程。微分方程已经被用来在生物学(例如,生物种群增长)和经济学(例如,简单的指数增长模型)中模拟复杂系统的行为。

微分方程可以分为两种类型:常微分方程 ( ODE ) 和 偏微分方程 ( PDE )。ODE 是包含一个独立变量的函数及其导数的方程。另一方面,偏微分方程包含多个独立变量的函数及其偏导数。多变量函数的偏导数是这个函数相对于其中一个变量的导数。这些方法在 SciPy 中的概念细节和实现可以参考http://docs . SciPy . org/doc/SciPy-0 . 13 . 0/reference/generated/SciPy . integrate . ode . html

求解微分方程的各种方法如下:

  • 欧拉方法
  • 泰勒级数法
  • 龙格-库塔法
  • 龙格-库塔四阶公式
  • 预测校正法

以下是用于求解偏微分方程的一些方法:

  • 有限元法
  • 差分法
  • 有限体积法

初值问题

初值问题是一个普通的微分方程,以及解域中某一点的未知函数值,例如, dy/dx = f(x,y) ,其中, y=y1 代表 x=x1

边值问题

边值问题也是一个带有一些约束的微分方程,它的解是满足这些给定约束的微分方程的解。这些约束称为边界条件。

随机数发生器

在计算中,随机数生成器是一种算法或过程,它生成一个不遵循任何模式的数字序列,这就是为什么它们被称为随机数。几乎不可能预测将要生成的数字。使用随机数的应用的数量日益增加,因此导致了许多随机数生成方法的发展。这个概念已经被使用了很长时间,例如使用骰子,硬币翻转,使用扑克牌,以及更多的方法。然而,这些方法对于随机数的值是有限的。

随机数生成的计算方法很快在各种各样的应用中变得流行起来,例如统计抽样、赌博、随机设计生成设计、各种科学和工程概念的计算机模拟,以及许多需要不可预测结果的其他领域,例如密码学。

随机数发生器主要有两大类,即真随机数发生器和伪随机数发生器。真正的随机数生成器使用一些物理现象来生成随机数,例如,硬盘实际的读取或写入时间,而伪随机数生成器使用计算算法来生成随机数。还有第三类随机数发生器。它们基于统计分布,如毒分布、指数分布、正态分布、高斯分布等。

各种伪随机数发生器如下:

  • 布卢姆舒卜
  • 威奇曼山
  • 互补进位乘法
  • 逆同余发生器
  • 密码
  • 滞后斐波那契发生器
  • 线性同余发生器
  • 线性反馈移位寄存器
  • 最大周期倒数
  • 梅森龙卷风
  • 进位乘法
  • Naor-Reingold 伪随机函数
  • 帕克-米勒随机数发生器
  • 均匀分布长周期线性

Python 科学计算

Python 对科学计算的支持是由许多用于科学计算所需的不同功能的包和 API 组成的。对于每个类别,我们有多个选项和一个最受欢迎的选择。以下是 Python 科学计算选项的示例:

  • 图表绘制:目前最流行的二维图表绘制包是 matplotlib。还有其他几个绘图包,如 Visvis、Plotly、HippoDraw、Chaco、MayaVI、Biggles、Pychart 和 Bokeh。有一些包是在 matplotlib 的基础上构建的,以提供增强的功能,例如 Seaborn 和 Prettyplotlib。
  • 优化:SciPy 栈有一个优化包。优化功能的其他选择是 OpenOpt 和 CVXOpt。
  • 高级数据分析 : Python 支持与 R 统计包集成,使用 RPy 或 RSPlus-Python 接口进行高级数据分析。有一个基于 Python 的库,用于执行名为 pandas 的数据分析活动。
  • 数据库 : PyTables 是一个管理分层数据库的包。该软件包是在 HDF5 的基础上开发的,旨在高效处理大型数据集。
  • 交互命令外壳 : IPython 是一个支持交互编程的 Python 包。
  • 符号计算 : Python 有 SymPy、PyDSTool 等支持符号计算的包。在本章的后面,我们将讨论符号计算的概念。
  • 专用扩展 : SciKits 为 SciPy、NumPy 和 Python 提供了专用的插件。以下是 Scikits 包的精选列表:
    • scikit-aero:Python 中的航空工程计算
    • scikit-bio:生物信息学的数据结构、算法和教育资源
    • scikit-commpy:用 Python 实现数字通信算法
    • scikit-image:SciPy 的图像处理例程
    • scikit-learn:一套用于机器学习和数据挖掘的 Python 模块
    • scikit-monaco:用于蒙特卡罗集成的 Python 模块
    • scikit-spectra:以熊猫为原型的蟒蛇光谱学
    • scikit-tensor:用于多线性代数和张量因子分解的 Python 模块
    • scikit-tracker:细胞生物学的目标检测和跟踪
    • scikit-xray:X 射线科学的数据分析工具
    • bvp_solver:求解两点边值问题的 Python 包
    • datasmooth:sci kits 数据平滑包
    • optimization:数值优化的 Python 模块
    • statsmodels:用于 SciPy 的统计计算和模型
  • 第三方或非 scikit 包/应用/工具:有很多项目已经为特定的科学领域开发了包/工具,例如天文学、天体物理学、生物信息学、地球科学等等。以下是 Python 中针对特定科学领域的一些选定的第三方包/工具:
    • Astropy:一个社区驱动的 Python 包,用于支持天文学和天体物理学计算
    • Astroquery:这个包是用来访问在线天文数据的工具集合
    • BioPython:这是一个用 Python 进行生物计算的工具包集合
    • HTSeq:这个包支持 Python 中高通量测序数据的分析
    • Pygr:这是 Python 中用于序列和比较基因组分析的工具包
    • TAMO:这是一个 Python 应用,用于使用 DNA 序列基序分析转录调控
    • EarthPy:这是 IPython 笔记本的集合,有地球科学领域的例子
    • Pyearthquake:用于地震和 MODIS 分析的 Python 包
    • MSNoise:这是一个使用环境地震噪声监测地震速度变化的 Python 包
    • AtmosphericChemistry:该工具支持大气化学力学的探索、构建和转换
    • Chemlab:这个包是一个完整的库,用来执行与化学相关的计算

NumPy 简介

Python 编程被扩展为支持大型数组和矩阵,以及操作这些数组的数学函数库。这些数组是多维的,这个 Python 扩展叫做 NumPy。在 NumPy 的基本实现成功后,它用许多 APIs 工具进行了扩展,包括 matplotlib、pandas、SciPy 和 SymPy。让我们来看看 NumPy 的每个子工具/子 API 的简要功能。

科学图书馆

SciPy 是为科学家和工程师设计和开发的 Python 库,用于执行与科学计算相关的操作。它支持不同操作的功能,如优化、线性代数、微积分、插值、图像处理、快速傅立叶变换、信号处理和特殊功能。它解决常微分方程,并执行科学和工程所需的其他任务。它建立在 NumPy 数组对象之上,是 NumPy 堆栈中非常重要的组件。这就是为什么 NumPy 栈和 SciPy 栈有时被用作同一个引用。

SciPy 子包

SciPy 的各种子包包括以下内容:

  • constants:这些是物理常数和换算系数
  • cluster:层次聚类、矢量量化、K 均值
  • fftpack:离散傅里叶变换算法
  • integrate:数值积分例程
  • interpolate:插值工具
  • io:数据输入输出
  • lib:外部库的 Python 包装器
  • linalg:线性代数例程
  • misc:杂项实用程序(例如,图像读写)
  • ndimage:多维图像处理的各种功能
  • optimize:优化算法,包括线性规划
  • signal:信号处理工具
  • sparse:稀疏矩阵及相关算法
  • spatial:KD-树、最近邻和距离函数
  • special:特殊功能
  • stats:统计功能
  • weave:将 C/C++代码写成 Python 多行字符串的工具

利用大熊猫进行数据分析

熊猫库是一个开源库,旨在用 Python 提供高性能的数据操作和分析功能。使用 pandas,用户可以在 Python 中处理完整的数据分析工作流。此外,使用 pandas、IPython 工具包和其他库,用于执行数据分析的 Python 环境在性能和生产率方面变得非常好。熊猫图书馆只有一个缺点;它只支持线性回归和面板回归。但是对于其他功能,我们可以使用statsmodelsscikit-learn。pandas 库支持数据集的高效合并和连接。它有一系列工具,用于在不同类型的数据源之间读写数据,包括内存、CSV、文本文件、微软 Excel、SQL 数据库和 HDF5 格式。

使用 IPython 进行交互编程的简单想法

Python 在 IPython 的帮助下支持多种编程语言的交互计算。IPython 是一个专门为 Python 编程设计的命令外壳,现在它支持多种语言。它提供了出色的自省功能、新的 shell 语法、命令行文本完成和命令历史。内省是对命令行环境进行编程以检查各种特性(属性、方法和其他细节,如超类)的能力。IPython 具有许多特性,包括:

  • 基于命令行和基于 QT 的交互式外壳
  • 基于浏览器的笔记本,支持编码、数学表达式、内嵌图形和图形
  • 它还能够支持交互式数据可视化和其他图形用户界面
  • 支持高性能并行计算

IPython 并行计算

IPython 对并行和分布式计算有很好的支持,便于大规模计算。它具有开发、执行、调试和监控并行或分布式应用的能力。IPython 支持大多数并行风格,包括以下风格,以及由此产生的任何混合方法:

  • 单程序多数据 ( SPMD )并行度
  • 多程序多数据 ( MIMD )并行度
  • 消息传递界面 ( MPI )
  • 任务和数据并行性
  • 自定义用户定义的方法

IPython 笔记本电脑

IPython 笔记本是一个基于网络的交互式计算环境。该环境用于创建 IPython 笔记本。它接受单用户输入或单个表达式,对它们求值,并将结果返回给用户。该功能称为读取、评估、打印和循环 ( REPL )。对于 REPL,用户可以使用以下 Python 库:

  • 伊普提洪伊普提翁伊普提翁伊普提翁伊普提翁伊普提翁伊普提翁伊普提翁伊普提翁伊普提翁伊普提翁伊普提翁
  • MQ (ZMQ)
  • 龙卷风(网络服务器)
  • jQuery
  • 引导(前端框架)
  • MathJax,你好吗

笔记本程序在计算机上创建一个本地网络服务器,以便从网络浏览器访问它。IPython 笔记本是一个 JSON 文档,用于使用编码、文本、数学运算、图形和绘图来执行不同类型的计算。这些笔记本可以使用基于网络和基于命令的选项导出为各种格式。支持的格式有 HTML、LaTeX、PDF、Python 等等。

Python 笔记本的开发过程如下图所示。它从左边开始,准备数据,然后开发程序及其版本。程序开发完成后,可以导出各种格式。

IPython Notebook

IPython 的其他一些显著特点如下:

  • 与 GUI 库和工具包的非阻塞交互:IPython 支持与许多基于 Python 的 GUI 工具包/库的非阻塞交互,包括 Tkinter、PyGTK、PyQt 和 wxPython
  • 集群管理:IPython 支持使用 MPI/异步状态回调消息计算集群管理工具
  • 类似 Unix 的环境:IPython 的默认行为几乎类似于支持环境定制的 Unix 外壳的行为

型式

下载示例代码

您可以从您在http://www.packtpub.com的账户下载您购买的所有 Packt Publishing 书籍的示例代码文件。如果您在其他地方购买了这本书,您可以访问http://www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给您。

IPython 用户界面截图如下(来源为http://ipython.org/notebook.html):

IPython Notebook

IPython 笔记本界面的用户界面

以下是 IPython 命令外壳的各种功能特性:

  • 选项卡完成:用户无需键入完整的命令。只输入前几个字符后,按下标签即可完成剩余的命令。
  • 探索你的物体:物体的各种属性可以使用内省工具来确定。
  • 魔法功能:用户可以调用的魔法功能有很多。
  • 运行和编辑:用户可以从命令外壳执行和编辑 Python 脚本。
  • 调试:命令外壳中还捆绑了强大的调试工具。
  • 历史记录:命令外壳存储命令的历史记录及其结果。
  • 系统外壳命令:用户也可以使用系统外壳提供的命令。
  • 定义自己的系统别名:用户可以根据自己的喜好定义命令的别名。
  • 配置:可以使用配置文件自定义 IPython 环境。
  • 启动文件:用户可以自定义环境,在 IPython 会话开始时运行一些命令或代码。

使用 SymPy 的符号计算

符号计算操纵数学对象和表达式。这些数学对象和表达式是按原样表示的,它们没有被评估/近似。带有未赋值变量的表达式/对象保留其符号形式。

让我们在下图中看看计算机化正规计算和计算机化符号计算的区别。这两种情况我们都有两个例子。例 A1例 A2 是正规计算的例子,例 B1例 B2 是符号计算的例子。例 A1****例 A2 输出明显。我们来看看示例 B1示例 B2 的输出。示例 B1 的输出与sqrt(3)相同。不执行评估;只是原始符号。这是因为在符号计算中,如果sqrt函数的参数不是一个完美的正方形,那么它将保持原样。另一方面,在示例 B2 中,输出稍微简单一些。原因是对于这个例子,有可能简化答案;sqrt(27)可以写成sqrt (9 X 3)或者3(sqrt(3),所以简化为3sqrt(3)

Symbolic computing using SymPy

正常计算和符号计算的比较

症状的特征

因为它是一个符号计算库,所以 SymPy 能够象征性地执行所有类型的计算。它可以简化表达式(就像我们看到的sqrt(8));计算微分、积分和极限;并求解方程、矩阵运算和各种其他数学函数。所有这些功能都象征性地执行。

让我们讨论一下 SymPy 的各种特性。SymPy 库由核心功能和许多可选模块组成。以下是 SymPy 支持的功能:

  • 核心功能,如基本运算和简化,以及模式匹配功能,如三角函数、双曲函数、指数函数、对数函数等
  • 它支持多项式运算,例如,基本算术、因式分解和各种其他运算
  • 微积分功能,例如,极限、微分、积分等等
  • 求解各种类型的方程,例如多项式、方程组和微分方程
  • 离散数学
  • 矩阵表示和运算的功能
  • 几何函数
  • 借助外部 pyglet 模块进行绘图
  • 对物理的支持
  • 执行统计操作,如概率和分布
  • 各种打印功能
  • 编程语言和 LaTeX 的代码生成

为什么是症状?

SymPy 是一个开源库,并在自由的 BSD 许可下获得许可。您可以修改源代码。其他替代品则不是这样,例如 Maple 和 Mathematica。SymPy 的另一个优点是它是用 Python 设计、开发和执行的。对于 Python 开发人员来说,这带来了额外的优势。与替代工具相比,该库具有很高的可扩展性。

标绘库

Python 的图表绘制库被命名为 matplotlib。它提供了一个面向对象的 API,用于在使用各种 Python 图形用户界面工具包开发的应用中添加图表。SciPy/NumPy 使用 matplotlib 绘制数组的 2D 图。matplotlib 背后的设计理念是简化绘图功能。用户可以使用很少的函数调用或仅使用一个函数调用轻松创建各种类型的图。有一些专门的工具包/API 扩展了 matplotlib 的功能。其中一些工具与 matplotlib 捆绑在一起,另一些则可以单独下载。这里列出了其中的一些:

  • 底图是一个地图绘制工具包
  • Cartopy 包用于轻松制作用于数据分析和可视化的绘图地图
  • Excel 工具支持与微软 Excel 交换数据
  • Qt 和 GTK+的接口
  • mplot3d 可用于绘制三维图

下表给出了可以使用 matplotlib 绘制的各种类型的图表。这些图表截图来自http://matplotlib.org/users/screenshots.html的 matplotlib 网页:

|

不同类型的图形:

|   |
| --- | --- |
| 简单的情节The plotting library | 多轴子图演示The plotting library |
| 直方图The plotting library | 路径演示The plotting library |
| mplot3d: 3D 图形The plotting library | 流图:用于绘制矢量场的流线The plotting library |
| 条形图图表The plotting library | 饼图图表The plotting library |
| 极坐标图The plotting library | 记录图The plotting library |
| 财务图表:用于通过组合 matplotlib 提供的各种绘图功能、布局命令和标记工具来绘制复杂的财务图。The plotting library |

总结

在这一章中,我们讨论了数学和数值分析的许多概念,包括线性和非线性方程组、最优化、插值、外推、数值微分和积分、微分方程和随机数发生器。

在本章的第二部分,我们简要讨论了用 Python 语言执行科学计算的各种包/工具包/API。我们还讨论了 NumPy、SciPy、IPython、SymPy、matplotlib 和 pandas 的功能和特性。

在下一章中,我们将讨论如何为科学计算准备和管理数据。

三、高效构建和管理科学数据

这一章是关于科学计算的数据。它介绍了这些数据的概念,然后介绍了用于管理这些数据的各种工具包以及要对其执行的操作。之后,讨论了各种数据格式和基于随机数的技术来生成合成数值数据。

在本章中,我们将涵盖以下主题:

  • 数据、信息和知识的基础
  • 各种数据存储软件和工具的概念
  • 可以对数据执行的操作
  • 科学数据标准格式的细节
  • 关于现成数据集的讨论
  • 使用随机数的合成数据生成
  • 大规模数据集的概念

数据的基本概念

关于一个实体的事实和数字的原始的和无组织的形式被称为 数据。任何以无组织/原始形式(如一系列数字或字母)表示现实世界中的概念、现象、对象或实体的实际数量或价值都可以被视为数据。数据没有极限,到处都有。

数据可以转化为信息,并有助于实现组织的目标。当添加到数据中时,某些属性使其成为信息。准确及时的数据如果是为了特定的目的而组织的,并且是在特定的背景下准备和呈现的,则被称为信息。这给这些数据赋予了意义和相关性。

通过使用领域经验增加洞察力,数据和信息可以进一步转化为知识。这些知识需要大量的经验来处理与特定应用相关的数据,如商品价格或天气预报。

现在,让我们考虑一个数据、信息和知识的科学例子。显然,79°F 是温度读数,是数据。如果我们在阅读的同时添加一些细节——例如,这是 2015 年 3 月 3 日下午 5:30 印度孟买印度之门的温度——那么这就是信息。根据几年来这一周每小时的温度读数,预测下一周的温度就是知识。同样,根据印度北部最近两天强降雪的一些信息,得出印度中部气温也会有一定程度下降的结论也是知识。下图描述了数据、信息和知识之间的关系。这个过程从从实验中收集的数据开始,然后从这些数据中提取信息。最后,在详细分析这些信息后,我们从中解读知识。

The basic concepts of data

数据、信息和知识的金字塔

数据存储软件和工具包

一般来说,涉及计算机科学的概念随着时间的推移变化非常快,存储数据的软件和工具也在快速演变。因此,目前市场上有许多软件和工具包可用于存储数据。数据有两大类存储软件和工具包。同样,在每个类别中,都有多个子类别。下图描述了用于管理和存储数据的各种数据存储软件/工具包的分类:

Data storage software and toolkits

数据存储和管理软件/工具包分类

文件

第一类包括以不同格式的平面文件存储数据的软件或工具。平面文件的子类别是结构化和非结构化文件。“结构化文件”是指具有用于存储数据的预定义/固定结构的文件。而在非结构化文件中,没有预定义的结构来存储数据。通常,这两种类型的文件存储文本数据,而对于某些特定的科学应用,它们可能包括图像、音频、视频和其他非文本数据。

结构化文件

结构化文件的一个例子可以是带有 逗号分隔值 ( CSV )的文本文件。在此类文件中,各种数据字段由逗号或分隔符分隔。该分隔符可以是任何字符或符号。优选地,该符号必须是不出现在要存储的数据中的符号。例如,如果我们在数据中存储货币值,那么逗号就不是合适的分隔符。

考虑 CSV 文件的以下记录:H.K. Mehta, 08-Oct-1975, Higher Education department, 50,432

前面的记录有姓名、出生日期、部门名称和月薪。现在,对于 CSV 文件,不建议将空格、点(.)、逗号(,)和破折号(-)作为字段的分隔符。如果我们选择其中任何一个——空格点、逗号或破折号——作为分隔符,那么逗号会将金额视为两个值,同样,破折号(-)会将出生日期视为三个不同的值。点(.)将名称视为三个不同的值,如果空格是分隔符,部门名称将被分为三个值。对于这里提到的记录,分隔符可以是其他符号之一,如问号(?)或管道(|)。通常,在商业价值中,管道(|)是最常用的分隔符。

固定宽度文件是结构化文件的另一个示例。在这样的文件中,每个字段的总大小是预先定义的,并在整个文件中保持不变。如果特定记录中某个字段的大小小于或大于该字段的预定义固定大小,则对于该特定记录,要么用空格填充该字段(如果该字段较小),要么对其进行修剪以减小其大小。

非结构化文件

非结构化文件的例子有网络服务器日志、书籍、日志和电子邮件。这包括文本和非文本数据。文本数据包括可由任何字符编码方案表示的数据,如美国信息交换标准代码 ( ASCII ) 或 Unicode。还有另一类基于文件的数据存储,叫做半结构化。它不具有与关系数据库和其他数据库的结构一致的形式结构。半结构化方法使用标签或其他标记来分隔字段,为值添加适当的含义,并创建记录和字段的结构。这种数据的例子有 XML 和 JSON。这些数据类型的优势在于它们是独立于语言和平台的格式。因此,它们的操作不会随着语言或平台而改变。

数据库

第二类产品将数据存储在数据库中。除了文件,还有各种各样的数据库来存储计算数据。这些数据库可以分为两大类:基于模式的数据库和没有模式的数据库。基于模式的数据库是传统的数据库,它迫使用户在存储数据之前创建结构。另一方面,无模式数据库是大规模数据库领域的最新进展,旨在满足大规模应用的需求。基于模式的数据库的一些例子有 MySQL、Oracle、MS SQL Server、Postgres 等等。MongoDB、HBSE 和 Cassandra 就是无模式数据库的例子。

对数据的可能操作

除了存储数据,还需要执行许多操作来有效地管理和使用数据:

  • 数据农业:使用高性能计算在巨大数据集上多次运行一组模拟的过程称为数据农业。数据农业的输出是来自数据的可见特征和特性的广阔视图;它支持决策过程。它是多个学科的集成,包括高性能计算、数据分析和可视化以及大规模数据库。
  • 数据管理:数据管理是一个广义的术语由许多要对数据执行的操作组成,包括以下内容:
    • 数据治理:这是主控制。它确保输入的数据具有建模过程中定义的所需标准。该数据输入可以手动或通过自动过程来执行。
    • 数据架构、分析和设计:数据架构涉及应用各种模型、流程、算法、规则或标准,这些模型、流程、算法、规则或标准涉及必须收集什么数据、如何构建数据的存储以及如何集成数据。数据的分析和设计包括清理和转换数据的过程,以便对组织有益。
    • 数据库管理:数据的管理是一项复杂的任务,涉及多个相关活动,例如数据库的开发和设计、数据库监控、整体系统监控、提高数据库性能、数据库容量和扩展规划、安全规划和实施以及维护。
    • 数据安全管理:本次包括与数据安全相关的管理活动,包括访问权限管理、数据隐私管理以及其他与数据安全相关的方面(如数据清理/擦除、加密、屏蔽、备份)。
    • 数据质量管理:这是与提高数据质量相关的任务。它涉及许多操作,包括以下操作:
      • 通过检测和纠正数据集的损坏或不准确记录(称为脏数据)来清理数据。
      • 数据完整性是指在不同时期保证数据的准确性和一致性,并对数据进行处理的过程。
      • 数据丰富化是对数据进行提炼或增强的过程,重点是通过根据数据的领域搜索拼写错误或印刷错误来提高数据的质量。例如,在任何情况下,获得的分数都不能超过最大可能分数。在这种情况下,我们必须纠正那些分数大于最大分数的记录。
      • 数据集成是一个复杂的过程,需要丰富的经验,因为它通过将来自多个来源的数据转换成统一的结构来组合它们,而不影响其意义。
    • 数据仓库管理:数据仓库管理涉及到数据集市的准备、进行数据挖掘、进行与数据移动相关的各种操作的流程,如 抽取、翻译、加载 ( ETL )。
    • 元数据管理:这是对数据库中存储的实际数据进行数据管理的过程。该管理数据称为 元数据。元数据包括存储数据的描述、数据创建和修改的日期和时间、数据的所有者、数据在物理设备上的位置以及其他相关细节。
  • 数据的导入导出:这些对于任何一种应用都是非常重要的操作,无论是商业应用还是科学应用。一般来说,在执行导入和导出操作时必须小心。用户需要考虑为其导出或导入数据的应用的性质。因此,可以选择适当的格式。
  • 科学数据归档:这个是基于科学家应该存储多少数据的应用和组织政策,以及这个数据的可访问性级别管理,长期存储科学数据的过程。

科学数据格式

有多种格式/形式可用于存储科学数据。一般来说,大多数科学计算 APIs 语言/工具包都支持这些格式的导入和导出操作。一些流行的格式如下:

  • Network Common Data Form (NetCDF): This is a self-describing and machine/device/platform-independent data format that supports manipulation (creation, access, and sharing) of large array-based scientific data. It is also bundled with a set of software libraries for creation and manipulation. Generally, this format is used in applications such as weather forecasting, climate change from climatology and meteorology, the oceanography domain, and GIS applications. Most GIS applications support NetCDF as an input/output format, and it is also used for general scientific data exchanges.

    这种格式的主要来源是 大学大气研究公司 ( UCAR )的 Unidata 项目。项目的主页由他们托管。他们的网站上有一句很受欢迎的话,http://www . unidata . ucar . edu/software/netcdf/docs/FAQ . html # whatist:

    “NetCDF(网络通用数据表单)是一组面向数组的数据访问接口,是 C、Fortran、C++、Java 等语言的数据访问库的自由分布集合。NetCDF 库支持表示科学数据的独立于机器的格式。接口、库和格式共同支持科学数据的创建、访问和共享

  • 分层数据格式 ( HDF ):这是一套在不同版本(HDF4 和 HDF5)中演变而来的文件格式。这种数据格式提供了存储和组织大量数值数据的设施。它是在国家超级计算应用中心开发的,现在得到了非营利组织 HDF 集团的支持,该组织确保了 HDF5 格式和相关工具/技术的进一步发展。这是一种非常流行的科学数据格式,HDF 得到了许多工具、语言、技术和平台的支持,包括 Java APIs、MATLAB、Octave、Scilab、Python APIs、R APIs 等等。

  • 灵活图像传输系统 ( FITS ):这是一个开放标准,定义了一种数字文件格式来管理用于科学和其他应用的图像文件。这种格式主要用于天文应用。它有几个选项用于描述光度和空间校准信息以及其他元数据。FITS 格式的第一次标准化是在 1981 年。其最新版本于 2008 年实现了标准化。FITS 还可以用于存储非图像数据,例如光谱、数据立方体,甚至数据库。FITS 支持一个重要特性;新版本的格式总是保持向后兼容。另一个重要的特性是文件的元数据存储在标题中人类可读的 ASCII 字符中。这将帮助用户分析文件并理解存储在其中的数据。

  • 带交错数据/带交错文件:这些是二进制格式。这意味着数据存储在非文本文件中,一般这种格式用于遥感和高端 GIS。这些文件有两个子类型,即 逐行交错带(【BIL】)和 逐像素交错带 ( BIP )。

  • 通用数据格式 ( CDF ):这是一种流行的存储标量和多维平台无关数据的格式。因此,它被用来存储科学数据,并作为一种数据交换格式在研究人员和组织中很受欢迎。 空间物理数据设施 ( SPDF )提供了一个 CDF 软件工具包,作为 戈达德太空飞行中心 ( GSFC )的一部分,用于数据操作。CDF 还支持许多编程语言、工具和 API 的非常好的接口,包括 C、C++、C#、FORTRAN、Python、Perl、Java、MATLAB 和 IDL。

各种科学数据格式有如下一些共同特征:

  • 这些格式支持数据的顺序访问和随机访问读取。
  • 它们被设计成高效地存储大量科学数据。
  • 这些格式包含支持自我描述功能的元数据。
  • 默认情况下,这些格式支持对象、网格、图像和数组的排序。
  • 这些格式不可更新。用户可以在末尾追加数据。
  • 它们支持机器便携性。
  • 这些格式大多是标准化的。

这里讨论的各种数据格式可以用来存储任何主题及其子域的数据。然而,有些数据格式是专门为特定主题设计的。以下是特定主题数据格式的列表。我没有对这些特定主题的格式进行任何描述;有特殊兴趣的读者可以参考它们的来源:

  • 天文数据的格式:
    • 适合:适合天文数据和图像格式(.fit.fits)
    • SP3 : GPS 等卫星轨道(.sp3)
  • 存储医学影像数据的格式:
    • DICOM : DICOM 注释医学图像(.dcm.dic)
  • 医疗和生理数据的格式:
    • Affymetrix:Affymetrix 数据格式(.cdf.cel.chp.gin.psi)
    • BDF :生物电磁干扰数据格式(.bdf)
    • EDF :欧洲数据格式(.edf)
  • 化学和生物分子数据的格式:
    • 面向机器的语言(machine-oriented language)
    • 自卫队
    • 笑容
    • 物理数据库
    • GenBank
    • 固定
  • 地震学(地震相关科学和工程)数据格式:
    • NDK:NDK 地震数据格式(.ndk)
  • 天气数据格式:
    • GRIB:GRIB 科学数据格式(.grb.grib)

现成可用的标准数据集

多个政府、协作和研究工作正在持续进行,以开发和维护不同主题和主题内不同领域的标准数据集。这些数据集可供公众下载或离线工作,或者他们也可以对这些数据集进行在线计算。其中一个引人注目的努力被命名为 开放科学数据云 ( OSDC ),它在每个主题上都有几个数据集。这个列表是从各种开放的数据源编译而来的,可供使用。他们也在他们的网络门户网站(https://www.opensciencedatacloud.org/publicdata/上托管数据。OSDC 选定数据集的主题列表如下:

  • 农业:
    • 美国农业部植物数据库
  • 生物学:
    • 1000 个基因组
    • 基因表达综合系统
    • 麻省理工学院癌症基因组学数据
    • 蛋白质数据库
  • 气候/天气:
    • 澳大利亚天气
    • 加拿大气象中心
    • 来自欧洲环境署的气候数据(每月更新)
    • 1929 年以来的全球气候数据
  • 复杂网络:
    • CrossRef 两个 URL
    • DBLP 引文数据集
    • NIST 复杂网络数据收集
    • UFL 稀疏矩阵集合
    • WSU 图形数据库
  • 计算机网络:
    • 2012 年普通爬行 3.5 B 网页
    • 印第安纳大学 10 万用户的 53.5 B 网络点击量
    • 互联网数据集
    • 1B 网页
  • 数据挑战:
    • 机器学习面临的挑战
    • 推动社会公益的大量竞争
    • 信息社会世界首脑会议数据挑战(自 2009 年起)
    • 卡格尔竞赛数据
  • 经济学:
    • 美国经济协会
    • 来自 UMD 的第二个数据
    • 互联网产品代码数据库
  • 能源:
    • AMPds
    • 变蓝的
    • 数据端口
    • 英国-戴尔
  • 财务:
    • CBOE 期货交易所
    • 谷歌金融
    • 谷歌趋势
    • 全国证券交易商协会自动报价系统
  • “地球空间”/地理信息系统:
    • BODC—大约 22,000 vars 的海洋数据
    • 美国马萨诸塞州剑桥,地理信息系统数据在 GitHub 上
    • EOSDIS——美国宇航局的地球观测系统数据
    • 来自亚利桑那州立大学的地理空间数据
  • 医疗保健:
    • EHDP 大型健康数据集
    • 世界人口数据库
    • 美国医疗保险数据库
    • 医疗保险数据文件
  • 图像处理:
    • 2 GB 猫的照片
    • 情感图像分类
    • 人脸识别基准
    • 大量视觉记忆刺激
    • 麻省理工学院太阳数据库
  • 机器学习:
    • 发现月度数据
    • 易贝在线拍卖(2012 年)
    • IMDb 数据库
    • 分类、回归和时间序列的龙骨存储库
    • 百万首歌曲数据集
  • 博物馆:
    • 库珀·休伊特收藏数据库
    • 明尼阿波利斯艺术学院元数据
    • 泰特收藏元数据
    • 盖蒂词汇表
  • 自然语言:
    • 博主语料库
    • ClueWeb09 中非共和国武装部队
    • 谷歌图书(2.2 兆字节)
    • 谷歌网页 5 克(2006 年为 1 TB)
  • 物理学:
    • 欧洲核子研究中心开放数据门户
    • NSSDC(美国航天局)550 艘航天器的数据
  • 公共域:
    • CMU JASA 数据档案
    • 加州大学洛杉矶分校 SOCR 分校数据收集
    • 不明飞行物报告
    • 维基解密 911 呼机拦截
  • 搜索引擎:
    • 来自 UMB 的数据共享学术洪流
    • 存档-从互联网存档
    • DataMarket (Qlik)
    • 统计与研究
  • 社会科学:
    • 由 150 名用户组成的 CMU 安然电子邮件数据集
    • 来自 LAW 的脸书社交网络(自 2007 年起)
    • 2010 年和 2011 年的四方社交网络
    • 来自 UMN/萨尔瓦特的四方(2013 年)
  • 运动:
    • Betfair 历史交换数据
    • 板球比赛(棒球)
    • 1950 年至今的一级方程式赛车
    • 足球/足球资源(数据和应用接口)
  • 时间序列:
    • MU 的时间序列数据库(TSDL)
    • 加州大学河滨分校时间序列数据集
    • 硬盘故障率
  • 交通:
    • 航空公司 1987-2008 年的 OD 数据
    • 自行车共享系统(BSS)集合
    • 湾区自行车共享数据
    • 马萨诸塞州湖滨百万次骑行
    • 海上交通—船舶轨迹、港口呼叫等

数据生成

对于某些应用,如果用户没有可用于计算的数据,那么他们需要在执行计算之前生成该数据。它可以通过三种方式生成:个人收集、仪器收集或(针对某些特定应用)在计算机上合成生成。

有些应用的数据应该是个人收集的;例如,如果应用需要一个人的生物测定数据,可以通过建立数据收集并请求志愿者支持生物测定数据收集来亲自收集数据。这种收集必须亲自进行,因为这些数据不能在计算机上或使用仪器产生。对于这种特定的应用,用户有可能获得政府的支持,以便从政府数据库中获得这种数据,例如在签证处理过程中收集的生物特征细节的数据库,或者全国性的项目,例如美国政府的个人登记数据库,或者在印度的唯一识别项目(ADHAAR)期间收集的数据。

对于一些特定的实验,数据可以使用许多仪器生成,这些仪器提供感兴趣的用户的读数。例如,可以使用如下仪器生成与天气相关的数据:我们可以在不同的地方放置多个温度记录仪,并定期收集它们的读数。使用一些专门的传感器,我们还可以收集与天气或健康科学相关的数据。例如,可以使用专门设计的智能腰带或分发给不同人的手表来收集脉搏率和血液快感相关信息,并且可以从这些设备内的内置全球定位系统收集信息,该系统将定期使用推拉方法。

可以为许多需要数字或文本数据的实验生成合成数据,因为这些数据可以在没有任何特定仪器的计算机上使用根据预定义约束生成数据的程序生成。为了生成文本数据,可以使用现有的离线文本数据或具有文本信息的在线网页来生成用于处理的新样本。例如,文本挖掘和语言处理有时需要样本文本数据。

合成数据生成(制作)

在本节中,我们将讨论合成数值数据生成的各种方法。我们还将展示一个使用泊松分布的随机数生成算法及其 Python 实现。此外,我们将探索合成文本数据生成的不同方法。

使用 Python 的内置函数生成随机数

Python 有一个名为 random 的模块,它基于各种统计分布实现各种伪随机数生成器。该模块具有针对各种类型随机性的功能,例如整数、序列、列表的随机排列,以及从预定义群体生成随机样本。Python 随机模块支持使用各种统计分布生成随机数,包括均匀分布、正态分布(高斯分布)、对数正态分布、负指数分布、伽玛分布和贝塔分布。为了生成均匀的随机角度,Python 提供了冯米塞斯分布。Python 中随机数生成器的大部分模块都依赖于一个名为random()的基本函数。该函数生成半开范围内的随机浮点数(【0.0,1.0】)。

Mersenne Twister 是 Python 的主要随机数生成器。它能够产生 53 位精度的随机浮点数,周期为 2**19937-1。它是用 C 语言写在底层实现之上的,是线程安全和快速的。这是最广泛使用和测试的随机数发生器之一。然而,它并不适合所有应用,因为它是完全确定的。因此,它根本不适合与安全性相关的计算。随机模块还提供了一个SystemRandom类,该类使用操作系统提供的工具中的os.urandom()函数生成随机数。此类可用于生成用于加密目的的随机数。

随机模块的功能是random.Random类的隐藏实例的绑定方法。但是,用户可以拥有自己的Random类实例。优点是这个实例不共享状态。此外,如果用户需要设计一个新的随机数生成器,那么这个类也可以被扩展/继承来创建一个新的Random子类。在这种情况下,用户应该覆盖五种方法:getstate()jumpahead()random()seed()setState()

让我们讨论 Python 随机模块的各种内置方法。如下节所述,这些功能分为几类。

记账功能

随机模块的各种记账功能如下:

  • random.seed(a=None, version=2):该功能初始化随机数发生器。如果用户将整数值传递给a,则使用该值。如果没有值传递给a或者如果是none,则当前系统时间被用作seed值。如果正在使用的操作系统支持随机性来源,那么将使用它们而不是系统时间作为seed值。
  • random.getstate():此函数返回一个代表随机数发生器当前内部状态的对象。该对象可用于使用setstate()功能恢复相同的状态。
  • random.setstate(state):状态值必须是调用getstate()函数得到的对象。然后,setstate将发电机的内部状态恢复到调用getstate()时的状态。
  • random.getrandbits(k):该函数返回一个带有k随机位的 Python 长整数。该方法由MersenneTwister发电机提供,也可以由其他几台发电机提供。

整数随机数生成功能

这里陈述了返回整数随机数的不同函数:

  • random.randrange(stop)random.randrange(start, stop[, step]):此方法从给定的中返回随机选择的元素。其参数含义如下:start是区间的起点;它将包含在范围内。stop功能是范围的终点;它将被排除在范围之外。step代表要加到一个数上以决定一个随机数的值。
  • random.randint(a,b):该函数返回从ab的包含范围内的整数值。

序列的功能

对序列进行运算以生成新的随机序列或子序列的各种功能如下:

  • random.choice(seq):该函数返回非空seq序列的随机元素。seq字符必须是非空的。如果seq为空,则该函数会引发名为IndexError的错误/异常。
  • random.shuffle(x):该功能将x顺序打乱。原地洗牌意味着值的位置将在列表变量中改变。
  • random.sample(population, k):该函数从群体中返回唯一随机元素的k长度列表。群体必须是序列或集合。该功能一般用于随机采样,无需替换。此外,群体的成员可以是重复的,并且它们的每个出现都有相等的概率出现在所选列表中。如果样本量大于种群量 k ,将提出ValueError例外。

基于统计分布的函数

有很多统计分布适合各种情况。为了支持这些情况,随机数模块具有针对不同统计分布的一组函数。以下是基于统计分布的随机数生成器:

  • 随机数发生器函数(random.uniform(a,b)) :该函数返回一个介于ab之间的随机浮点数 N 。在ab之间选择任意数字的概率相等。
  • 随机三角(低、高、模式)发生器:此函数根据三角分布返回一个随机浮点数 N ,使得低< = N < =高。低值和高值被视为界限,并且mode保持在这些界限之间。下限的默认值为 0。上限为 1,mode参数默认为下限和上限之间的中点。
  • 随机β变量(α,β)生成器:该函数根据参数上的β分布条件返回一个介于 0 和 1 之间的随机数,为α(α)>0β(β)>0
  • 随机数发生器:这个函数根据指数分布返回一个随机数。参数 lambd ( λ)的值应该是非零的。如果 lambd 为正,则返回 0 到正无穷大范围内的值,如果 lambd 为负,则返回负无穷大到 0 范围内的值。这个参数被有意地称为 lambda,因为 lambda 在 Python 中是一个保留字。
  • 随机γ变量(α,β)生成器:该函数按照γ分布生成随机数,参数条件为α(α)>0β(β)>0
  • 随机正态变量(μ,σ)生成器:正态分布是跟随生成随机数。这里,μ(μ)是平均值,σ(σ)是标准差。
  • random . gauss(μ,σ)生成器:顾名思义,这个函数使用高斯分布来生成随机数。同样,μ是平均值,σ是标准差。与正态分布相比,这个函数更快。
  • 随机数生成器:对数正态分布用于随机数生成。由这个分布得到的值的自然对数给出了正态分布的值。同样,μ是平均值,σ是标准差。这里,mu 可以有任何值,但是 sigma 必须大于零。
  • 随机变量(μ,kappa)生成器:该函数使用冯米塞斯分布返回随机角度,其中μ是以弧度为单位的平均角度,值介于 0 和 2pi* 之间,kappa ( κ )是浓度参数( > =0 )。
  • 随机.帕累托变量(α)生成器:该函数遵循帕累托分布返回一个随机变量。这里,α是形状参数。
  • 随机威布尔变量(α,β)生成器:威布尔分布是本函数中用来生成随机数的。这里,α是比例参数,β是形状参数。

不确定随机数发生器

除了所讨论的随机数生成功能之外,还有一种可选的随机数生成器可以使用,特别是在随机数生成必须是不确定的情况下,例如加密和安全中需要的数字。该发电机为类random.SystemRandom([seed])。这个类使用操作系统提供的os.urandom()函数生成随机数。

下面的程序演示了所讨论的函数的用法。函数调用的输出也显示在其中。为了简单起见,我们只在其中使用了以下函数:

  • random.random
  • random.uniform
  • random.randrange
  • random.choice
  • random.shuffle
  • print random.sample
  • random.choice

程序如下:

import random
print random.random()
print random.uniform(1,9)
print random.randrange(20)
print random.randrange(0, 99, 3) 
print random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ') # Output 'P'
items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
random.shuffle(items)
print items
print random.sample([1, 2, 3, 4, 5, 6, 7, 8, 9, 10],  5)   
weighted_choices = [('Three', 3), ('Two', 2), ('One', 1), ('Four', 4)]
population = [val for val, cnt in weighted_choices for i in range(cnt)]
print random.choice(population) 

我们来讨论一下每个函数调用的输出。第一个函数random返回任何大于 0 小于 1 的浮点随机值。uniform函数返回给定范围内均匀分布的随机值。randrange函数返回给定范围内的随机整数值。如果忽略第一个参数,则取默认值0。所以randrange(20)的范围是 0 到 19。

现在,让我们讨论与序列相关的函数的输出。choice函数从提供的选项列表中返回一个随机选项。在本例中,有 26 个选项,返回一个值Pshuffle函数的输出是显而易见的,正如所料,一些值被打乱了。sample功能选择给定大小的随机样本。在本例中,sample尺寸选择为5。因此,随机样本有五个要素。最后三行执行一个重要的功能,以给定的概率选择一个随机选择。这就是为什么这个choice函数被称为加权选择——因为权重被分配给应用所需的每个选择。

设计并实现基于统计分布的随机数生成器

在本节中,我们将讨论泊松分布的算法设计及其 Python 实现。这在两个方面会有好处;一个是你将学习一个新的随机数生成统计分布的设计和实现。第二个方面是这个功能在随机模块中不可用,所以用户也可以使用这个新的发行版。对于一些特定的应用,一些变量假设泊松随机值。例如,考虑操作系统中进程调度中使用的调度算法。为了模拟流程调度,流程到达遵循泊松分布。

有许多应用泊松分布的情况。其中一些案例如下:

  • 互联网上的流量模式遵循泊松分布
  • 呼叫中心收到的呼叫数遵循泊松分布
  • 曲棍球或足球(两队)等比赛中的进球数也遵循泊松分布
  • 操作系统中的进程到达时间
  • 给定一个年龄组,一年的死亡人数又是一个泊松模式
  • 给定时间间隔内股票价格的跳跃次数
  • 如果我们对一段给定的 DNA 施加辐射,突变的数量遵循泊松分布

泊松分布的算法是 Knuth 在他的畅销书计算机编程的艺术,第二卷中给出的,具体如下:

algorithm poisson_random_number (Knuth):
    initializations:
         L = e−λ, 
count = 0 
product = 1
    do:
           k = k + 1
           u = uniform_random_number (0,1) 
p = p × u
    while p > L
    return k − 1

下面的代码是泊松分布的 Python 实现:

import math
import random
def nextPoisson(lambdaValue):
  elambda = math.exp(-1*lambdaValue)
  product = 1
  count = 0

  while (product >= elambda):
    product *= random.random()
    result = count
    count+=1
  return result
for x in range(1, 9):
  print nextPoisson(8)

前一程序的输出如下:

5
7
11
8
9
8
7
6

重现生成的随机数的特别说明

如果应用要求再现使用任何方法生成的随机数,那么在这种情况下,可以选择再现使用这些函数生成的数字。为了重现这个序列,我们只需要使用具有相同种子值的相同函数。通过这种方式,我们可以重现列表,这就是为什么我们称大多数随机数生成函数为确定性的。

用简单的逻辑生成五位随机数的程序

下一个程序演示了使用时间和日期对象产生随机数的思想。它有非常简单的逻辑来生成五位数的随机数。在这个程序中,当前系统时间用于生成随机数。系统时间的四个组成部分——小时、分钟、秒和微秒——通常是一个独特的组合。该值被转换为字符串,然后转换为五位数的值。用户定义函数中的第一行用于引入微秒级的延迟,以便在很短的时间内不同调用之间的时间值会有所不同。如果没有这一行,用户可能会得到一些重复的值:

import datetime 
import time

# the user defined function that returns 5 digit random number
def  next_5digit_int():
  # this will introduce randomness at the microsecond level
  time.sleep(0.123)            
current_time = datetime.datetime.now().time() 
  random_no = int(current_time.strftime('%S%f'))
  # this will trim last three zeros
  return random_no/1000          

# to demonstrate generation of ten random numbers
for x in range(0, 10):
  i = next_5digit_int()
  print i

关于大规模数据集的简要说明

各种科学应用的数据集从几 MB 到几 GB 不等。对于某些特定的应用,数据集可能很大。这些巨大的数据集可能跨越几千兆字节。我们通常理解 MB 和 GB;让我们了解一下千兆字节的规模。假设我们在光盘 ( 光盘 ) 中存储 1pb 的数据,并将这些光盘以堆栈的形式排列。这个堆栈的大小大约为 1.75 公里。由于网络和分布式计算技术的最新进展,如今有许多应用可以处理几千兆字节的数据集。为了高效地处理大规模数据集,在软件或硬件的所有级别都有许多可用的选项。

有几种有效的框架可以处理各种规模的数据集。这些框架可以同等效率地处理小型、中型或大型数据,具体取决于所提供的基础设施。Map reduce 就是这样一个框架的例子,Hadoop 是 MapReduce 框架的开源实现。

在数据库级别,用户有许多选择,能够存储和管理任何规模的数据。这些数据库可能是最简单的,比如平面文件——文本或二进制文件。然后,有许多基于模式的数据库,如关系数据库,可以有效地管理几千兆字节的数据库。文件和基于模式的数据库都可以管理从几兆字节到几千兆字节的数据。为了处理超出这些限制的数据,目前的趋势是使用非基于模式的数据库和高级分布式文件系统,例如谷歌的 BigTable、Apache HBase 和 HDFS。HBase 是一个面向列的数据库,旨在支持非常大规模的数据库。HDFS 是一个分布式文件系统,能够存储几千兆字节大小的文件,不像普通文件系统(如 WINDOWS NT)中的最大文件大小约为 16 GB。

大多数编程语言都支持这些框架和数据库,包括 Python、Scala、Java、Ruby 等等。除了软件层面,硬件层面也有进步,例如不同硬件(例如处理器、输入/输出设备和网络设备)中的虚拟化概念。还增强了对所讨论的软件的硬件级支持。

分布式计算的最新进展,称为云计算,已经实现了许多新的科学计算和商业应用。这是可能的,因为云计算与本节中讨论的概念一起,提供了有史以来最高的处理和存储能力。这使得许多新的应用得以实现,并且这类应用的列表日益增长。

所讨论的技术广泛应用于需要文本搜索、模式发现和匹配、图像处理、数据挖掘和处理大型数据集的应用中。这种要求在各种商业和科学应用中非常常见。

第 8 章并行和大规模科学计算中,我们将对这些技术进行详细的讨论,重点是将其用于大规模科学应用。

总结

本章首先讨论了数据、信息和知识的基本概念。然后介绍了用于存储数据的各种软件。之后,我们讨论了应该在数据集上执行的各种操作。然后我们看到了存储科学数据的标准格式。我们还讨论了各种预定义的、已经使用的和标准的数据集,用于各种学科领域的许多科学应用。然而,在特定主题中,有些领域的数据集不可用。

在介绍了基本概念之后,介绍了为某些特定实验准备合成数据的各种技术。还介绍了用于合成数据生成的随机数生成的各种标准函数。对于合成数据生成,介绍了一种使用泊松分布生成随机数的算法和程序。

下一章将详细讨论并展示用于科学计算的各种 Python APIs 和工具包的功能。这些 API 提供数值计算(NumPy 和 SciPy)、符号计算(SymPy)、数据可视化和绘图(matplotlib 和 pandas)以及交互式编程(IPython)。本章还将简要讨论这些 API 的特性和功能。

四、面向 Python 的科学计算 API

在本章中,我们将全面讨论 Python 中各种科学计算 API 和工具包的特性和功能。除了基础知识,我们还将讨论每个 API 的一些示例程序。由于符号计算是计算机化数学的一个相对不同的领域,我们在 SymPy 部分分配了一个特殊的小节来讨论计算机化代数系统的基础。

在本章中,我们将涵盖以下主题:

  • 利用 NumPy 和 SciPy 进行科学数值计算
  • 使用 SymPy 的符号计算
  • 计算机化的代数系统
  • SymPy 及其模块简介
  • SymPy 中的几个简单的示例程序
  • 数据分析、可视化和交互式计算

Python 中的数值科学计算

科学计算主要要求对代数方程、矩阵、微分、积分、微分方程、统计、方程求解器等进行计算。默认情况下,Python 没有这些功能。然而,NumPy 和 SciPy 的发展已经使我们能够执行这些操作,以及比它们更高级的功能。NumPy 和 SciPy 是非常强大的 Python 包,使用户能够高效地为所有类型的科学应用执行所需的操作。

NumPy 包

NumPy 是科学计算的基础 Python 包。它提供多维数组和基本数学运算的工具,如线性代数。Python 提供了几种数据结构来存储用户数据;最流行的数据结构是列表和字典。列表对象可以将任何类型的 Python 对象存储为一个元素。这些元素可以使用循环或迭代器来处理。字典对象以键值格式存储数据。

标准的数据结构

ndarrays 类似于 list,但是非常灵活和高效。n array 是一个数组对象,用于表示固定大小项目的多维数组。这个数组应该是同构的。它有一个类型为dtype的关联对象,用于定义数组中元素的数据类型。该对象定义数据类型(整数、浮点或 Python 对象)、数据大小(字节)和字节顺序(大端或小端)。此外,如果数据的类型是recordsub-array,那么它也包含关于它们的细节。实际数组可以使用数组、零或空方法中的任何一种来构造。

ndarrays 的另一个重要方面是数组的大小可以动态修改。此外,如果用户需要从数组中移除一些元素,那么这可以使用屏蔽数组的模块来完成。在许多情况下,科学计算要求删除/移除不正确或错误的数据。numpy.ma模块提供了屏蔽数组的功能,可以轻松地从数组中移除选定的元素。屏蔽数组只不过是普通的带屏蔽的数组。Mask 是另一个具有真值或假值的关联数组。如果对于特定位置,掩码具有真值,则主数组中的对应元素有效,如果掩码为假,则主数组中的对应元素无效或被掩码。在值为false的这种情况下,当对这种数组执行任何计算时,将不会考虑被屏蔽的元素。

文件处理

科学计算的另一个重要方面是将数据存储在文件中,NumPy 支持文本和二进制文件的读写。大多数情况下,文本文件是一种很好的读取、写入和数据交换方式,因为它们本身是可移植的,并且默认情况下,大多数平台都有能力操作它们。但是,对于某些应用,有时最好使用二进制文件,或者在某些情况下,此类应用所需的数据只能存储在二进制文件中。有时,图像或声音等数据的大小和性质要求将其存储在二进制文件中。

与文本文件相比,二进制文件更难管理,因为它们有特定的格式。此外,二进制文件的大小相对非常小,对它们的读/写操作比读/写文本文件要快得多。这种快速读/写最适合处理大型数据集的应用。用 NumPy 操作的二进制文件的唯一缺点是它们只能通过 NumPy 访问。

Python 有文本文件操作功能,如openreadlineswritelines。然而,将这些功能用于科学数据操作并不具有性能效率。这些默认的 Python 函数在文件中读写数据非常慢。NumPy 有一个高性能的替代方案,可以在实际计算之前将数据加载到数组中。在 NumPy 中,可以使用numpy.loadtxtnumpy.savetxt功能访问文本文件。loadtxt功能可用于将数据从文本文件加载到数据库。NumPy 还有一个单独的函数,用于操作二进制文件中的数据。读写功能分别为numpy.loadnumpy.save

一些 NumPy 示例程序

NumPy 数组可以从使用该数组的列表或元组中创建。这种方法可以将序列序列转换成二维数组:

import numpy as np
x = np.array([4,432,21], int)
print x   #Output [  4 432  21]
x2d = np.array( ((100,200,300), (111,222,333), (123,456,789)) )
print x2d

以下是输出:

[  4 432  21]
[[100 200 300]
[111 222 333]
[123 456 789]]

基本的矩阵算术运算可以很容易地在二维数组上执行,如下面的程序中所使用的。基本上,这些操作应用于元素。因此,操作数数组的大小必须相等。如果大小不匹配,则执行这些操作将导致运行时错误。考虑以下一维数组的算术运算示例:

import numpy as np
x = np.array([4,5,6])
y = np.array([1,2,3])
print x + y    # output [5 7 9]
print x * y    # output [ 4 10 18]
print x - y    # output [3 3 3]  
print x / y    # output [4 2 2]
print x % y    # output [0 1 0]

有一个单独的子类叫做 matrix,用于执行矩阵运算。让我们通过下面的例子来理解矩阵运算,它演示了基于数组的乘法和矩阵乘法之间的区别。NumPy 矩阵是二维的,数组可以是任意维的:

import numpy as np
x1 = np.array( ((1,2,3), (1,2,3), (1,2,3)) )
x2 = np.array( ((1,2,3), (1,2,3), (1,2,3)) )
print "First 2-D Array: x1"
print x1
print "Second 2-D Array: x2"
print x2
print "Array Multiplication"
print x1*x2

mx1 = np.matrix( ((1,2,3), (1,2,3), (1,2,3)) )
mx2 = np.matrix( ((1,2,3), (1,2,3), (1,2,3)) )
print "Matrix Multiplication"
print mx1*mx2

输出如下:

First 2-D Array: x1
[[1 2 3]
  [1 2 3]
  [1 2 3]]
Second 2-D Array: x2
[[1 2 3]
  [1 2 3]
  [1 2 3]]
Array Multiplication
[[1 4 9]
  [1 4 9]
  [1 4 9]]
Matrix Multiplication
[[ 6 12 18]
  [ 6 12 18]
  [ 6 12 18]]

下面是一个简单的程序,演示了 NumPy 中给出的简单统计函数:

import numpy as np
x = np.random.randn(10)    # Creates an array of 10 random elements
print x
mean = x.mean()
print mean
std = x.std()
print std
var = x.var()
print var

这是的第一个样本输出:

[0.08291261  0.89369115  0.641396   -0.97868652  0.46692439 -0.13954144
  -0.29892453  0.96177167  0.09975071  0.35832954]
0.208762357623
0.559388806817
0.312915837192

以下是第二个示例输出:

[ 1.28239629  0.07953693 -0.88112438 -2.37757502  1.31752476  1.50047537
  0.19905071 -0.48867481  0.26767073  2.660184  ]
0.355946458357
1.35007701045
1.82270793415

前面的程序是 NumPy 的一些简单例子。在第 5 章执行数值计算中,我们将详细讨论 NumPy 功能。下一小节讨论 SciPy Python 包。

科学包

SciPy 通过提供高级数学函数,如微分、积分、微分方程、优化、插值、高级统计函数、方程求解器等,扩展了 Python 和 NumPy 对的支持。SciPy 是写在 NumPy 数组框架之上的。它利用了 NumPy 中提供的数组及其基本操作,并将其扩展到科学家和工程师应用经常需要的大多数数学方面。

在本章中,我们将介绍一些基本功能的示例,在第 5 章执行数值计算中,我们将全面介绍 NumPy 和 SciPy 功能。在随后的小节中,我们将介绍 SciPy 的各种重要包/模块的基础知识,包括聚类分析、文件处理、集成、插值、优化、信号和图像处理、特殊分析和统计。

优化包

SciPy 中的优化包提供了解决单变量和多变量最小化问题的功能。它使用许多算法和方法为最小化问题提供解决方案。最小化问题在科学和商业领域有着广泛的应用。通常,我们执行线性回归,搜索函数的最小值和最大值,找到函数的根,并对这种情况进行线性规划。优化包支持所有这些功能。

插值包

插值包中提供了许多插值方法和算法作为内置函数。它提供了执行单变量和多变量插值以及一维和二维样条的工具。当数据依赖于一个变量时,我们使用单变量插值;如果它依赖于一个以上的变量,那么我们使用多元插值。除了这些功能,插值包还为拉格朗日和泰勒多项式插值器提供了额外的功能。

SciPy 中的积分和微分方程

积分是科学计算的重要数学工具。SciPy 集成子包提供了执行数值集成的功能。SciPy 提供了一系列函数来对方程和数据进行积分。它还有一个常微分方程积分器。它提供了各种功能,以执行数值积分的帮助下,许多方法从数学使用数值分析。

统计模块

SciPy 统计模块包含一个用于大多数概率分布和大范围或统计函数的函数。支持的概率分布包括各种连续分布、多元分布和离散分布。统计函数的范围从简单的平均值到最复杂的统计概念,包括偏斜度、峰度和卡方检验,仅举几例。

SciPy 中的聚类包和空间算法

聚类分析是一种流行的数据挖掘技术,在科学和商业领域有着广泛的应用。在科学领域,生物学、粒子物理学、天文学、生命科学和生物信息学是广泛使用聚类分析解决问题的几个学科。聚类分析在计算机科学中被广泛用于计算机化的欺诈检测、安全分析、图像处理以及许多其他领域。聚类软件包提供了 K-means 聚类、矢量量化以及分层和聚集聚类功能。

spatial类具有使用三角剖分、Voronoi 图和一组点的凸包来分析数据点之间距离的功能。它还具有用于执行最近邻查找功能的 KDTree 实现。

SciPy 中的图像处理

SciPy 提供对执行各种图像处理操作的支持,包括图像文件的基本读写、显示图像以及简单的图像操作,如裁剪、翻转和旋转。它还支持图像滤波功能,如数学变形、平滑、去噪和图像锐化。此外,它支持各种其他操作,例如通过标记对应于不同对象的像素进行图像分割、分类以及例如边缘检测的特征提取。

【SciPy 程序示例

在接下来的小节中,我们将讨论一些使用 SciPy 模块和包的示例程序。我们将从一个执行标准统计计算的简单程序开始。之后,我们将讨论一个使用优化找到最小解的程序。最后,我们将讨论图像处理程序。

使用 SciPy 进行统计

SciPy 的 stats 模块具有执行简单统计运算和各种概率分布的功能。以下程序演示了使用stats.describe SciPy 函数的简单统计计算。这个函数对一个数组进行运算,并返回元素数量、最小值、最大值、平均值、方差、偏斜度和峰度:

import scipy as sp
import scipy.stats as st
s = sp.randn(10)
n, min_max, mean, var, skew, kurt = st.describe(s)
print("Number of elements: {0:d}".format(n))
print("Minimum: {0:3.5f} Maximum: {1:2.5f}".format(min_max[0], min_max[1]))
print("Mean: {0:3.5f}".format(mean))
print("Variance: {0:3.5f}".format(var))
print("Skewness : {0:3.5f}".format(skew))
print("Kurtosis: {0:3.5f}".format(kurt))

这里是输出:

Number of elements: 10
Minimum: -2.00080 Maximum: 0.91390
Mean: -0.55638
Variance: 0.93120
Skewness : 0.16958
Kurtosis: -1.15542

SciPy 中的优化

一般在数学优化中,使用一个称为 Rosenbrock 函数的非凸函数来测试优化算法的性能。下面的程序演示了这个函数的最小化问题。 N 变量的罗森布罗克函数由下式给出,在 xi =1 处最小值为 0:

Optimization in SciPy

上述功能的程序如下:

import numpy as np
from scipy.optimize import minimize

# Definition of Rosenbrock function
def rosenbrock(x):
     return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0)

x0 = np.array([1, 0.7, 0.8, 2.9, 1.1])
res = minimize(rosenbrock, x0, method = 'nelder-mead', options = {'xtol': 1e-8, 'disp': True})

print(res.x)

这是输出:

Optimization terminated successfully.
         Current function value: 0.000000
         Iterations: 516
         Function evaluations: 827
[ 1\.  1\.  1\.  1\.  1.]

最后一条线是print(res.x)的输出,其中数组的所有元素都是1

使用 SciPy 进行图像处理

下面开发了两个程序来演示 SciPy 的图像处理功能。第一个程序只是显示一个标准的测试图像。该图像广泛应用于图像处理领域,被称为 Lena。第二个程序对这个图像应用几何变换。它执行图像裁剪和旋转 45%。

下面的程序使用 matplotlib API 显示 Lena 图像。imshow方法将数组渲染成图像,show方法显示图像:

from scipy import misc
l = misc.lena()
misc.imsave('lena.png', l) 
import matplotlib.pyplot as plt
plt.gray()
plt.imshow(l)
plt.show()

上一个程序的输出如下图所示:

Image processing using SciPy

以下程序执行几何变换。该程序将变换后的图像与原始图像一起显示为四轴数组:

import scipy
from scipy import ndimage
import matplotlib.pyplot as plt
import numpy as np

lena = scipy.misc.lena()
lx, ly = lena.shape
crop_lena = lena[lx/4:-lx/4, ly/4:-ly/4]
crop_eyes_lena = lena[lx/2:-lx/2.2, ly/2.1:-ly/3.2]
rotate_lena = ndimage.rotate(lena, 45)

# Four axes, returned as a 2-d array
f, axarr = plt.subplots(2, 2)
axarr[0, 0].imshow(lena, cmap=plt.cm.gray)
axarr[0, 0].axis('off')
axarr[0, 0].set_title('Original Lena Image')
axarr[0, 1].imshow(crop_lena, cmap=plt.cm.gray)
axarr[0, 1].axis('off')
axarr[0, 1].set_title('Cropped Lena')
axarr[1, 0].imshow(crop_eyes_lena, cmap=plt.cm.gray)
axarr[1, 0].axis('off')
axarr[1, 0].set_title('Lena Cropped Eyes')
axarr[1, 1].imshow(rotate_lena, cmap=plt.cm.gray)
axarr[1, 1].axis('off')
axarr[1, 1].set_title('45 Degree Rotated Lena')

plt.show()

这是输出:

Image processing using SciPy

SciPy 和 NumPy 是 Python 支持科学计算的核心,因为它们在数值计算方面提供了坚实的功能。在第 5 章执行数值计算中,我们将详细讨论这两个包。下一小节介绍使用 SymPy 的符号计算。

使用 SymPy 的符号计算

对数学符号进行的计算机化计算,而不评估或改变其含义,称为符号计算。一般来说,符号计算也被称为计算机化代数,这样的计算机化系统被称为计算机代数系统。下一小节对 SymPy 做了一个简单而好的介绍。在第 6 章将 Python 应用于符号计算中,我们将深入报道 Python 中的符号计算。

计算机代数系统

让我们来讨论一下计算机代数系统 ( CAS )的概念。CAS 是一种软件或工具包,用于使用计算机而不是手动计算对数学表达式进行计算。起初,使用计算机进行这些应用被称为计算机代数;现在这个概念被称为符号计算。CAS 系统可分为两种类型。第一类是通用 CAS,第二类是针对特定问题的 CAS。通用系统适用于代数数学的大多数领域,而专用 CAS 是为特定领域设计的系统,如群论或数论。大多数时候,我们更喜欢通用 CAS 来处理科学应用中的数学表达式。

通用 CAS 的特性

用于科学应用的通用化学文摘社的各种期望特征如下:

  • 操作数学表达式的用户界面。
  • 用于编程和调试的接口。
  • 这种系统需要简化各种数学表达式。因此,简化程序是这种计算机代数系统最基本的组成部分。
  • 通用 CAS 系统必须支持一组详尽的函数来执行任何代数计算所需的各种数学运算。
  • 大多数应用执行大量计算,因此高效的内存管理非常重要。
  • 该系统必须支持对高精度数字和大数量进行数学计算。

症状的简要概念

SymPy 是 CAS 的开源和基于 Python 的实现。开发 SymPy 背后的理念是设计和开发一个 CAS,该 CAS 具有所有期望的特性,但其代码尽可能简单,以便它能够高度且容易地扩展。它完全用 Python 编写,不需要任何外部库。

SymPy 背后的基本思想是表达式的创建和操作。使用 SymPy,用户用 Python 语言表示数学表达式——通过使用 SymPy 类和对象。这些表达式由数字、符号、运算符、函数等组成。函数是执行数学功能的模块,如对数和三角函数。

ondřej·切尔蒂克于 2006 年 8 月开始开发 SymPy。从那以后,在数百人的贡献下,它有了很大的发展。这个库现在由 26 个不同的集成模块组成。这些模块能够执行基本符号算术、微积分、代数、离散数学、量子物理、绘图和打印所需的计算,以及以 LaTeX 和其他格式导出计算输出的选项。

SymPy 的能力可以分为两类——核心能力高级能力——因为 SymPy 库分为一个核心模块和几个高级可选模块。各种模块支持的功能将在以下章节中讨论。

核心能力

核心能力模块支持要执行的任何数学代数运算所需的基本功能。这些运算包括基本算术,如乘法、加法、减法和除法,还有指数运算。该模块还支持简化表达式,以便简化复杂的表达式。它提供了扩展系列和符号的功能。

核心模块还支持用于执行与三角学、双曲线、指数、方程根、多项式、阶乘、伽马函数、对数以及 B 样条、球谐函数、张量函数和正交多项式的许多特殊函数相关的操作的函数。

核心模块中也有对模式匹配操作的强大支持。此外,SymPy 的核心功能包括支持代数运算所需替换的功能。它不仅支持整数、有理数和浮点数的高精度算术运算,还支持多项式运算所需的非交换变量和符号。

多项式

用于执行多项式运算的各种函数属于多项式模块。这些函数包括除法、最大公约数 ( GCD )、最小公倍数 ( LCM )、无平方因式分解、具有符号系数的多项式表示、一些特殊操作,例如结果的计算、三角恒等式的导出、部分分数分解以及多项式环和域上的 Grbner 基的工具。

微积分

演算模块中提供了支持基础演算和高级演算所需的不同操作的各种功能。它支持限额要求的功能;对此有一个limit功能。它还支持微分、积分、级数展开、微分方程和有限差分演算。SymPy 还特别支持定积分和积分变换。在微分中,它支持数值微分、导数的合成和分数导数。

解方程

求解器是提供方程求解功能的 SymPy 模块的名称。该模块支持复杂多项式、多项式根和多项式方程组的求解能力。有一个解代数方程的函数。它不仅支持微分方程(包括常微分方程、某些形式的偏微分方程、初值和边值问题等)的求解,还支持差分方程的求解。在数学中,差分方程也称为递归关系,即递归定义值的序列或多维数组的方程。

离散数学

离散数学包括本质上是离散的数学结构,而不是连续的数学(如微积分)。它从逻辑理论的角度处理整数、图形和语句。该模块完全支持二项式系数、乘积和求和。

该模块还支持数论中的各种函数,包括剩余理论、欧拉全能性、划分以及一些处理素数及其因式分解的函数。Plus SymPy 支持使用符号和布尔值创建和操作逻辑表达式。

矩阵

SymPy 对与矩阵和行列式相关的各种运算有强有力的支持。矩阵属于数学的线性代数范畴。它支持创建矩阵、基本矩阵运算(如乘法和加法)、0 和 1 的矩阵、创建随机矩阵以及对矩阵元素执行运算。它还支持特殊函数,例如计算一个函数的黑森矩阵、一组向量上的格拉姆-施密特过程、计算一个函数矩阵的渥伦斯肯等等。

此外,它完全支持特征值和特征向量、矩阵求逆以及矩阵和行列式的求解。计算矩阵的行列式,除了其他方法外,它还支持巴雷斯的无分数算法和伯克维茨算法。对于矩阵,它支持零空间计算、余因子展开工具、矩阵元素的导数计算以及计算矩阵的对偶。

几何图形

SymPy 有一个支持与 2D 几何相关的各种操作的模块。它支持创建 2D 实体或对象,如点、线、圆、椭圆、多边形、三角形、射线和线段。它还允许我们对这些实体进行查询,例如合适对象(椭圆、圆或三角形)的面积和直线的交点。然后,它支持诸如确定直线相切和查找实体的相似性和交集等查询。

标绘

有一个非常好的模块,可以让我们画出二维和三维的图。目前,使用matplotlib包渲染地块。它还支持其他软件包,如TextBackendPyglettextplot等。它有一个非常好的交互界面工具,可以定制和绘制各种几何实体。

绘图模块具有以下绘图功能:

  • 2D 线图
  • 2D 参数图
  • 2D 隐式和区域图
  • 包含两个变量的函数的三维图
  • 三维线和曲面图

物理学

还有也是一个解决物理领域问题的模块。它支持力学功能,包括经典力学和量子力学,以及高能物理。它具有支持一维和三维泡利代数和量子谐振子的功能。它还具有光学功能。有一个单独的模块将单元系统集成到 SymPy 中。这允许用户选择特定的单位系统来执行他们的计算和单位之间的转换。单位制由计算用的单位和常数组成。

统计

在 SymPy 中引入了统计模块,以支持数学计算中所需的各种统计概念。除了支持各种连续和离散的统计分布,它还支持与符号概率相关的功能。一般来说,这些分布支持 SymPy 中随机数生成的函数。

印刷

SymPy 有一个为美版提供全面支持的模块。漂亮的打印将各种风格的格式转换成文本文件,如源代码、文本文件、标记文件或类似的内容。该模块通过使用 ASCII 和/或 Unicode 字符进行打印来产生所需的输出。

它支持各种打印机,如 LaTeX 和 MathML 打印机。它能够产生各种编程语言的源代码,如 C、Python 和 Fortran。它也是能够使用标记语言如 HTML 和 XML 产生内容。

症状模块

以下列表显示了前面段落中讨论的模块的正式名称:

  • 假设:假设引擎
  • 具体:符号积和求和
  • 核心基础类结构:基础、添加、Mul、Pow 等等
  • 功能:初等和特殊功能
  • Galgebra :几何代数
  • 几何图形:几何实体
  • 积分:符号积分器
  • 交互:交互会话(例如 IPython)
  • 逻辑:布尔代数与定理证明
  • 矩阵:线性代数和矩阵
  • mpmath :快速任意精度数值数学
  • 合成:数论函数
  • 解析 : Mathematica 和 maxima 解析器
  • 物理学:物理单位和量子材料
  • 绘制:使用Pyglet绘制 2D 和 3D
  • Polys :多项式代数和因式分解
  • 打印:漂亮-打印和代码生成
  • 系列:符号极限和截断系列
  • 简化:改写其他形式的表达式
  • 求解器:代数、递归和微分
  • 统计:标准概率分布
  • 实用工具:测试框架和兼容性相关内容

各种数学工具包中有许多符号计算系统。有一些专有软件,如 Maple 和 Mathematica,也有一些开源替代软件,如奇异和 AXIOM。但是,这些产品有自己的脚本语言。很难扩展它们的功能,并且它们的开发周期很慢。另一方面,SymPy 是高度可扩展的,是用 Python 语言设计和开发的,是一个支持快速开发生命周期的开源 API。

简单的示范程序

这里有一些非常简单的例子来帮助你了解 SymPy 的能力。这些都是少于 10 行的 SymPy 源代码,它们涵盖了从基本符号操作到限制、区分和集成的主题。我们可以通过在谷歌应用引擎上实时运行 SymPy 在线测试这些程序在 SymPy 上的执行情况,该引擎可在http://live.sympy.org/获得。

基本符号操作

下面的代码定义了三个符号和一个带有这些符号的表达式。然后它打印出表达式:

import sympy
a = sympy.Symbol('a')
b = sympy.Symbol('b')
c = sympy.Symbol('c')
e = ( a * b * b + 2 * b * a * b) + (a * a + c * c)
print e

输出如下:

a**2 + 3*a*b**2 + c**2

这里,**代表一个电源操作。

症状中的表达扩展

这里显示的程序演示了表达式扩展的概念。它在这些符号上定义了两个符号和一个简单的表达式,然后打印该表达式及其扩展形式:

import sympy
a = sympy.Symbol('a')
b = sympy.Symbol('b')
e = (a + b) ** 4
print e
print e.expand()

这是输出:

(a + b)**4
a**4 + 4*a**3*b + 6*a**2*b**2 + 4*a*b**3 + b**4

表达式或公式的简化

SymPy 具有简化数学表达式的功能。下面的程序有两个用于简化的表达式,它显示表达式简化后的输出:

import sympy
x = sympy.Symbol('x')
a = 1/x + (x*exp(x) - 1)/x
simplify(a)
simplify((x ** 3 +  x ** 2 - x - 1)/(x ** 2 + 2 * x + 1))

以下是输出:

ex
x – 1

简单积分

这个程序计算两个简单函数的积分:

import sympy 
from sympy import integrate
x = sympy.Symbol('x')
integrate(x ** 3 + 2 * x ** 2 + x, x)
integrate(x / (x ** 2 + 2 * x), x)

输出如下:

x**4/4+2*x**3/3+x**2/2
log(x + 2)

用于数据分析和可视化的 API 和工具包

Python 拥有优秀的工具包和 API,用于分析、可视化和呈现数据和计算结果。在接下来的讨论中,我们将涉及熊猫的概念和想法。我们将简要讨论 matplotlib 和一些图表绘制和以不同格式导出的示例程序。我们可以导出图像文件和其他文件中的图表,如 PDF。在第 7 章数据分析和可视化中,我们将详细讨论 matplotlib 和 pandas 的大部分概念,以及 IPython 工具包。

利用大熊猫进行数据分析和处理

熊猫是一个用于数据分析和数据处理的 Python 包。它由许多数据结构组成,用于在 Python 中进行科学数据分析。熊猫发展背后的最终目标是设计一个强大而灵活的数据操作和分析工具。它提供了高效、灵活和重要的数据结构,这些数据结构经过特殊设计,可以处理任何类型的数据。熊猫可以用来处理大多数流行的数据库和数据集。熊猫是在 NumPy 的基础上发展起来的。

因此,它本质上支持与 Python 的其他科学计算 API 和工具包的集成。它可以用于以下任何类型的数据:

  • 它可以是表格数据,如关系数据库或电子表格(例如,微软电子表格)
  • 它可以是有序或无序的时间序列数据
  • 它可以是以多维数组组织的数据,例如带有行和列标签的矩阵
  • 它可以是我们在第 3 章中讨论的用于以任何格式存储科学数据的任何数据集,高效地制造和管理科学数据

大熊猫的重要数据结构

熊猫的数据结构范围从 1D 到 3D。系列是 1D,数据框架是 2D,面板是三维更高维的数据结构;其更高的层面如 4D 正在发展中。通常,系列和数据框架适用于统计、工程、金融和社会科学中的大多数用例:

  • 系列:这个是一个带标签的 1D 数组,可以用来存储任何数据类型,比如整数、浮点数、字符串和其他有效的 Python 对象。这个轴的标签统称为索引。
  • 数据帧:这个是一个有行有列的标签化的 2D 数据结构。这些列可能有不同的类型。数据框可被视为类似于其他 2D 结构,如电子表格和数据库表。DataFrame 也可以被认为是不同类型的多个系列的集合。
  • 面板:在统计学和经济学中,面板数据指的是多维数据,其中包含了一段时间内进行的不同测量。这个数据结构的名字就是从这个概念衍生出来的。与系列和数据框相比,面板是一种较少使用的数据结构。

大熊猫的特征

以下是熊猫的突出特征:

  • 它提供了在内存中熊猫数据结构和不同数据格式(包括 CSV、微软 Excel、SQL 数据库和 HDF5 格式)之间进行数据操作的工具。
  • 它经过高度优化,可实现高性能;关键代码是在 Cython 和 c 开发的。
  • 它支持使用切片、索引和子集化对大型数据集进行分区或细分。
  • 它提供自动和明确的数据对齐。对象可以明确地与一组标签对齐。如果用户忽略标签,则数据结构会自动对齐数据。
  • 数据结构支持动态大小可变性,因为可以插入和删除列。
  • pandas 有一个强大的group by运算引擎,用于数据的聚合和转换。
  • 它还支持对数据集进行高效的合并和连接操作,以实现数据集成。
  • 它使用重新索引的概念来管理丢失的数据。我们所说的“缺失数据”是指空数据或缺失数据。
  • pandas 还对特定于时间序列的功能提供了出色的支持,包括移动窗口统计、日期范围生成和频率转换、日期移动和滞后、移动窗口线性回归等等。

使用 matplotlib 的数据可视化

matplotlib 是用于数据可视化的 Python API。这是 2D 图形应用最广泛的 Python 包。它提供了一种快速且可定制的数据可视化方式,并以多种格式发布高质量的图像。它支持绘制多维图表。matplotlib 对这些图表的大多数属性都有默认值。然而,这些值是高度可定制的。用户可以控制任何图表的几乎所有设置,如图形大小、线宽、颜色和样式、轴、轴和网格属性以及文本属性(如字体、表面和大小)。

让我们讨论一些将它们绘制和导出为不同格式的示例。

使用 IPython 的 Python 交互计算

有两种流行的使用 Python 程序的风格:交互或通过脚本。仍然有一些程序员更喜欢使用脚本。通常,他们使用文本编辑器编写程序,并使用终端进行执行和其他活动,如调试。此外,科学计算应用通常需要非常好的交互式计算环境。在交互式计算中,只要需要,这些过程就可以从人类那里获取输入。该输入可以来自命令行或图形用户界面。Python 科学计算 API 使用与 IPython 捆绑在一起的一套工具获得了一个交互式计算环境。IPython 大量用于科学计算应用中的各种活动,例如数据管理、数据操作、数据分析、数据可视化、科学计算和大规模计算。

让我们讨论一些简单的例子,通过使用 NumPy、SymPy、pandas 和 matplotlib 来使用 IPython 进行计算。

样本数据分析和可视化程序

在小节中,我们将讨论使用 matplotlib 和 pandas 进行数据分析和可视化的示例程序。如果你没有熊猫和 matplotlib 的本地安装,你可以使用在https://www.pythonanywhere.com/try-ipython/提供的实时 IPython。

首先,我们需要一些数据来分析或可视化。下面的程序从雅虎获取关于苹果的数据!从 2014 年 10 月 1 日至 2015 年 1 月 31 日的财务,并将此数据保存在 CSV 文件中:

import pandas as pd
import datetime
import pandas.io.data

start = datetime.datetime(2014, 10, 1)
end = datetime.datetime(2015, 1, 31)

apple = pd.io.data.get_data_yahoo('AAPL', start, end)
print(apple.head())
apple.to_csv('apple-data.csv')
df = pd.read_csv('apple-data.csv', index_col='Date', parse_dates=True)
df.head()

这是输出:

|   |

打开

|

高的

|

低的

|

关闭

|

|

近的

|
| --- | --- | --- | --- | --- | --- | --- |
| 日期 |   |   |   |   |   |   |
| 10/1/2014 | One hundred point five nine | One hundred point six nine | Ninety-eight point seven | Ninety-nine point one eight | Fifty-one million four hundred and ninety-one thousand three hundred | Ninety-eight point three six |
| 10/2/2014 | Ninety-nine point two seven | One hundred point two two | Ninety-eight point zero four | Ninety-nine point nine | Forty-seven million seven hundred and fifty-seven thousand eight hundred | Ninety-nine point zero eight |
| 10/3/2014 | Ninety-nine point four four | One hundred point two one | Ninety-nine point zero four | Ninety-nine point six two | Forty-three million four hundred and sixty-nine thousand six hundred | Ninety-eight point eight |
| 10/6/2014 | Ninety-nine point nine five | One hundred point six five | Ninety-nine point four two | Ninety-nine point six two | Thirty-seven million fifty-one thousand two hundred | Ninety-eight point eight |
| 10/7/2014 | Ninety-nine point four three | One hundred point one two | Ninety-eight point seven three | Ninety-eight point seven five | Forty-two million ninety-four thousand two hundred | Ninety-seven point nine four |

下一个程序绘制了上一个示例中创建的.csv文件中的数据。它在收盘时计算出 50 移动平均线(50 毫安)读数。然后在 2D 图上画出开盘价、收盘价、最高价、最低价和 50 均线数据。此截图中显示的图表是由截图后显示的程序准备的:

Sample data analysis and visualization programs

程序如下:

import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv('apple-data.csv', index_col = 'Date', parse_dates=True)
df['H-L'] = df.High - df.Low
df['50MA'] = pd.rolling_mean(df['Close'], 50)
df[['Open','High','Low','Close','50MA']].plot()
plt.show()

现在以下程序对相同的数据进行三维绘图:

import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

df = pd.read_csv('apple-data.csv', parse_dates=True)
print(df.head())
df['H-L'] = df.High - df.Low
df['50MA'] = pd.rolling_mean(df['Close'], 50)

threedee = plt.figure().gca(projection='3d')
threedee.scatter(df.index, df['H-L'], df['Close'])
threedee.set_xlabel('Index')
threedee.set_ylabel('H-L')
threedee.set_zlabel('Close')
plt.show()

threedee = plt.figure().gca(projection='3d')
threedee.scatter(df.index, df['H-L'], df['Volume'])
threedee.set_xlabel('Index')
threedee.set_ylabel('H-L')
threedee.set_zlabel('Volume')
plt.show()

前面程序的输出是一个 3D 图,如下图所示:

Sample data analysis and visualization programs

总结

在本章中,我们讨论了各种科学计算 API 和工具包的概念、特征和一些选定的示例程序。这一章从讨论 NumPy 和 SciPy 开始。在介绍完 NymPy 之后,我们讨论了与符号计算和 SymPy 相关的概念。

在剩下的一章中,我们讨论了交互式计算、数据分析和可视化,以及它们的 API 或工具包。IPython 是用于交互式计算的 Python 工具包。我们还讨论了名为 pandas 的数据分析包和名为 matplotlib 的数据可视化 API。

在下一章中,我们将详细讨论数值计算 API——NumPy。我们将借助示例程序介绍 NumPy 的各种函数和相关的数学概念。

五、执行数值计算

在本章中,我们将借助示例程序讨论 NumPy 和 SciPy 的大部分特性。我们将首先通过示例详细讨论数组以及可以对其执行的操作。这将为讨论 NumPy 和 SciPy 支持的各种高级功能奠定坚实的基础。

在本章中,我们将涵盖以下主题:

  • 利用 NumPy 和 SciPy 进行科学数值计算
  • 数字货币的基本目标
  • NumPy 的各种包/模块
  • SciPy 包的基础知识
  • SciPy 的数学函数
  • 高级数学模块和软件包

NumPy 是 Python 中数值计算的基础,其最根本、最重要的思想是支持多维数组。让我们从 NumPy 中数组的基本概念开始讨论。在基础知识之后,我们将讨论可以在多维数组上执行的各种操作。我们还将介绍 NumPy 支持的各种基本和高级数学函数。NumPy 有一些支持高级数学概念的子包或模块。

NumPy 基本对象

NumPy 和 SciPy 的整个科学计算功能是围绕 NumPy 中的两种基本类型的对象构建的。第一个对象是名为n 维数组对象,第二个对象是名为ufunc的通用函数对象。除了这两个对象之外,还有许多其他对象构建在它们之上。

**## 标准对象

数组对象是元素的同构集合,使用 N 整数进行索引,其中 N 是数组的维数。ndarray 有两个重要属性。第一个是数组元素的数据类型,称为dtype,第二个是数组的形状。这里的数据类型可以是 Python 支持的任何数据类型。数组的形状是一个 N 元组,即 N 维数组的 N 个元素的集合,其中元组的每个元素定义数组该维中的元素数量。

数组的属性

除了形状和dtype之外,一个数组的其他重要属性如下:

  • size
  • itemsize
  • data
  • ndim

itemsize是数组中一个元素的长度(以字节为单位),而data属性是一个 Python 缓冲区对象,指向数组数据的开始。让我们借助下面的 Python 程序来理解形状、数据类型和其他属性的概念:

import numpy as np
x2d = np.array( (   (100,200,300), 
                    (111,222,333), 
                    (123,456,789) ) )
x2d.shape
x2d.dtype
x2d.size
x2d.itemsize
x2d.ndim
x2d.data

对数组的基本操作

使用方括号([])来索引数组值被称为 数组索引。考虑上一个程序中定义和使用的x2d二维数组。二维数组的一个特定元素可以称为x2d[row, column]。例如,我们可以将第二行的第二个元素(即222)称为x2d[1,1],因为索引从 0 开始。类似地,x2d[2,1]元素是指第三行的第二个元素(即456)。

数组切片是从数组中选择一些元素以产生子数组的过程。对于一维数组,我们可以从数组中依次选择一些元素。此外,通过使用切片,我们可以获取二维数组的整行或整列。换句话说,使用切片,我们可以跨轴获取数组元素。Python 的基本切片概念扩展到 N 维度进行数组。基本切片语法是start:stop:step。第一个元素指定切片的开始索引,第二个元素指定切片的停止索引,最后一个元素定义要添加到先前选择的元素的索引中的步骤。如果我们跳过前两个值中的任何一个,那么这个值被认为是零或更多。同样,step的默认值为 1。让我们考虑几个例子来使切片更加清晰。

考虑x2d,一个 6×3 的数组。那么x2d[1]x2d[1, :]一样,代表数组的第二行,有三个元素。另一方面,x2d[:, 1]代表数组的第二列,有六个元素。第二列的每三个元素可以选择为x2d[:: 1, 2]

省略号也可以用来替换零个或多个:项。省略号扩展到零个或多个全切片对象,以匹配切片对象的总维度,该维度等于原始数组的维度。比如x4d5×6×7×8,那么x4d[2 :, ..., 6]就相当于x4d[2 :, :, :, 6]。同样x4d[..., 4]相当于A[:, :, :, 4]。考虑下面的程序来清楚地了解数组切片的概念。这个程序演示了一维和二维数组的切片:

import numpy as np
x = np.array([1,12, 25, 8, 15, 35, 50, 7, 2, 10])
x[3:7]
x[1:9:2]
x[0:9:3]

x2d = np.array((  (100,200,300), 
                  (111,222,333), 
                  (123,456,789),
                  (125,457,791),
                  (127,459,793),
                  (129,461,795) ))
x2d[0:4,0:3]
x2d[0:4:2,0:3:2]

可以使用for循环对数组进行迭代。在一维数组中,我们可以使用for循环顺序获取所有元素。另一方面,可以相对于第一个轴对多维数组进行迭代。这个程序演示了如何在数组上执行迭代:

import numpy as np
x = np.array([1,12, 25, 8, 15, 35, 50, 7, 2, 10])
x2d = np.array((  (100,200,300), 
               (111,222,333), 
               (123,456,789),
               (125,457,791),
               (127,459,793),
               (129,461,795) ))
for i in x:
  print i

for row in x2d:
  print row

数组上的特殊操作(形状变化和转换)

对于改变数组的形状,我们有很多方法如ravel``reshape``resize,以及给形状属性赋予新的值。ravelreshape方法返回具有修改的形状的参数(调用对象),而调整大小和赋值修改实际的数组。ravel 方法将数组展平成 C 语言风格的数组。它返回的参数就像是一维数组,每行按顺序一个接一个地排列。

让我们借助下一个程序来讨论这些方法的影响。这个程序对二维数组执行形状操作。程序中的第一个print将显示原始数组。ravel功能将显示展平的数组。ravel功能后的print功能将再次显示原始数组,因为ravel功能不会改变原始数组。现在resize功能将数组的形状从原来的六行三列的(6,3)变为三行六列的(3,6)。因此,resize功能之后的print功能将以新的形状显示数组。

现在,我们已经对数组的原始形状((6,3))应用了reshape函数。这将以(6,3)的原始形状显示数组。但是由于reshape不改变形状,之后的print功能会打印出(3,6)形状的数组。最后,最后一种方法是将(9,2)的形状值分配给shape属性。这将改变形状为(9,2)

需要记住的最重要的一点是,在重塑的同时,新数组的总大小应该保持不变:

import numpy as np
x2d = np.array((  (100,200,300), 
                  (111,222,333), 
                  (123,456,789),
                  (125,457,791),
                  (127,459,793),
                  (129,461,795) ))
print x2d
x2d.ravel()
print x2d
x2d.resize((3,6))
print x2d
x2d.reshape(6,3)
print x2d
x2d.shape = (9,2)
print x2d

如果需要,有工具将数组转换成 Python 列表数据结构、存储文件和字符串。每个转换都有单独的方法,称为tolisttofiletostring

与数组关联的类

有许多类和子类与ndarray类相关联。这些类旨在支持特定的增强功能。在下面的段落中,我们将讨论这些类和子类。

矩阵子类

matrix类是 ndarrays 的 Python 子类。可以从其他矩阵或字符串或任何其他可以转换为数组的对象创建矩阵。matrix子类专门覆盖了运算符,比如矩阵乘法的*和矩阵幂的**matrix类中提供了几个函数来执行各种活动,如元素排序、转置计算、求矩阵元素的和、矩阵到列表的转换以及其他数据结构和数据类型。考虑下面的程序,它定义了两个矩阵,每个矩阵有三行和三列。最后,程序显示矩阵乘法的输出:

import numpy as np
a = np.matrix('1 2 3; 4 5 6; 7 8 9')
print a
b = np.matrix('4 5 6; 7 8 9; 10 11 12')
print b
print a*b

屏蔽数组

NumPy 有一个名为的模块,用于创建屏蔽数组。屏蔽数组是一个普通数组,它有一些无效的、丢失的或不需要的条目。它有两个组成部分:原始数组和一个掩码。掩码是用于确定数组值是否有效的布尔值数组。掩码中的一个true值反映数组中对应的值无效。屏蔽或无效的条目将不会用于对屏蔽数组的任何进一步计算。下一个程序演示了屏蔽数组的概念。假设原始数组x有不同人的脉率,并且有两个无效条目。为了屏蔽这些无效条目,在屏蔽中相应的值被设置为 1 ( true)。最后,我们计算原始数组和屏蔽数组的平均值。没有掩蔽,平均值是61.1,因为两个负值;掩蔽后,其余 8 个值的平均值为94.5:

import numpy as np
import numpy.ma as ma
x = np.array([72, 79, 85, 90, 150, -135, 120, -10, 60, 100])
mx = ma.masked_array(x, mask=[0, 0, 0, 0, 0, 1, 0, 1, 0, 0])
mx2 = ma.masked_array(x,mask=x<0)
x.mean()
mx.mean()
mx2.mean()

结构化/重新记录数组

NumPy 数组可以保存记录类型值。要创建一个record类型的数组,我们首先需要创建一个记录的数据类型,然后我们将使用这个数据类型作为数组元素的类型。这个记录数据类型可以使用dtype数据类型的定义来定义,然后我们可以在数组定义中使用这个dtype。考虑下面的程序,它创建了一组记录,这些记录具有城市的最低、最高和平均温度。dtype功能有两个组成部分:字段名称及其格式。本例中使用的格式是 32 位整数(i4)、32 位浮点(f4)和 30 个或更少字符的字符串(a30):

import numpy as np
rectype= np.dtype({'names':['mintemp', 'maxtemp', 'avgtemp', 'city'], 'formats':['i4','i4', 'f4', 'a30']})

a = np.array([(10, 44, 25.2, 'Indore'),(10, 42, 25.2, 'Mumbai'), (2, 48, 30, 'Delhi')],dtype=rectype)

print a[0]
print a['mintemp']
print a['maxtemp']
print a['avgtemp']
print a['city'] 

通用功能对象

一个通用功能 ( 取消 ) 是一个在逐个元素的基础上对标准进行操作的功能。它还支持广播、类型转换和许多其他重要功能。NumPy 中的广播是在不同形状的数组上操作的过程。特别是在算术运算期间,具有较小形状的数组将在较大的数组中传播,以使它们的形状兼容。通用函数是 NumPy 的ufunc类的实例。

属性

每个通用函数都有几个属性,尽管用户不能设置这些属性的值。以下是通用函数的属性。通用函数具有一些信息属性:

  • __doc__:包含ufunc功能的doc字符串。它的第一部分是根据名称、输入数量和输出数量动态生成的。它的第二部分是在创建函数时定义的,并与函数一起存储。
  • __name__:这是ufunc的名字。
  • ufunc.nin:表示输入的总数。
  • ufunc.nout:表示输出总数。
  • ufunc.nargs:这表示参数的总数,包括输入和输出。
  • ufunc.ntypes:表示定义该函数的不同类型的总数。
  • ufunc.types:这将返回一个列表,该列表包含ntypes元素,这些元素具有定义该函数的类型。
  • ufunc.identity:该函数的身份值。

方法

所有ufuncs都有五种方法,如下表所示。前四种方法只与接受两个输入参数并返回一个输出参数的 ufunc 相关。当试图调用其他 ufuncs 时,这些方法将引发ValueError异常。第五种方法允许用户使用索引执行就地操作。以下方法适用于每个 NumPy 通用功能:

  • ufunc.reduce:通过沿一个轴应用 ufunc,将数组的维数减少一。
  • ufunc.accumulate:这个累加了对所有元素应用运算符的结果。
  • ufunc.reduceat:这将对单个轴上的指定切片执行缩减。
  • ufunc.outer(A, B):对于A中的 aB中的 b ,这将 ufunc 运算符应用于所有 (a,b) 对。
  • ufunc.at:这将对指定元素的操作数执行无缓冲就地操作。

各种可用的 ufunc

NumPy 支持的 ufunc 有多个(目前 60 多个)。这些函数涵盖了各种各样的运算,包括简单的数学运算(如加、减、模和绝对值)、平方、对数、指数、三角、按位、比较和浮点函数。一般来说,使用这些函数比应用循环更好,因为它们比循环更有效。

以下程序演示了其中一些 ufuncs 的使用:

import numpy as np
x1 = np.array([72, 79, 85, 90, 150, -135, 120, -10, 60, 100])
x2 = np.array([72, 79, 85, 90, 150, -135, 120, -10, 60, 100])
x_angle = np.array([30, 60, 90, 120, 150, 180])
x_sqr = np.array([9, 16, 25, 225, 400, 625])
x_bit = np.array([2, 4, 8, 16, 32, 64])
np.greater_equal(x1,x2)
np.mod(x1,x2)
np.exp(x1)
np.reciprocal(x1)
np.negative(x1)
np.isreal(x1)
np.isnan(np.log10(x1))
np.sqrt(np.square(x_sqr))
np.sin(x_angle*np.pi/180)
np.tan(x_angle*np.pi/180)
np.right_shift(x_bit,1)
np.left_shift (x_bit,1)

在 Python 中,如果有一个值不能用数字表示,那么这个值就叫做nan。例如,如果我们在前面的程序中对x1数组操作log10 ufunc,那么作为输出,有到nan。有一个名为isnan的 ufunc 验证输入参数是nan。三角函数需要参数作为角度值,单位为度。正常的十进制值是弧度值,可以通过乘以 180/NumPy.pi 转换为度数。按位左移 1 执行参数值 2 的快速乘法。类似地,按位右移 1 对参数执行值为 2 的快速除法。通常,这些 ufuncs 对数组进行操作,如果有任何非数组参数,那么该参数将作为数组进行广播。然后,执行逐个元素的操作。这是前一个程序最后四行的情况。

NumPy 数学模块

NumPy 为特定功能增加了模块,例如线性代数、离散傅立叶变换、随机采样和矩阵代数库。这些功能捆绑在单独的模块中,如下所示:

  • numpy.linalg:这个模块支持线性代数的各种功能,比如数组和向量的内积、外积、点积;向量和矩阵的范数;线性矩阵方程的解:和矩阵求逆方法。
  • numpy.fft:离散傅里叶变换在数字信号处理中有着广泛的应用。该模块具有计算各种离散傅立叶变换的功能,包括一维、二维、多维、逆和厄米傅立叶变换。
  • numpy.matlib:这个模块包含默认情况下返回矩阵对象而不是数组的函数。这些功能包括emptyzerosoneseyerapmatrandrandnbmatmatmatrix
  • numpy.random:该模块包含从特定人群中进行随机采样的功能。有一些函数可以从给定的总体或范围中生成简单的随机数据。它还支持随机排列的生成。此外,它还有一系列支持各种基于统计分布的随机抽样数据生成的功能。

下一个程序演示了linalg模块中一些功能的使用。它计算方阵的范数、逆、行列式、特征值和右特征向量。它还通过求解两个方程的系统来演示线性方程求解器, 2x+3y=43x+4y=5 ,这是通过将它们表示为数组来完成的。最后一行的allclose函数比较传递给它的两个数组,如果它们在公差范围内元素相等,则返回trueeig方法计算正方形数组的特征值和特征向量。返回值如下:w为特征值,v为特征向量,其中v[:,i]列为w[i]的特征向量:

import numpy as np
from numpy import linalg as LA
arr2d = np.array((  (100,200,300), 
          (111,222,333), 
          (129,461,795) ))
eig_val, eig_vec = LA.eig(arr2d)
LA.norm(arr2d)
LA.det(arr2d)
LA.inv(arr2d)
arr1 = np.array([[2,3], [3,4]])
arr2 = np.array([4,5])
results = np.linalg.solve(arr1, arr2)
print results
np.allclose(np.dot(arr1, results), arr2)

随机抽样是科学和商业计算的一个重要方面。下面的程序演示了numpy随机采样模块支持的每一类功能中的一些功能。除了规模和人口,一些分布需要一些统计值,如平均值、模式和标准差。permutation函数随机置换一个序列或返回一个置换的范围,而randint函数从前两个参数给出的范围中返回随机选择的元素;元素的总数将作为第三个参数给出。其余方法从特定分布返回样本,如卡方、帕累托、标准正态和对数正态:

import numpy as np
np.random.permutation(10)
np.random.randint(20,50, size=10)
np.random.random_sample(10)
np.random.chisquare(5,10) # degree of freedom, size
alpha, location_param = 4., 2.
s = np.random.pareto(alpha, 10) + location_param

s = np.random.standard_normal(20)

mean, std_deviation = 4., 2\. 
s = np.random.lognormal(mean, std_deviation, 10)

SciPy 简介

SciPy 包含许多专用于各种科学计算应用所需的通用功能的子模块。SciPy 社区建议科学家在 SciPy 中实际实现所需功能之前,首先检查该功能是否已经实现。由于几乎所有科学计算的基本功能都已经实现,这种检查将节省科学家们在重新发明轮子时所付出的努力。此外,SciPy 模块已经针对错误和可能的错误进行了优化和测试。因此,使用它们将有利于提高性能。

SciPy 中的数学函数

SciPy 写在 NumPy 之上,扩展其功能以执行高级数学功能。NumPy 中可用的基本数学函数并没有经过重新设计来执行这些功能。我们需要在本章后续讨论的程序中使用 NumPy 函数,正如我们将看到的。

高级模块/包

SciPy 的功能被分成许多独立的特定于任务的模块。让我们逐一讨论这些模块。为简洁起见,我们将不涵盖任何模块的所有功能。相反,我们将演示 SciPy 每个模块中的一些示例。

整合

scipy.integrate子包有几种积分方法的功能,包括常微分方程的积分器。当给定函数对象时,有几种方法来集成函数。当给定固定样本时,它有积分函数的方法。

以下是给定函数对象的积分函数:

  • quad:通用集成
  • dblquad:通用双集成
  • tplquad:通用三重集成
  • nquad:通用 n 维集成
  • fixed_quad:使用高斯求积对函数(x) 进行积分 n
  • quadrature:使用高斯求积在给定公差内积分
  • romberg:使用龙贝格积分积分功能

这些是给定固定样本的积分函数:

  • cumtrapz:用梯形法则累计计算积分
  • simps:用辛普森法则从样本中计算积分
  • romb:使用龙贝格积分计算 (2**k + 1) 均匀间隔样本的积分

常微分方程系统的积分器如下:

  • odeint:常微分方程的一般积分
  • ode:使用 VODE 和 ZVODE 例程集成 ODE
  • complex_ode:将复值 ODE 转换为实值并积分

让我们讨论从前面的列表中选择方法的程序。quad函数对正负无穷大范围内两点之间的一个变量的函数进行一般积分。在下面的程序中,我们使用该函数计算第一类贝塞尔函数在 (0,20) 区间内的积分。第一类贝塞尔函数在special.jv方法中定义。以下程序的最后一行使用quad函数计算高斯积分:

import numpy as np
from scipy import special
from scipy import integrate

result = integrate.quad(lambda x: special.jv(4,x), 0, 20)
print result 
print "Gaussian integral", np.sqrt(np.pi),quad(lambda x: np.exp(-x**2),-np.inf, np.inf)

如果要集成的函数需要额外的参数,例如变量的乘法或幂因子,那么这些参数可以作为参数传递。这在下面的程序中进行了演示,通过将abc作为参数传递给quad函数。有时,积分可能发散或收敛非常慢:

import numpy as np
from scipy.integrate import quad

def integrand(x, a, b, c):
  return a*x*x+b*x+c

a = 3
b = 4 
c = 1
result = quad(integrand, 0,np.inf,  args=(a,b,c))
print result

可以分别使用dblquadtplquad功能进行双重和三重积分。下一个程序演示了dblquad功能的使用。tx的参数从0到无穷大(inf不等。注释后的代码在固定间隔内执行高斯求积:

import numpy as np
from scipy.integrate import quad, dblquad, fixed_quad

def integrand1 (t, x, n):
  return np.exp(-x*t) / t**n

n = 4
result = dblquad(lambda t, x: integrand1(t, x, n), 0, np.inf, lambda x: 0, lambda x: np.inf)
# the following code is performing Gaussian quadrature over a fixed interval
from scipy.integrate import fixed_quad, quadrature

def integrand(x, a, b):
  return a * x + b
a = 2
b = 1
fixed_result = fixed_quad(integrand, 0, 1, args=(a,b))
result  = quadrature(integrand, 0, 1, args=(a,b))

对于函数与任意间隔样本的积分,我们有simps函数。辛普森法则将三个相邻点之间的函数近似为抛物线。以下程序使用simps功能:

import numpy as np
from scipy.integrate import simps
def func1(a,x):
  return a*x**2+2

def func2(b,x):
  return b*x**3+4

x = np.array([1, 2, 4, 5, 6])
y1 = func1(2,x)
Intgrl1 = simps(y1, x)

print(Intgrl1)

y2 = func2(3,x)
Intgrl2 = simps (y2,x)
print (Intgrl2)

这里有一个程序,演示了使用odeint函数积分常微分方程:

import matplotlib.pyplot as plt
from numpy import linspace, array
def derivative(x,time): 
  a = -2.0
  b = -0.1
  return array([  x[1], a*x[0]+b*x[1] ])

time = linspace (1.0,15.0,1000)
xinitialize = array ([1.05,10.2]) 
x = odeint(derivative,xinitialize,time)
plt.figure()
plt.plot(time,x[:,0]) 
plt.xlabel('t')
plt.ylabel('x')
plt.show()

信号处理

信号处理工具箱包含许多滤波函数、滤波器设计函数以及用于一维和二维数据的几种 B 样条插值算法的函数。该工具箱有几个用于执行以下操作的功能:

  • 盘旋
  • b 样条
  • 过滤
  • 滤波器设计
  • Matlab 风格的 IIR 滤波器设计
  • 连续时间线性系统
  • 离散时间线性系统
  • LTI 代表处
  • 波形
  • 窗口功能
  • 小波
  • 峰值发现
  • 光谱分析

让我们讨论一些示例程序来理解信号处理工具箱的功能。

detrend函数是一个过滤函数,从数据中去除沿轴的恒定或线性趋势,以便我们可以看到高阶的效果,如以下程序所示:

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from scipy import signal
t = np.linspace(0, 5, 100)
x = t + np.random.normal(size=100)
plt.plot(t, x, linewidth=3)
plt.show()
plt.plot(t, signal.detrend(x), linewidth=3)
plt.show()

下面的程序使用样条滤波,使用misc.lena命令计算作为数组的 Lena 脸部的边缘图像。该功能通过使用两个功能来实现。首先,cspline2d命令用于将具有镜像对称边界条件的可分离二维 FIR 滤波器应用于样条系数。该函数比第二个函数convolve2d更快,后者卷积任意二维滤波器,并允许您选择镜像对称边界条件:

import numpy as np
from scipy import signal, misc
import matplotlib.pyplot as plt
img = misc.lena()

splineresult = signal.cspline2d(img, 2.0)
arr1 = np.array([[-1,0,1], [-2,0,2], [-1,0,1]], dtype=np.float32)
derivative = signal.convolve2d(splineresult,arr1,boundary='symm' ,mode='same')
plt.figure()
plt.imshow(derivative)
plt.title('Image filtered by spline edge filter')
plt.gray()
plt.show()

傅里叶变换

实数或复数序列的离散傅里叶变换和离散逆傅里叶变换可分别使用fftifft(快速傅里叶变换)计算,如本程序所示:

import numpy as np
from scipy.fftpack import fft, ifft
x = np.random.random_sample(5) 
y = fft(x)
print y
yinv = ifft(y)
print yinv

以下程序绘制了三个正弦之和的快速傅立叶变换:

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from scipy.fftpack import fft
x = np.linspace(0.0, 1, 500)
y = np.sin(100*np.pi*x) + 0.5*np.sin(150*np.pi*x) + 0.75*np.sin(200*np.pi*x)
yf = fft(y)
xf = np.linspace(0.0, 0.1, 250)
import matplotlib.pyplot as plt
plt.plot(xf, 2.0/500 * np.abs(yf[0:500/2]))
plt.grid()
plt.show()

空间数据结构和算法

空间分析是一套用于分析空间数据的技术和算法。与地理空间或地平线相关的数据对象或元素可以称为空间数据。这些数据由点、线、多边形和其他几何和地理图元组成,这些图元可以通过位置进行映射,并用于跟踪和定位各种设备。它可以是提供关于地理或空间位置的特定信息的标量或矢量数据。空间数据由不同领域的许多应用使用和处理,如地理、地理信息系统/检索、基于位置的服务、基于网络和桌面的空间应用、空间挖掘等。

一个 k 维树 ( k-d 树)是一个空间划分的数据结构。它在 k 维空间中组织点。在数学中,空间划分是将一个空间划分为多个不相交空间的过程。它将空间划分为不重叠的区域,其中空间中的每个点可能恰好属于一个区域。

SciPy 有一个空间模块,支持空间计算的各种所需功能。用户可以计算 N 维的德劳奈三角剖分、沃罗诺伊图和凸包。它也有绘图助手来绘制这些二维计算。此外,为了执行快速最近邻查找,它还支持 KDTree 功能,并且具有从原始观察向量集合中计算远处矩阵的功能。

让我们讨论一些展示这些功能的示例程序。以下程序执行德劳奈三角测量,然后使用pyplot绘制计算结果:

import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import Delaunay
arr_pt = np.array([[0, 0], [0, 1.1], [1, 0], [1, 1]])
arr1 = np.array([0., 0., 1., 1.])
arr2 = np.array([0., 1.1, 0., 1.])

triangle_result = Delaunay(arr_pt)
plt.triplot(arr1, arr2, triangle_result.simplices.copy())
plt.show()
plt.plot(arr1, arr2, 'ro')
plt.show()

包含给定点集中所有点的最小凸对象称为凸包,可以使用convexHull函数计算。下一个程序演示了该函数的使用,然后绘制了使用convexHull函数的计算结果:

import numpy as np
from scipy.spatial import ConvexHull
import matplotlib.pyplot as plt
randpoints = np.random.rand(25, 2) 
hull = ConvexHull(randpoints)
#following line will draw points
plt.plot(randpoints[:,0], randpoints[:,1], 'x')
#this loop will draw the line segment
for simplex in hull.simplices:
  plt.plot(randpoints[simplex,0], randpoints[simplex,1], 'k')

plt.show()

我们可以使用 KDTree 来找出点集中哪个点最接近所选点。这个程序演示了 k-d 树的使用:

from scipy import spatial
x_val, y_val = np.mgrid[1:5, 3:9]
tree_create = spatial.KDTree(zip(x_val.ravel(), y_val.ravel()))
tree_create.data
points_for_query = np.array([[0, 0], [2.1, 2.9]])
tree_create.query(points_for_query)

以下程序显示最近距离和索引:

import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import KDTree
vertx = np.array([[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]])
tree_create = KDTree(vertx)
tree_create.query([1.1, 1.1])
x_vals = np.linspace(0.5, 3.5, 31)
y_vals = np.linspace(0.5, 3.5, 33)
xgrid, ygrid = np.meshgrid(x, y)
xy = np.c_[xgrid.ravel(), ygrid.ravel()]
plt.pcolor(x_vals, y_vals, tree.query(xy)[1].reshape(33, 31))
plt.plot(points[:,0], points[:,1], 'ko')
plt.show()

优化

优化是为一个或多个变量的目标函数寻找最佳解的过程,可能在这些变量上存在一些预定义的约束,也可能在这些变量上存在一些预定义的约束。目标函数可以被认为是最小化的成本/能量函数或最大化的利润或效用函数。有几个与优化问题相关的重要概念,例如优化问题的维数和优化的类型。在解决优化问题之前,最好先了解这些概念,然后再开始解决方案。对于问题的维数,我们指的是执行优化值搜索的标量变量的数量。变量的数量可以是一个或多个。变量的数量也会影响解决方案的可伸缩性。标量变量越多,问题越慢。此外,优化的类型也会影响解决方案的设计。

另一个重要的考虑是这个问题是否是一个约束问题。通过约束问题,我们意味着解决方案必须满足对所研究的变量的一些预先定义的约束。例如,我们可以写一个一般约束最小化优化问题如下:

Minimize                           f(x)
Subjected to constraints    gi (x)= ai     for i= 1 … … n
                                        Hj (x)>= bj     for j= 1 … … m

解决方案需要满足这些约束。问题的解决取决于目标函数、约束和变量之间的关系。此外,模型的大小也会影响解决方案。模型的大小由变量的数量和约束的数量来衡量。通常,模型的大小有一个上限,这是由大多数优化求解软件应用强加的。由于更高的内存要求、问题的处理要求及其数值稳定性,必须引入该限制。可能我们根本找不到解决方案,或者获得解决方案可能非常耗时,这给人的印象是解决方案没有收敛。

此外,优化问题可以是凸或非凸问题。凸问题相对更容易解决,因为它有一个全局最小值/最大值,而没有局部最小值/最大值。

让我们详细讨论一下凸性的概念。凸优化是在凸集上最小化convex函数的过程。如果图形上任意两点之间的线段位于图形之上,则为区间定义的convex函数(它保存实数值)称为convex函数。两个流行的convex函数是指数函数( f(x)=ex )和二次函数( f(x)=x2 )。convex和非凸函数的一些例子如图所示:

Optimization (scipy.optimize)

现在,凸集是这样一个区域,如果我们用一条线段连接它里面的两个点,那么这条线段上的所有点也位于这个区域里面。下图描述了convex和非凸集:

Optimization (scipy.optimize)

scipy.optimize包为标量和多维函数最小化、曲线拟合和求根的大多数有用算法提供了函数。让我们讨论如何使用这些函数。

下一个程序演示了布赖登-弗莱彻-戈德法布-沙诺 ( BFGS ) 算法的使用。该算法利用目标函数的梯度快速收敛到解。程序首先定义一个名为rosen_derivative的函数来计算rosenbrock函数的梯度:

import numpy as np
from scipy.optimize import minimize
def rosenbrock(x):
  return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0)

x0 = np.array([1.3, 0.7, 0.8, 1.9, 1.2])

def rosen_derivative(x):
  x1 = x[1:-1]
  x1_m1 = x[:-2]
  x1_p1 = x[2:]
  derivative = np.zeros_like(x)
  derivative[1:-1] = 200*(x1-x1_m1**2) - 400*(x1_p1 - x1**2)*x1 - 2*(1-x1)
  derivative[0] = -400*x[0]*(x[1]-x[0]**2) - 2*(1-x[0])
  derivative[-1] = 200*(x[-1]-x[-2]**2)
  return derivative

res = minimize(rosenbrock, x0, method='BFGS', jac=rosen_derivative, options={'disp': True})

下面的程序首先计算罗森布鲁克函数的海森,然后使用牛顿共轭梯度法最小化该函数:

import numpy as np
from scipy.optimize import minimize

def rosenbrock(x):
  return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0)

x0 = np.array([1.3, 0.7, 0.8, 1.9, 1.2])

def rosen_derivative(x):
  x1 = x[1:-1]
  x1_m1 = x[:-2]
  x1_p1 = x[2:]
  derivative = np.zeros_like(x)
  derivative[1:-1] = 200*(x1-x1_m1**2) - 400*(x1_p1 - x1**2)*x1 - 2*(1-x1)
  derivative[0] = -400*x[0]*(x[1]-x[0]**2) - 2*(1-x[0])
  derivative[-1] = 200*(x[-1]-x[-2]**2)
  return derivative

def rosen_hessian(x):
  x_val = np.asarray(x)
  hess = np.diag(-400*x_val[:-1],1) - np.diag(400*x_val[:-1],-1)
  diagonal = np.zeros_like(x_val)
  diagonal[0] = 1200*x_val[0]**2-400*x_val[1]+2
  diagonal[-1] = 200
  diagonal[1:-1] = 202 + 1200*x_val[1:-1]**2 - 400*x_val[2:]
  hess = hess + np.diag(diagonal)
  return hess

result = minimize(rosenbrock, x0, method='Newton-CG', jac=rosen_derivative, hess=rosen_hessian, options={'xtol': 1e-8, 'disp': True})
print result.x

minimize函数还有一个接口,可以连接到许多约束最小化算法。以下程序使用顺序最小二乘编程优化 ( SLSQP )算法。要最小化的函数在func中定义,其导数在func_deriv中定义,约束在cons变量中定义:

import numpy as np
from scipy.optimize import minimize
def func(x, sign=1.0):
  return sign*(2*x[0]*x[1] + 2*x[0] - x[0]**2 - 2*x[1]**2)

def func_deriv(x, sign=1.0):
  dfdx0 = sign*(-2*x[0] + 2*x[1] + 2)
  dfdx1 = sign*(2*x[0] - 4*x[1])
  return np.array([ dfdx0, dfdx1 ])

cons = ({'type': 'eq',
  'fun': lambda x: np.array([x[0]**3 - x[1]]),
  'jac': lambda x: np.array([3.0*(x[0]**2.0), -1.0])},
  {'type': 'ineq',
  'fun': lambda x: np.array([x[1] - 1]),
  'jac': lambda x: np.array([0.0, 1.0])})

res = minimize(func, [-1.0,1.0], args=(-1.0,), jac=func_deriv, method='SLSQP', options={'disp': True})
print(res.x)

res = minimize(func, [-1.0,1.0], args=(-1.0,), jac=func_deriv,constraints=cons, method='SLSQP', options={'disp': True})
print(res.x)

下一个程序演示了寻找全局最小值和局部最小值的方法。首先,它定义了函数并绘制了图。该函数在-1.3附近有一个全局最小值,在3.8附近有一个局部最小值。使用 BFGF 算法来寻找局部最小值。该程序使用强力算法来寻找全局最小值。但是,随着网格大小(要检查的值的范围/域)的增加,蛮力方法会变得很慢,因此最好对标量函数使用布伦特方法。该程序还使用fminbound函数来寻找 0 到 10 之间的局部最小值:

import numpy as np
import matplotlib.pyplot as plt
from scipy import optimize

def f(x):
  return x**2 + 10*np.sin(x)

x = np.arange(-10,10,0.1)
plt.plot(x, f(x))
plt.show()

optimize.fmin_bfgs(f, 0)

grid = (-10, 10, 0.1)
optimize.brute(f, (grid,))
optimize.brent(f)
optimize.fminbound(f, 0, 10)

以下程序演示了约束优化的使用:

import numpy as np
from scipy import optimize
def f(x):
     return np.sqrt((x[0] - 2)**2 + (x[1] - 3)**2)

def constraint(x):
     return np.atleast_1d(2.5 - np.sum(np.abs(x)))

optimize.fmin_slsqp(f, np.array([0, 2]), ieqcons=[constraint, ])
optimize.fmin_cobyla(f, np.array([3, 4]), cons=constraint)

有几种方法可以找到多项式的根,接下来的三个程序使用平分法、牛顿-拉夫森法和根函数。本程序采用二等分法求polynomial_func中定义的多项式的根:

import scipy.optimize as optimize
import numpy as np

def polynomial_func(x):
    return np.cos(x)**3 + 4 - 2*x

print(optimize.bisect(polynomial_func, 1, 5))

牛顿-拉夫森法用于在以下程序中寻找多项式的根:

import scipy.optimize
from scipy import optimize

def polynomial_func(xvalue):
  yvalue = xvalue + 2*scipy.cos(xvalue)
        return yvalue

scipy.optimize.newton(polynomial_func,  1)

在数学中,拉格朗日乘子法被用来寻找函数的局部最小值和局部最大值,服从等式约束。该程序使用fsolve方法计算拉格朗日乘数:

import numpy as np
from scipy.optimize import fsolve
def func_orig(data):
    xval = data[0]
    yval = data[1]
    Multiplier = data[2]
    return xval + yval + Multiplier * (xval**2 + yval**2 - 1)

def deriv_func_orig(data):
    dLambda = np.zeros(len(data))
    step_size = 1e-3 # this is the step size used in the finite difference.
    for i in range(len(data)):
        ddata = np.zeros(len(data))
        ddata[i] = step_size
        dLambda[i] = (func_orig(data+ddata)-func_orig(data-ddata))/(2*step_size);
    return dLambda

data1 = fsolve(deriv_func_orig, [1, 1, 0])
print data1, func_orig(data1)

data2 = fsolve(deriv_func_orig, [-1, -1, 0])
print data2, func_orig(data2)

插值

插值是一种在已知数据点的离散集合范围内寻找新数据点的方法。interpolate子包具有插值器,用于使用各种插值方法进行计算。它支持使用spline函数、univariatemultivariate一维和多维插值、拉格朗日和泰勒多项式插值器的插值。它也有用于FITPACKDFITPACK函数的包装类。让我们讨论一些演示这些方法使用的程序。

这个程序演示了使用线性插值和三次插值的一维插值,并绘制它们进行比较:

import numpy as np
from scipy.interpolate import interp1d
x_val = np.linspace(0, 20, 10)
y_val = np.cos(-x**2/8.0)
f = interp1d(x_val, y_val)
f2 = interp1d(x_val, y_val, kind='cubic')
xnew = np.linspace(0, 20, 25)
import matplotlib.pyplot as plt
plt.plot(x,y,'o',xnew,f(xnew),'-', xnew, f2(xnew),'--')
plt.legend(['data', 'linear', 'cubic'], loc='best')
plt.show()

以下程序演示了使用griddata函数进行 150 点多变量数据插值。这个点数可以更改为任何合适的值。程序使用pyplot在单个剧情中创建四个支线剧情:

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata

def func_user(x, y):
  return x*(1-x)*np.cos(4*np.pi*x) * np.sin(4*np.pi*y**2)**2

x, y = np.mgrid[0:1:100j, 0:1:200j]

points = np.random.rand(150, 2)
values = func_user(points[:,0], points[:,1])
grid_z0 = griddata(points, values, (x, y), method='nearest')
grid_z1 = griddata(points, values, (x, y), method='linear')
grid_z2 = griddata(points, values, (x, y), method='cubic')

f, axarr = plt.subplots(2, 2)
axarr[0, 0].imshow(func(x, y).T, extent=(0,1,0,1), origin='lower')
axarr[0, 0].plot(points[:,0], points[:,1], 'k', ms=1)
axarr[0, 0].set_title('Original')

axarr[0, 1].imshow(grid_z0.T, extent=(0,1,0,1), origin='lower')
axarr[0, 1].set_title('Nearest')

axarr[1, 0].imshow(grid_z1.T, extent=(0,1,0,1), origin='lower')
axarr[1, 0].set_title('Linear')

axarr[1, 1].imshow(grid_z2.T, extent=(0,1,0,1), origin='lower')
axarr[1, 1].set_title('Cubic')

plt.show()

线性代数

scipy线性代数方法期望一个参数作为一个可以转换成二维数组的对象。这些方法还返回一个二维数组。与numpy.linalg相比,scipy.linalg功能具有更高级的功能。

以下程序计算表示为二维数组的矩阵的逆矩阵。它还使用T(转置的快捷方式)并在数组上执行乘法:

import numpy as np
from scipy import linalg
A = np.array([[2,3],[4,5]])
linalg.inv(A)
B = np.array([[3,8]]) 
A*B 
A.dot(B.T)

这个小程序计算矩阵的逆矩阵及其行列式:

import numpy as np
from scipy import linalg
A = np.array([[2,3],[4,5]])
linalg.inv(A)
linalg.det(A)

下一个程序演示了如何使用矩阵求逆来求解线性方程,以及如何使用求解器来快速实现:

import numpy as np
from scipy import linalg
A = np.array([[2,3],[4,5]])
B = np.array([[5],[6]])
linalg.inv(A).dot(B)
np.linalg.solve(A,B)

以下程序寻找一组线性比例系数,并使用模型拟合该数据。本程序使用linalg.lstsq解决数据拟合问题。lstsq方法用于求线性矩阵方程的最小二乘解。该方法是为给定数据点寻找最佳拟合线的工具。它使用线性代数和简单微积分:

import numpy as np
from scipy import linalg
import matplotlib.pyplot as plt
coeff_1, coeff_2 = 5.0, 2.0
i = np.r_[1:11]  # or we can use np.arang(1, 11)
x = 0.1*i
y = coeff_1*np.exp(-x) + coeff_2*x
z = y + 0.05 * np.max(y) * np.random.randn(len(y))

A = np.c_[np.exp(-x)[:, np.newaxis], x[:, np.newaxis]]
coeff, resid, rank, sigma = linalg.lstsq(A, zi) 

x2 = np.r_[0.1:1.0:100j]
y2 = coeff[0]*np.exp(-x2) + coeff[1]*x2

plt.plot(x,z,'x',x2,y2)
plt.axis([0,1,3.0,5.5])
plt.title('Data fitting with linalg.lstsq')
plt.show()

以下程序演示了奇异值分解的方法以及linag.svdlinag.diagsvd函数:

import numpy as np
from scipy import linalg
A = np.array([[5,4,2],[4,8,7]])
row = 2
col = 3
U,s,Vh = linalg.svd(A)
Sig = linalg.diagsvd(s,row,col)
U, Vh = U, Vh
print U
print Sig
print Vh

利用 ARPACK 求解稀疏特征值问题

该程序计算标准特征值分解和相应的特征向量:

import numpy as np
from scipy.linalg import eigh
from scipy.sparse.linalg import eigsh
#following line is suppressing the values after decimal
np.set_printoptions(suppress=True)

np.random.seed(0)
random_matrix = np.random.random((75,75)) - 0.5
random_matrix = np.dot(random_matrix, random_matrix.T) 
#compute eigenvalues decomposition
eigenvalues_all, eigenvectors_all = eigh(random_matrix)

eigenvalues_large, eigenvectors_large = eigsh(random_matrix, 3, which='LM')
print eigenvalues_all[-3:]
print eigenvalues_large
print np.dot(eigenvectors_large.T, eigenvectors_all[:,-3:])

如果我们尝试使用eigenvalues_small, eigenvectors_small = eigsh(random_matrix, 3, which='SM')来寻找具有最小值的特征值,在这种情况下,系统返回一个没有convergence的错误。解决这个问题有几个选择。第一种解决方案是通过将tol=1E-2传递给eigsh函数来增加公差极限,如下所示:eigenvalues_small, eigenvectors_small = eigsh(random_matrix, 3, which='SM', tol=1E-2)。这将解决问题,但会导致精度下降。

另一种解决方案是将maxiter=5000传递给eigsh函数,将最大迭代次数增加到 5000 次,如下所示:eigenvalues_small, eigenvectors_small = eigsh(random_matrix, 3, which='SM', maxiter=5000)。然而,更多的迭代将花费更长的时间,并且有更好的方法以期望的精度快速解决这个问题。使用sigma=02which='LM'参数使用换档模式,如下所示:eigenvalues_small, eigenvectors_small = eigsh(random_matrix, 3, sigma=0, which='LM')

统计数据

有许多统计函数是为处理数组而设计的,它们的特殊版本是为处理屏蔽数组而设计的。后续段落中的程序演示了连续和离散概率分布的一些可用函数的使用。

以下程序使用离散二项式随机变量并绘制其概率质量函数。下面是二项式离散分布的概率质量函数:

binom.pmf(k) = choose(n, k) * p**k * (1-p)**(n-k)

在前面的代码中,k 在(0,1,...,n),n 和 p 是形状参数:

import numpy as np
from scipy.stats import binom
import matplotlib.pyplot as plt

n, p = 5, 0.4
mean, variance, skewness, kurtosis = binom.stats(n, p, moments='mvsk')
x_var = np.arange(binom.ppf(0.01, n, p),binom.ppf(0.99, n, p))

plt.plot(x_var, binom.pmf(x_var, n, p), 'ro', ms=5, label='PMF of binomial ')
plt.vlines(x_var, 0, binom.pmf(x_var, n, p), colors='r', lw=3, alpha=0.5)
plt.show()

下一个程序演示了几何离散随机变量的使用,并绘制了概率质量函数:

geom.pmf(k) = (1-p)**(k-1)*p

这里k>= 1**p为形状参数:

import numpy as np
from scipy.stats import geom
import matplotlib.pyplot as plt

p = 0.5
mean, variance, skewness, kurtosis = geom.stats(p, moments='mvsk')
x_var = np.arange(geom.ppf(0.01, p),geom.ppf(0.99, p))
plt.plot(x_var, geom.pmf(x_var, p), 'go', ms=5, label='PMF of geomatric')
plt.vlines(x_var, 0, geom.pmf(x_var, p), colors='g', lw=3, alpha=0.5)

plt.show()

以下程序演示了广义帕累托连续随机变量的计算,并绘制了其概率密度函数:

genpareto.pdf(x, c) = (1 + c * x)**(-1 - 1/c)
Here, x >= 0 if c >=0 and 0 <= x <= -1/c if c < 0:
import numpy as np
from scipy.stats import genpareto
import matplotlib.pyplot as plt
c = 0.1
mean, variance, skewness, kurtosis  = genpareto.stats(c, moments='mvsk')
x_val = np.linspace(genpareto.ppf(0.01, c),genpareto.ppf(0.99, c), 100)
plt.plot(x_val, genpareto.pdf(x_val, c),'b-', lw=3, alpha=0.6, label='PDF of Generic Pareto')
plt.show()
plt.show()

下一个程序显示了广义伽马连续随机变量的计算,并绘制了其概率密度函数:

gengamma.pdf(x, a, c) = abs(c) * x**(c*a-1) * exp(-x**c) / gamma(a)

这次, r x > 0a > 0 ,以及 c!= 0 。这里 ac 是形状参数:

import numpy as np
from scipy.stats import gengamma
import matplotlib.pyplot as plt
a, c = 4.41623854294, 3.11930916792
mean, variance, skewness, kurtosis   = gengamma.stats(a, c, moments='mvsk')
x_var = np.linspace(gengamma.ppf(0.01, a, c),gengamma.ppf(0.99, a, c), 100)
plt.plot(x_var, gengamma.pdf(x_var, a, c),'b-', lw=3, alpha=0.6, label='PDF of generic Gamma')
plt.show()

以下程序演示了多元正态随机变量的计算,并绘制了其概率密度函数。为简单起见,我们跳过概率密度函数:

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import multivariate_normal
x_var = np.linspace(5, 25, 20, endpoint=False)
y_var = multivariate_normal.pdf(x_var, mean=10, cov=2.5)
plt.plot(x_var, y_var)
plt.show()

我们还可以冻结这些统计分布,以显示冻结的概率分布/质量函数。

多维图像处理

通常,图像处理和图像分析可以被认为是对二维值数组执行操作。这个包提供了许多应用于数组的图像处理和图像分析功能。下面的代码适用于莉娜的形象。首先,程序在图像中引入一些噪声,然后使用一些过滤器来清除噪声。它使用高斯、中值和signal.wiener过滤器显示有噪声的图像和过滤后的图像:

import numpy as np
from scipy import signal
from scipy import misc
from scipy import ndimage
import matplotlib.pyplot as plt

lena = misc.lena()
noisy_lena = np.copy(lena).astype(np.float)
noisy_lena += lena.std()*0.5*np.random.standard_normal(lena.shape)
f, axarr = plt.subplots(2, 2)
axarr[0, 0].imshow(noisy_lena, cmap=plt.cm.gray)
axarr[0, 0].axis('off')
axarr[0, 0].set_title('Noissy Lena Image')
blurred_lena = ndimage.gaussian_filter(noisy_lena, sigma=3)
axarr[0, 1].imshow(blurred_lena, cmap=plt.cm.gray)
axarr[0, 1].axis('off')
axarr[0, 1].set_title('Blurred Lena')
median_lena = ndimage.median_filter(blurred_lena, size=5)
axarr[1, 0].imshow(median_lena, cmap=plt.cm.gray)
axarr[1, 0].axis('off')
axarr[1, 0].set_title('Median Filter Lena')
wiener_lena = signal.wiener(blurred_lena, (5,5))
axarr[1, 1].imshow(wiener_lena, cmap=plt.cm.gray)
axarr[1, 1].axis('off')
axarr[1, 1].set_title('Wiener Filter Lena')
plt.show()

上一个程序的输出显示在这个截图中:

Multidimensional image processing (scipy.ndimage)

聚类

聚类是将一大组对象放入多个组的过程。它使用一些参数,使得一个组(称为集群)中的对象比其他组或集群中的对象更相似。

Clustering

分组为四组的对象

SciPy 聚类包有两个模块:矢量量化 ( VQ )和层次结构。VQ 模块支持 k 均值和矢量量化。层次模块支持层次聚类和聚集聚类。

让我们简单了解一下这些算法:

  • 矢量量化 : VQ 是一种信号处理技术,使其用户能够通过原型矢量的分布来建模概率密度函数。它通过将一大组向量或点分成多个组来执行这种建模,这些组在其附近具有大致相同数量的点。每组都有一个代表性的质心点。
  • k-means : k-means 是一种取自信号处理的矢量量化技术,广泛应用于聚类分析,并广受欢迎。它将 n 个观测值划分为 k 个聚类,每个观测值都属于平均值最近的聚类。
  • 层次聚类:这种聚类技术试图从观察结果中建立一个聚类层次。分层聚类技术通常属于以下两种类型:
    • 可分聚类:这是一种自上而下创建聚类层次的方法。它从最上面的一个集群开始,向下移动时执行拆分。
    • 聚集聚类:这是一种自下而上的方法。每个观察都是一个集群,这种技术在向上移动时执行这种集群的配对。

通常,分层聚类的结果以树形图(即树形图)描述,如下所示:

Clustering

以下程序演示了 k 均值聚类和矢量量化的示例:

from scipy.cluster.vq import kmeans,vq
from numpy.random import rand
from numpy import vstack,array
from pylab import plot,show

data_set = vstack((rand(200,2) + array([.5,.5]),rand(200,2)))

# K-Means computation for 2 clusters
centroids_of_clusters,_ = kmeans(data_set,2)
index,_ = vq(data_set,centroids_of_clusters)

plot(data_set[index==0,0],data_set[index==0,1],'ob',
     data_set[index==1,0],data_set[index==1,1],'or')
plot(centroids_of_clusters[:,0],centroids_of_clusters[:,1],'sg',markersize=8)

show()

# The same data for 3 clusters
centroids_of_clusters,_ = kmeans(data_set,3)
index,_ = vq(data_set,centroids_of_clusters)

plot(data_set[index==0,0],data_set[index==0,1],'ob',
     data_set[index==1,0],data_set[index==1,1],'or',
     data_set[index==2,0],data_set[index==2,1],'og') # third cluster points
plot(centroids_of_clusters[:,0],centroids_of_clusters[:,1],'sm',markersize=8)
show()

分层的聚类模块具有分成许多类别的许多功能,例如用于将分层聚类切割成平面聚类的功能、用于聚集聚类的例程、用于聚类可视化的例程、数据结构和用于将层次表示为树结构的例程、用于计算层次统计的例程、用于检查链接有效性和不稳定性度量的谓词功能等等。使用分层模块的linkage(凝聚聚类)和dendrogram功能,以下程序用于绘制样本数据的树形图:

import numpy
from numpy.random import rand
from matplotlib.pyplot import show
from scipy.spatial.distance import pdist
import scipy.cluster.hierarchy as sch

x = rand(8,80)
x[0:4,:] *= 2

y = pdist(x)
z = sch.linkage(y)
sch.dendrogram(z)
show()

输出描述如下:

Clustering

曲线拟合

构建对一系列数据点具有最佳拟合的数学函数或曲线的过程称为曲线拟合。通常,这种曲线拟合受到一些限制。当没有数据可用时,曲线拟合的输出可用于数据可视化,以深入了解函数。曲线拟合也可以用来观察多个变量之间的关系。我们可以对不同类型的曲线使用曲线拟合,如直线、多项式、圆锥曲线、三角函数、圆、椭圆等。

这个程序首先创建一些带有噪声的随机数据。然后定义一个表示模型的函数(line_func)并进行曲线拟合。接下来确定实际参数,ab。最后,它还绘制了错误:

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

xdata = np.random.uniform(0., 50., 80)
ydata = 3\. * xdata + 2\. + np.random.normal(0., 5., 80)
plt.plot(xdata, ydata, '.')

def line_func(x, a, b):
    return a * x + b

opt_param, cov_estimated = curve_fit(line_func, xdata, ydata)

errors = np.repeat(5., 80)
plt.errorbar(xdata, ydata, yerr=errors, fmt=None)

opt_param, cov_estimated = curve_fit(line_func, xdata, ydata, sigma=errors)

print "a =", opt_param[0], "+/-", cov_estimated[0,0]**0.5
print "b =", opt_param[1], "+/-", cov_estimated[1,1]**0.5

plt.errorbar(xdata, ydata, yerr=errors, fmt=None)

xnew = np.linspace(0., 50., 80)  
plt.plot(xnew, line_func(xnew, opt_param[0], opt_param[1]), 'r-')
plt.errorbar(xdata, ydata, yerr=errors, fmt=None)
plt.plot(xnew, line_func(xnew, *opt_param), 'r-')
plt.show()

以下程序拟合 cos 三角函数的曲线:

import numpy as np
from scipy import optimize
import pylab as pl

np.random.seed(0)

def func(x, omega, p):
    return np.cos(omega * x + p)

x = np.linspace(0, 10, 100)
y = f(x, 2.5, 3) + .1*np.random.normal(size=100)
params, params_cov = optimize.curve_fit(f, x, y)
t = np.linspace(0, 10, 500)
pl.figure(1)
pl.clf()
pl.plot(x, y, 'bx')
pl.plot(t, f(t, *params), 'r-')
pl.show()

文件输入/输出

SciPy 为使用模块、类和函数以各种文件格式执行读写数据提供支持:

  • Matlab 文件
  • ALD 档案
  • 矩阵市场文件
  • 未格式化的 FORTRAN 文件
  • WAV 声音文件
  • ARFF 档案
  • NetCDF 文件

该程序对 NetCDF 文件执行读写操作:

from scipy.io import netcdf
# file creation
f = netcdf.netcdf_file('TestFile.nc', 'w')
f.history = 'Test netCDF File Creation'
f.createDimension('age', 12)
age = f.createVariable('age', 'i', ('age',))
age.units = 'Age of persons in Years'
age[:] = np.arange(12)
f.close()

#Now reading the file created  
f = netcdf.netcdf_file('TestFile.nc', 'r')
print(f.history)
age = f.variables['age']
print(age.units)
print(age.shape)
print(age[-1])
f.close()

以类似的方式,我们可以对各种其他类型的文件执行读/写操作。有一个单独的子模块用于加载WEKA机器学习工具创建的文件。WEKAARFF格式存储文件,这是WEKA的标准格式。ARFF是一个可能包含数值、字符串和数据值的文本文件。以下程序读取并显示test.arff文件中存储的数据。文件内容为@relation foo@attribute width numeric@attribute height numeric@attribute color {red,green,blue,yellow,black}@data5.0,3.25,blue4.5,3.75,green3.0,4.00,red

读取和显示内容的程序如下:

from scipy.io import arff

file1 = open('test.arff')
data, meta = arff.loadarff(file1)

print data
print meta

总结

在本章中,我们详细讨论了如何使用 Python 的 NumPy 和 Scipy 包来执行数值计算。这些概念与示例程序一起呈现。这一章首先讨论了 NumPy 的基本对象,然后我们继续讨论 NumPy 的高级概念。

本章还讨论了 SciPy 的功能和模块。它涵盖了 SciPy 提供的基本和特殊功能,然后涵盖了特殊模块或子包。这是为了展示先进的概念,如优化,插值,傅里叶变换,信号处理,线性代数,统计,空间算法,图像处理,文件输入和输出。

在下一章中,我们将对符号计算进行详尽的讨论。具体来说,我们将涵盖多项式、微积分、方程求解器、离散数学、几何和物理的核心能力和扩展功能。**

六、Python 在符号计算中的应用

SymPy 包括从基本符号算术到多项式、微积分、解算器、离散数学、几何、统计和物理的功能。它主要处理三种类型的数字,即整数、实数和有理数。整数是没有小数点的整数,而实数是有小数点的数字。有理数有两部分:分子和分母。定义有理数,可以使用Ration类,需要两个数字。在这一章中,我们将借助示例程序讨论 SymPy 的概念。

我们将在本章中讨论以下主题:

  • 使用 SymPy 的计算机化代数系统
  • 核心能力和高级功能
  • 多项式、微积分和解方程
  • 离散数学、矩阵、几何、绘图、物理和统计
  • 打印功能

让我们开始讨论 SymPy 及其核心能力,包括基本算术、扩展、简化、替换、模式匹配和各种函数(例如,指数、对数、方程根、三角函数、双曲函数和特殊函数)。

符号、表达式和基本算术

在 SymPy 中,我们需要定义符号,然后才能在任何表达式中使用它们。定义一个符号非常简单。我们只需要使用Symbol类中的symbol函数来定义一个符号,如下图所示。我们可以使用evalf() / n()方法得到任意物体的float数值近似值。

以下程序使用三种方法创建符号。对于只创建一个符号,方法的名称是符号,对于创建多个符号,方法的名称是符号。创建多个符号有两种方法:一种是通过将空格分隔的符号名称传递给符号方法,另一种是通过将m0:5传递给符号方法来创建一系列符号,如m0m1m2m3m4。在第二个选项中,m0是索引的第一个值,:后面的数字5表示总共应该创建五个这样的变量。

通常,两个整数的除法会截断小数部分。为了避免这种情况,以下程序的第一行强制对两个整数执行实际浮点除法。这就是程序最后一行将3.142857142857143存储在y的原因。如果我们忽略下面程序中的第一行。那么y的价值将是3:

from __future__ import division
from sympy import *

x, y, z = symbols('x y z')
m0, m1, m2, m3, m4 = symbols('m0:5')
x1 = Symbol('x1')
x1 + 500
y=22/7

下面的程序使用evalf()n()方法将任何 SymPy 对象数值近似为一个float值。默认精度最高为 15 位小数,通过向这些方法传递一个参数,可以将其更改为任何所需的精度:

from __future__ import division
from sympy import, sin, pi

x=sin(50)

pi.evalf()
pi.evalf(50)

x.n()
x.n(20)

下一个程序演示了表达式的概念以及可以使用collectexpandfactorsimplifysubs方法对表达式执行的各种操作:

from sympy import collect, expand, factor, simplify
from sympy import Symbol, symbols
from sympy import sin, cos

x, y, a, b, c, d = symbols('x y a b c d')

expr = 5*x**2+2*b*x**2+cos(x)+51*x**2
simplify(expr)

factor(x**2+x-30)
expand ( (x-5) * (x+6) )

collect(x**3 + a*x**2 + b*x**2 + c*x + d, x)

expr = sin(x)*sin(x) + cos(x)*cos(x)
expr
expr.subs({x:5, y:25})
expr.subs({x:5, y:25}).n()

方程求解

有一个神奇的功能叫做solve。它可以求解所有类型的方程。这个函数返回一个方程的解。它需要两个参数:要求解的表达式和变量。下面的程序使用这个函数来求解各种类型的方程。在下面的等式中,假设等式的右侧为零:

from sympy import solve

solve (6*x**2 - 3*x - 30,x)

a, b, c = symbols('a b c')
solve( a*x**2 + b*x + c, x)
substitute_solution = solve( a*x**2 + b*x + c, x)
[ substitute_solution[0].subs({'a':6,'b':-3,'c':-30}), substitute_solution[1].subs({'a':6,'b':-3,'c':-30}) ]

solve([2*x + 3*y - 3, x -2* y + 1], [x, y])
)

为了求解方程组,我们有另一种形式的solve方法,该方法将方程列表作为第一个参数,将未知数列表作为第二个参数。这里展示了这一点:

from sympy import solve

solve ([2*x + y - 4, 5*x - 3*y],[x, y])
solve ([2*x + 2*y - 1, 2*x - 4*y],[x, y])

有理数、指数和对数的函数

SymPy 有许多处理有理数的函数。这些函数对有理数执行各种操作,包括简化、扩展、合并、拆分等等。SymPy 还支持指数和对数运算的几个函数。有三个对数函数:log(用来计算基数-b 的对数)ln(用来计算自然对数)log10(用来计算基数-10 的对数)。log函数需要两个参数:变量和基数。如果没有传递基数,那么默认情况下,这个函数会计算变量的自然对数,相当于ln。计算两个有理数的相加,我们使用together函数。类似地,要用分母除一个有理表达式的分子,我们使用apart函数,该函数用于以下程序:

from sympy import together, apart, symbols
x1, x2, x3, x4 = symbols('x1 x2 x3 x4')
x1/x2 + x3/x4
together(x1/x2 + x3/x4)

apart ((2*x**2+3*x+4)/(x+1))
together(apart ((2*x**2+3*x+4)/(x+1)))

exp(1)
log(4).n()
log(4,4).n()
ln(4).n()
mpmath.log10(4)

多项式

SymPy 允许我们定义和执行多项式的各种运算。我们也可以找到多项式的根。我们已经介绍了simplifyexpandfactorsolve方法。这些方法也执行多项式的功能。要检查两个多项式是否相等,我们应该使用simplify函数:

from sympy import *

p, q = symbols ('p q')
p = (x+4)*(x+2)
q = x**2 + 6*x + 8
p == q # Unsuccessful
p - q == 0 # Unsuccessful 
simplify(p - q) == 0

三角学和复数

三角函数的输入大多是弧度角,而反三角函数返回弧度角。该模块还提供了度数到弧度、弧度到度数的转换功能。除了基本的三角函数,如sincostan,SymPy 还有三角化简和展开函数。

SymPy 还支持复数,以应对不存在实数解的情况。例如,考虑这个等式: x**2+4=0 。这个方程没有实数解;其解决方案将是 -2I* 或 +2I* 。这个 I 表示-1 的平方根。以下程序演示了三角函数,并以复数形式给出了该方程的解:

from sympy import *
x, y = symbols('x y')
expr = sin(x)*cos(y)+cos(x)*sin(y)
expr_exp= exp(5*sin(x)**2+4*cos(x)**2)

trigsimp(expr)
trigsimp(expr_exp)
expand_trig(sin(x+y))
solve(x**2+4,x) #complex number as solution

线性代数

SymPy 线性代数模块是另一个非常简单的模块,它为矩阵操作提供了易于学习的功能。它具有执行各种矩阵运算的功能,包括快速特殊矩阵创建、特征值、特征向量、转置、行列式和逆。快速创建特殊矩阵有三种方法,即eyezerosoneseye方法创建一个单位矩阵,而zerosones创建所有元素分别等于 0 或 1 的矩阵。如果需要,我们可以从矩阵中删除选定的行和列。基本算术运算符,如 +- 、 *** 、 **** 也对矩阵起作用:

from sympy import *
A = Matrix( [[1, 2, 3, 4],
       [5, 6, 7, 8],
       [ 9, 10, 11, 12],
       [ 13, 14, 15, 16]] )
A.row_del(3)
A.col_del(3)

A[0,1] # display row 0, col 1 of A
A[0:2,0:3] # top-left submatrix(2x3)

B = Matrix ([[1, 2, 3],
       [5, 6, 7],
       [ 9, 10, 11]] )
A.row_join(B)
B.col_join(B)
A + B
A - B
A * B
A **2 
eye(3) # 3x3 identity matrix
zeros(3, 3) # 3x3 matrix with all elements Zeros
ones(3, 3) # 3x3 matrix with all elements Ones

A.transpose() # It is same as A.T
M = Matrix( [[1, 2, 3],
    [4, 5, 6],
    [7, 8, 10]] )
M.det()

默认情况下,矩阵的逆矩阵是通过高斯消去法计算的,我们可以指定通过 LU 分解计算逆矩阵。SymPy 中的矩阵有计算简化行梯次形式的方法(rref方法)和零空间法(nullspace方法)。如果 A 是矩阵,那么nullspace就是所有向量的集合 v ,使得 A v=0 。也可以对矩阵元素进行替换操作;我们可以用符号条目创建一个矩阵,并用实际值和其他符号替换它们。我们还可以执行特殊操作,例如 QR 分解、Gram-Schmidt 正交化器和 LU 分解:

from sympy import *
A = Matrix( [[1,2],
  [3,4]] )
A.inv()
A.inv()*A
A*A.inv()
A = Matrix( [[ 1, -2],
   [-2, 3]] )
A.eigenvals() # same as solve( det(A-eye(2)*x), x)
A.eigenvects()
A.rref() 

A.nullspace()

x = Symbol('x')
M = eye(3) * x
M.subs(x, 4)
y = Symbol('y')
M.subs(x, y)

M.inv()
M.inv("LU")  

A = Matrix([[1,2,1],[2,3,3],[1,3,2]])
Q, R = A.QRdecomposition()
Q

M = [Matrix([1,2,3]), Matrix([3,4,5]), Matrix([5,7,8])]
result1 = GramSchmidt(M)
result2 = GramSchmidt(M, True)

微积分

微积分涉及为研究任何函数的各种性质而执行的操作,包括变化率、函数的极限行为以及函数图下面积的计算。在这一节中,你将学习极限、导数、级数求和和积分的概念。以下程序使用极限函数来解决简单的极限问题:

from sympy import limit, oo, symbols,exp, cos

oo+5
67000 < oo
10/oo

x , n = symbols ('x n')
limit( ((x**n - 1)/ (x - 1) ), x, 1)

limit( 1/x**2, x, 0)
limit( 1/x, x, 0, dir="-")

limit(cos(x)/x, x, 0)
limit(sin(x)**2/x, x, 0)
limit(exp(x)/x,x,oo)

可以使用diff(func_to_be_differentiated, variable)原型的diff函数来区分任何症状表达。以下程序使用diff函数计算各种症状表达式的微分:

from sympy import diff, symbols, Symbol, exp, dsolve, subs, Function

diff(x**4, x)
diff( x**3*cos(x), x )
diff( cos(x**2), x )
diff( x/sin(x), x )
diff(x**3, x, 2)
diff( exp(x), x)

dsolve方法帮助我们求解任何一种常微分方程和常微分方程组。本程序演示了dsolve在常微分方程和边值问题中的应用:

x = symbols('x')
f = symbols('f', cls=Function) 
dsolve( f(x) - diff(f(x),x), f(x) )

#ics argument can be used to pass the boundary condition as a dictionary to dsolve method
from sympy import *
x=symbols('x')
f=symbols('f', cls=Function)
dsolve(Eq(f(x).diff(x,x), 400*(f(x)-1+2*x)), f(x), ics={f(0):5, f(2):10})
# the above line will results in f(x) = C1*e^−30x + C2*e^30x − 2x + 1

下面的程序求函数的临界点 f(x)=4x3-3x2+2x 用二阶导数求函数在区间【0,1】内的最大值:

x = Symbol('x')
f = 4*x**3-3*x**2+2*x
diff(f, x)
sols = solve( diff(f,x), x)
sols
diff(diff(f,x), x).subs( {x:sols[0]} )
diff(diff(f,x), x).subs( {x:sols[1]} )

在 SymPy 中,我们可以使用integrate函数计算定积分和不定积分。这是一个计算定积分和不定积分的程序。它将象征性地定义这些积分。为了计算实际值,我们调用积分的n()方法,如本程序最后一行所示:

from sympy import *
integrate(x**3+1, x)
integrate(x*sin(x), x)
integrate(x+ln(x), x)

F = integrate(x**3+1, x)
F.subs({x:1}) - F.subs({x:0})

integrate(x**3-x**2+x, (x,0,1))    # definite Integrals 
integrate(sin(x)/x, (x,0,pi))    # definite Integrals 
integrate(sin(x)/x, (x,pi,2*pi))  # definite Integrals 
integrate(x*sin(x)/(x+1), (x,0,2*pi)) # definite Integrals
integrate(x*sin(x)/(x+1), (x,0,2*pi)).n()

序列是取整数的函数,我们可以通过为它的 n 项指定一个表达式来定义一个序列。我们也可以用期望值来代替。下面的程序使用 SymPy 中的一些简单序列演示了序列的概念:

from sympy import *
s1_n = 1/n
s2_n = 1/factorial(n)
s1_n.subs({n:5})
[ s1_n.subs({n:index1}) for index1 in range(0,8) ]
[ s2_n.subs({n:index1}) for index1 in range(0,8) ]
limit(s1_n, n, oo)
limit(s2_n, n, oo)

其项包含变量不同阶幂的级数称为幂级数,如泰勒级数、指数级数或正弦/余弦级数。这里有一个程序,可以计算一些包含特殊函数的序列。它还使用幂级数的概念:

from sympy import *
s1_n = 1/n
s2_n = 1/factorial(n)
summation(s1_n, [n, 1, oo])
summation(s2_n, [n, 0, oo])
import math
def s2_nf(n):
  return 1.0/math.factorial(n)

sum( [s2_nf(n) for n in range(0,10)] )
E.evalf()

exponential_xn = x**n/factorial(n)
summation( exponential_xn.subs({x:5}), [x, 0, oo] ).evalf()
exp(5).evalf()
summation( exponential_xn.subs({x:5}), [x, 0, oo])

import math # redo using only python
def exponential_xnf(x,n):
  return x**n/math.factorial(n)
sum( [exponential_xnf(5.0,i) for i in range(0,35)] )

series( sin(x), x, 0, 8)
series( cos(x), x, 0, 8)
series( sinh(x), x, 0, 8)
series( cosh(x), x, 0, 8)
series(ln(x), x, 1, 6) # Taylor series of ln(x) at x=1
series(ln(x+1), x, 0, 6) # Maclaurin series of ln(x+1)

向量

实数上定义的一个 n 元组也可以称为向量。在物理和数学中,矢量是一种数学对象,它有大小、大小或长度以及方向。在 SymPy 中,向量表示为1×n行矩阵或n×1列矩阵。下面的程序演示了 SymPy 中向量计算的概念。它计算向量的转置和范数:

from sympy import *
u = Matrix([[1,2,3]]) # a row vector = 1x3 matrix
v = Matrix([[4],
[5],    # a col vector = 3x1 matrix
[6]])
v.T # use the transpose operation to
u[1] # 0-based indexing for entries
u.norm() # length of u
uhat = u/u.norm() # unit-length vec in same dir as u
uhat
uhat.norm()

下一个程序演示了点积、叉积和向量投影运算的概念:

from sympy import *
u = Matrix([ 1,2,3])
v = Matrix([-2,3,3])
u.dot(v)

acos(u.dot(v)/(u.norm()*v.norm())).evalf()
u.dot(v) == v.dot(u)
u = Matrix([2,3,4])
n = Matrix([2,2,3])
(u.dot(n) / n.norm()**2)*n  # projection of v in the n dir

w = (u.dot(n) / n.norm()**2)*n
v = u - (u.dot(n)/n.norm()**2)*n # same as u - w
u = Matrix([ 1,2,3])
v = Matrix([-2,3,3])
u.cross(v)
(u.cross(v).norm()/(u.norm()*v.norm())).n()

u1,u2,u3 = symbols('u1:4')
v1,v2,v3 = symbols('v1:4')
Matrix([u1,u2,u3]).cross(Matrix([v1,v2,v3]))
u.cross(v)
v.cross(u)

物理模块

物理模块包含从物理上解决问题所需的功能。有几个物理子模块,用于执行与矢量物理、经典力学、量子力学、光学等相关的活动。

氢波函数

这个类别下有两个功能。第一种是以哈特利原子单位计算状态 (n,l) 的能量。另一个用哈特利原子单位计算相对论性态能量 (n,l,自旋)。以下程序演示了这些功能的使用:

from sympy.physics.hydrogen import E_nl, E_nl_dirac, R_nl
from sympy import var

var("n Z")
var("r Z")
var("n l")
E_nl(n, Z)
E_nl(1)
E_nl(2, 4)

E_nl(n, l)
E_nl_dirac(5, 2) # l should be less than n
E_nl_dirac(2, 1)
E_nl_dirac(3, 2, False)
R_nl(5, 0, r) # z = 1 by default
R_nl(5, 0, r, 1)

矩阵与泡利代数

physics.matrices模块中有几个与物理相关的矩阵。以下程序演示了如何获得这些矩阵和泡利代数:

from sympy.physics.paulialgebra import Pauli, evaluate_pauli_product
from sympy.physics.matrices import mdft, mgamma, msigma, pat_matrix

mdft(4) # expression of discrete Fourier transform as a matrix multiplication
mgamma(2) # Dirac gamma matrix in the Dirac representation
msigma(2) #  Pauli matrix with (1,2,3)

# Following line computer Parallel Axis Theorem matrix to translate the inertia matrix a distance of dx, dy, dz for a body of mass m.
pat_matrix(3, 1, 0, 0)   

evaluate_pauli_product(4*x*Pauli(3)*Pauli(2))

一维和三维的量子谐振子

该模块具有用于计算一维谐振子、三维各向同性谐振子、一维谐振子的波函数和三维各向同性谐振子的径向波函数的函数。下面是一个使用本模块中可用功能的程序:

from sympy.physics.qho_1d import E_n, psi_n
from sympy.physics.sho import E_nl, R_nl
from sympy import var

var("x m omega")
var("r nu l")
x, y, z = symbols('x, y, z')

E_n(x, omega)
psi_n(2, x, m, omega)
E_nl(x, y, z)

R_nl(1, 0, 1, r)
R_nl(2, l, 1, r)

第二量化

用来分析和描述量子多体系统的概念是称为第二量子化。这个模块包含第二量子化算符的类和玻色子的状态。预定义符号可从sympy.abc导入:

from sympy.physics.secondquant import Dagger, B, Bd
from sympy.functions.special.tensor_functions import KroneckerDelta
from sympy.physics.secondquant import B, BKet, FockStateBosonKet
from sympy.abc import x, y, n
from sympy.abc import i, j, k
from sympy import Symbol
from sympy import I

Dagger(2*I)
Dagger(B(0))
Dagger(Bd(0))

KroneckerDelta(1, 2)
KroneckerDelta(3, 3)

#predefined symbols are available in abc including greek symbols like theta
KroneckerDelta(i, j)
KroneckerDelta(i, i)
KroneckerDelta(i, i + 1)
KroneckerDelta(i, i + 1 + k)

a = Symbol('a', above_fermi=True)
i = Symbol('i', below_fermi=True)
p = Symbol('p')
q = Symbol('q')
KroneckerDelta(p, q).indices_contain_equal_information
KroneckerDelta(p, q+1).indices_contain_equal_information
KroneckerDelta(i, p).indices_contain_equal_information

KroneckerDelta(p, a).is_above_fermi
KroneckerDelta(p, i).is_above_fermi
KroneckerDelta(p, q).is_above_fermi

KroneckerDelta(p, a).is_only_above_fermi
KroneckerDelta(p, q).is_only_above_fermi
KroneckerDelta(p, i).is_only_above_fermi

B(x).apply_operator(y)

B(0).apply_operator(BKet((n,)))
sqrt(n)*FockStateBosonKet((n - 1,))

高能物理

高能物理学是对任何物质的基本成分和相关力的研究。以下程序演示了本模块中定义的类和函数的使用:

from sympy.physics.hep.gamma_matrices import GammaMatrixHead
from sympy.physics.hep.gamma_matrices import GammaMatrix, DiracSpinorIndex
from sympy.physics.hep.gamma_matrices import GammaMatrix as GM
from sympy.tensor.tensor import tensor_indices, tensorhead
GMH = GammaMatrixHead()
index1 = tensor_indices('index1', GMH.LorentzIndex)
GMH(index1)

index1 = tensor_indices('index1', GM.LorentzIndex)
GM(index1)

GM.LorentzIndex.metric

p, q = tensorhead('p, q', [GMH.LorentzIndex], [[1]])
index0,index1,index2,index3,index4,index5 = tensor_indices('index0:6', GMH.LorentzIndex)
ps = p(index0)*GMH(-index0)
qs = q(index0)*GMH(-index0)
GMH.gamma_trace(GM(index0)*GM(index1))
GMH.gamma_trace(ps*ps) - 4*p(index0)*p(-index0)
GMH.gamma_trace(ps*qs + ps*ps) - 4*p(index0)*p(-index0) - 4*p(index0)*q(-index0)

p, q = tensorhead('p, q', [GMH.LorentzIndex], [[1]])
index0,index1,index2,index3,index4,index5 = tensor_indices('index0:6', GMH.LorentzIndex)
ps = p(index0)*GMH(-index0)
qs = q(index0)*GMH(-index0)
GMH.simplify_gpgp(ps*qs*qs)

index0,index1,index2,index3,index4,index5 = tensor_indices('index0:6', GM.LorentzIndex)
spinorindex0,spinorindex1,spinorindex2,spinorindex3,spinorindex4,spinorindex5,spinorindex6,spinorindex7 = tensor_indices('spinorindex0:8', DiracSpinorIndex)
GM1 = GammaMatrix
t = GM1(index1,spinorindex1,-spinorindex2)*GM1(index4,spinorindex7,-spinorindex6)*GM1(index2,spinorindex2,-spinorindex3)*GM1(index3,spinorindex4,-spinorindex5)*GM1(index5,spinorindex6,-spinorindex7)
GM1.simplify_lines(t)

力学

SymPy 有一个模块,该模块具有机械系统所需的设施和工具,能够操纵参考系、力和扭矩。以下程序计算作用在任何物体上的净力。作用在物体上的净力是作用在该物体上的所有力的总和。这是使用矢量加法来执行的,因为力是矢量:

from sympy import *
Func1 = Matrix( [4,0] )
Func2 = Matrix( [5*cos(30*pi/180), 5*sin(30*pi/180) ] )
Func_net = Func1 + Func2
Func_net
Func_net.evalf()

Func_net.norm().evalf()
(atan2( Func_net[1],Func_net[0] )*180/pi).n()

t, a, vi, xi = symbols('t vi xi a')
v = vi + integrate(a, (t, 0,t) )
v
x = xi + integrate(v, (t, 0,t) )
x

(v*v).expand()
((v*v).expand() - 2*a*x).simplify() 

如果物体上的净力是恒定的,那么这个恒定力所反映的运动就包含了恒定的加速度。下面的程序演示了这个概念。它还使用了 匀速加速运动 ( UAM )的概念。在前面的程序中,势能的概念被证明:

From the sympy import *
xi = 20 # initial position
vi = 10 # initial velocity
a = 5 # acceleration (constant during motion)
x = xi + integrate( vi+integrate(a,(t,0,t)), (t,0,t) )
x
x.subs({t:3}).n() # x(3) in [m]
diff(x,t).subs({t:3}).n() # v(3) in [m/s]

t, vi, xi, k = symbols('t vi xi k')
a = sqrt(k*t)
x = xi + integrate( vi+integrate(a,(t,0,t)), (t, 0,t) )
x

x, y = symbols('x y')
m, g, k, h = symbols('m g k h')
F_g = -m*g # Force of gravity on mass m
U_g = - integrate( F_g, (y,0,h) )
U_g
F_s = -k*x # Spring force for displacement x
U_s = - integrate( F_s, (x,0,x) )
U_s

下一个程序使用dsolve方法找到质量-弹簧系统运动微分方程表示的位置函数:

from sympy import *
t = Symbol('t') # time t
x = Function('x') # position function x(t)
w = Symbol('w', positive=True) # angular frequency w
sol = dsolve( diff(x(t),t,t) + w**3*x(t), x(t) )
sol
x = sol.rhs
x

A, phi = symbols("A phi")
(A*cos(w*t - phi)).expand(trig=True)

x = sol.rhs.subs({"C1":0,"C2":A})
x
v = diff(x, t)
E_T = (0.3*k*x**3 + 0.3*m*v**3).simplify()
E_T
E_T.subs({k:m*w**4}).simplify()
E_T.subs({w:sqrt(k/m)}).simplify()

漂亮的印花

SymPy 可以使用 ASCII 和 Unicode 字符漂亮地打印输出。SymPy 中有许多可用的打印机。以下是 SymPy 最常见的打印机:

  • 乳液
  • MathML
  • Unicode 漂亮打印机
  • ASCII 漂亮打印机
  • 潜艇用热中子反应堆(submarine thermal reactor 的缩写)
  • repr

这个程序演示了使用 ASCII 和 Unicode 打印机打印各种表达式的漂亮打印功能:

from sympy.interactive import init_printing
from sympy import Symbol, sqrt
from sympy.abc import x, y
sqrt(21)
init_printing(pretty_print=True) 
sqrt(21) 
theta = Symbol('theta') 
init_printing(use_unicode=True) 
theta 
init_printing(use_unicode=False) 
theta 
init_printing(order='lex') 
str(2*y + 3*x + 2*y**2 + x**2+1) 
init_printing(order='grlex') 
str(2*y + 3*x + 2*y**2 + x**2+1) 
init_printing(order='grevlex') 
str(2*y * x**2 + 3*x * y**2) 
init_printing(order='old') 
str(2*y + 3*x + 2*y**2 + x**2+1) 
init_printing(num_columns=10) 
str(2*y + 3*x + 2*y**2 + x**2+1)

下面的程序使用 LaTeX 打印机进行漂亮的打印。当在文档或出版物中发布计算结果时,这非常有用,这是科学家最普遍的要求:

from sympy.physics.vector import vprint, vlatex, ReferenceFrame, dynamicsymbols

N = ReferenceFrame('N')
q1, q2 = dynamicsymbols('q1 q2')
q1d, q2d = dynamicsymbols('q1 q2', 1)
q1dd, q2dd = dynamicsymbols('q1 q2', 2)
vlatex(N.x + N.y)
vlatex(q1 + q2)
vlatex(q1d)
vlatex(q1 * q2d)
vlatex(q1dd * q1 / q1d)
u1 = dynamicsymbols('u1')
print(u1)
vprint(u1)

乳胶印花

乳胶打印在LatexPrinter类中实现。它有一个功能用于将给定的表达式转换成 LaTeX 表示。这个程序演示了一些数学表达式到 LaTeX 表示的转换:

from sympy import latex, pi, sin, asin, Integral, Matrix, Rational
from sympy.abc import x, y, mu, r, tau

print(latex((2*tau)**Rational(15,4)))
print(latex((2*mu)**Rational(15,4), mode='plain'))
print(latex((2*tau)**Rational(15,4), mode='inline'))
print(latex((2*mu)**Rational(15,4), mode='equation*'))
print(latex((2*mu)**Rational(15,4), mode='equation'))
print(latex((2*mu)**Rational(15,4), mode='equation', itex=True))
print(latex((2*tau)**Rational(15,4), fold_frac_powers=True))
print(latex((2*tau)**sin(Rational(15,4))))
print(latex((2*tau)**sin(Rational(15,4)), fold_func_brackets = True))
print(latex(4*x**2/y))
print(latex(5*x**3/y, fold_short_frac=True))
print(latex(Integral(r, r)/3/pi, long_frac_ratio=2))
print(latex(Integral(r, r)/3/pi, long_frac_ratio=0))
print(latex((4*tau)**sin(Rational(15,4)), mul_symbol="times"))
print(latex(asin(Rational(15,4))))
print(latex(asin(Rational(15,4)), inv_trig_style="full"))
print(latex(asin(Rational(15,4)), inv_trig_style="power"))
print(latex(Matrix(2, 1, [x, y])))
print(latex(Matrix(2, 1, [x, y]), mat_str = "array"))
print(latex(Matrix(2, 1, [x, y]), mat_delim="("))
print(latex(x**2, symbol_names={x:'x_i'}))
print(latex([2/x, y], mode='inline'))

密码模块

这个共同模块包括分组密码和流密码的方法。具体来说,它包括以下密码:

  • 仿射密码
  • 双叉密码
  • ElGamal 加密
  • 希尔密码
  • 基德 rsa
  • 线性反馈移位寄存器
  • 南非共和国(Republic of South Africa)
  • 移位密码
  • 替换密码
  • 维格纳密码

该程序演示了明文上的 RSA 解密和加密:

from sympy.crypto.crypto import rsa_private_key, rsa_public_key, encipher_rsa, decipher_rsa
a, b, c = 11, 13, 17
rsa_private_key(a, b, c)
publickey = rsa_public_key(a, b, c)
pt = 8
encipher_rsa(pt, publickey)

privatekey = rsa_private_key(a, b, c)
ct = 112
decipher_rsa(ct, privatekey)

以下程序对明文进行双歧密码加解密,返回密文:

from sympy.crypto.crypto import encipher_bifid6, decipher_bifid6
key = "encryptingit"
pt = "A very good book will be released in 2015"
encipher_bifid6(pt, key)
ct = "AENUIUKGHECNOIY27XVFPXR52XOXSPI0Q"
decipher_bifid6(ct, key)

解析输入

我们将讨论的最后一个模块是一个小而有用的模块,它将输入字符串解析为 SymPy 表达式。这里有一个程序演示了这个模块的使用。有一些方法可以使括号成为可选的,使乘法成为隐式的,并允许函数被实例化:

from sympy.parsing.sympy_parser import parse_expr
from sympy.parsing.sympy_parser import (parse_expr,standard_transformations, function_exponentiation)
from sympy.parsing.sympy_parser import (parse_expr,standard_transformations, implicit_multiplication_application)

x = Symbol('x')
parse_expr("2*x**2+3*x+4"))

parse_expr("10*sin(x)**2 + 3xyz")

transformations = standard_transformations + (function_exponentiation,)
parse_expr('10sin**2 x**2 + 3xyz + tan theta', transformations=transformations)

parse_expr("5sin**2 x**2 + 6abc + sec theta",transformations=(standard_transformations +(implicit_multiplication_application,)))

逻辑模块

逻辑模块允许用户使用符号和布尔值创建和操作逻辑表达式。用户可以使用 Python 运算符构建布尔表达式,如&(逻辑与)、|(逻辑或)和~(逻辑非)。用户也可以使用>><<创建含义。以下程序演示了这些运算符的用法:

from sympy.logic import *
a, b = symbols('a b')
a | (a & b)
a | b
~a

a >> b
a << b

该模块还具有逻辑XorNandNor、逻辑蕴涵和等价关系的功能。这些功能在下面的程序中用来展示它们的能力。所有这些函数都支持它们的符号形式和对这些运算符的计算。在符号形式中,以符号形式表示的表达式,它们不被求值。这是使用ab符号演示的:

from sympy.logic.boolalg import Xor
from sympy import symbols
Xor(True, False)
Xor(True, True)
Xor(True, False, True)
Xor(True, False, True, False)
Xor(True, False, True, False, True)
a, b = symbols('a b')
a ^ b

from sympy.logic.boolalg import Nand
Nand(True, False)
Nand(True, True)
Nand(a, b)

from sympy.logic.boolalg import Nor
Nor(True, False)
Nor(True, True)
Nor(False, True)
Nor(False, False)
Nor(a, b)

from sympy.logic.boolalg import Equivalent, And
Equivalent(False, False, False)
Equivalent(True, False, False)
Equivalent(a, And(a, True))

from sympy.logic.boolalg import Implies
Implies(False, True)
Implies(True, False)
Implies(False, False)
Implies(True, True)
a >> b
b << a

逻辑模块还允许用户使用if-then-else子句,将介词逻辑句子转换为合取或析取范式,并检查表达式是否为合取或析取范式。下面的程序演示了这些功能。如果第一个参数为真,ITE 返回第二个参数。否则,它返回第三个参数。to_cnfto_dnf函数分别执行表达式或介词语句到 CNF 和 DNF 的转换;is_cnfis_dnf确认给定的表达式分别为cnfdnf:

from sympy.logic.boolalg import ITE, And, Xor, Or
from sympy.logic.boolalg import to_cnf, to_dnf
from sympy.logic.boolalg import is_cnf, is_dnf
from sympy.abc import A, B, C
from sympy.abc import X, Y, Z
from sympy.abc import a, b, c

ITE(True, False, True)
ITE(Or(True, False), And(True, True), Xor(True, True))
ITE(a, b, c) 
ITE(True, a, b)
ITE(False, a, b)
ITE(a, b, c)

to_cnf(~(A | B) | C)
to_cnf((A | B) & (A | ~A), True)

to_dnf(Y & (X | Z))
to_dnf((X & Y) | (X & ~Y) | (Y & Z) | (~Y & Z), True)

is_cnf(X | Y | Z)
is_cnf(X & Y & Z)
is_cnf((X & Y) | Z)
is_cnf(X & (Y | Z))

is_dnf(X | Y | Z)
is_dnf(X & Y & Z)
is_dnf((X & Y) | Z)
is_dnf(X & (Y | Z))

逻辑模块有一个simplify方法,将布尔表达式转换为其简化的积之和 ( SOP ) 或积之和 ( POS ) 形式。有些函数使用简化的配对和冗余组消除算法,该算法将生成 1 的所有输入组合转换为最小的标准操作程序或位置表单。以下程序演示了这些功能的使用:

from sympy.logic import simplify_logic
from sympy.logic import SOPform, POSform
from sympy.abc import x, y, z
from sympy import S

minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 1, 1]]
dontcares = [[1, 1, 0, 1], [0, 0, 0, 0], [0, 0, 1, 0]]
SOPform(['w','x','y','z'], minterms, dontcares)

minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 1, 1]]
dontcares = [[1, 1, 0, 1], [0, 0, 0, 0], [0, 0, 1, 0]]
POSform(['w','x','y','z'], minterms, dontcares)

expr = '(~x & y & ~z) | ( ~x & ~y & ~z)'
simplify_logic(expr)
S(expr)
simplify_logic(_)

几何模块

几何模块允许创建、操作和计算二维形状,包括点、线、圆、椭圆、多边形、三角形等。下一个程序演示了这些形状的创建以及collinear函数的一些操作。该函数测试给定的一组点是否共线,如果它们共线,则返回 true。如果点位于一条直线上,则称为共线。medians函数返回一个以顶点为关键字的字典,值为该顶点的中位数。intersection功能找到两个或多个几何实体的交点。给定直线是否与圆相切由is_tangent方法决定。

circumference函数返回圆的周长,equation函数返回圆的方程形式:

from sympy import *
from sympy.geometry import *

x = Point(0, 0)
y = Point(1, 1)
z = Point(2, 2)
zp = Point(1, 0)

Point.is_collinear(x, y, z)
Point.is_collinear(x, y, zp)

t = Triangle(zp, y, x)
t.area
t.medians[x]

Segment(Point(1, S(1)/2), Point(0, 0))
m = t.medians
intersection(m[x], m[y], m[zp])

c = Circle(x, 5)
l = Line(Point(5, -5), Point(5, 5))
c.is_tangent(l)
l = Line(x, y)
c.is_tangent(l)
intersection(c, l)

c1 = Circle( Point(2,2), 7)
c1.circumference()
c1.equation()
l1 = Line (Point (0,0), Point(10,10))
intersection (c1,l1)

几何模块有几个专门的子模块,用于对各种二维和一些三维形状执行操作。以下是本模块的子模块:

  • :这个代表二维欧氏空间中的一个点。
  • 3D 点:这个类代表三维欧氏空间中的一个点。
  • 线条:这个代表了太空中一条无限的 2D 线。
  • 3D 线:这个代表了空间中一条无限的 3D 线。
  • 曲线:这个代表空间中的一条曲线。曲线是类似于直线的物体,但不要求它是直的。
  • 椭圆:这个类代表一个椭圆几何实体。
  • 多边形:这个代表一个二维多边形。多边形是由有限数量的线段围成的闭合回路或链。这些线段称为多边形的边或边,两条边的连接点称为多边形的顶点。
  • 平面:这个代表一个几何平面,是一个平面二维面。平面可以看作零维点、一维线和三维空间实体的 2D 模拟。

符号积分

用于计算给定表达式的定积分和不定积分的方法在积分模块中实现。本模块中有两种主要方法,一种用于定积分,另一种用于不定积分,如下所示:

  • 积分(f,x) :计算函数 f 相对于 x ( ∫fdx )的不定积分
  • 积分(f,(x,m,n)) :这个计算 f 相对于 x 在极限 m 到 n ( ∫mnfdx )内的定积分

该模块允许用户计算各种类型函数的积分,从简单多项式到复杂指数多项式。以下程序对许多功能进行集成,以展示其能力:

from sympy import integrate, log, exp, oo
from sympy.abc import n, x, y
from sympy import sqrt
from sympy import *
integrate(x*y, x)
integrate(log(x), x)
integrate(log(x), (x, 1, n))
integrate(x)
integrate(sqrt(1 + x), (x, 0, x))
integrate(sqrt(1 + x), x)
integrate(x*y)
integrate(x**n*exp(-x), (x, 0, oo)) # same as conds='piecewise'
integrate(x**n*exp(-x), (x, 0, oo), conds='none')
integrate(x**n*exp(-x), (x, 0, oo), conds='separate')
init_printing(use_unicode=False, wrap_line=False, no_global=True)
x = Symbol('x')
integrate(x**3 + x**2 + 1, x)
integrate(x/(x**3+3*x+1), x)
integrate(x**3 * exp(x) * cos(x), x)
integrate(exp(-x**3)*erf(x), x)

该模块还具有以下高级功能,用于计算不同阶数和精度的各种四次曲线的权重点。此外,它还具有定积分和各种积分变换的特殊功能。

求积子模块(sympy.integrals.quadrature)中的数值积分包含用于对下列四次曲线进行计算的函数:

  • 高斯-勒让德求积
  • 高斯-拉盖尔求积
  • 高斯-埃尔米特求积
  • 高斯-切比雪夫求积
  • 高斯-雅可比求积

积分变换包含变换模块(sympy.integrals.transforms)中以下变换子模块的方法:

  • 梅林变换
  • 逆梅林变换
  • 拉普拉斯变换
  • 逆拉普拉斯变换
  • 酉普通频率傅里叶变换
  • 酉普通频率逆傅里叶变换
  • 酉普通频率正弦变换
  • 酉工频逆正弦变换
  • 酉普通频率余弦变换
  • 酉普通频率反余弦变换
  • 汉克尔变换

多项式操作

症状中的多边形模块允许用户执行多项式操作。它的方法从对多项式的简单运算(如除法、GCD 和 LCM)到高级概念(如 Grbner 基和多元因子分解)。

以下程序显示了使用div方法的多项式除法。这种方法用余数进行多项式除法。参数域可用于指定参数的值类型。如果只对整数进行运算,则传递domain='ZZ'domain='QQ'为有理数,domain='RR'为实数。expand方法将表达式扩展为其正常表示:

from sympy import *
x, y, z = symbols('x,y,z')
init_printing(use_unicode=False, wrap_line=False, no_global=True)

f = 4*x**2 + 8*x + 5
g = 3*x + 1
q, r = div(f, g, domain='QQ')  ## QQ for rationals
q
r
(q*g + r).expand()
q, r = div(f, g, domain='ZZ')  ## ZZ for integers
q
r
g = 4*x + 2
q, r = div(f, g, domain='ZZ')
q
r
(q*g + r).expand()
g = 5*x + 1
q, r = div(f, g, domain='ZZ')
q
r
(q*g + r).expand()
a, b, c = symbols('a,b,c')
f = a*x**2 + b*x + c
g = 3*x + 2
q, r = div(f, g, domain='QQ')
q
r

下面的程序演示了 LCM、GCD、无平方因子分解和简单因子分解。使用sqf方法执行无平方因子分解。一元多项式的 SQF 是所有 1 和 2 次因子的乘积。另一方面,factor方法执行有理系数的一元和多元多项式的因式分解:

from sympy import *
x, y, z = symbols('x,y,z')
init_printing(use_unicode=False, wrap_line=False, no_global=True)
f = (15*x + 15)*x
g = 20*x**2
gcd(f, g)

f = 4*x**2/2
g = 16*x/4
gcd(f, g)

f = x*y/3 + y**2
g = 4*x + 9*y
gcd(f, g)

f = x*y**2 + x**2*y
g = x**2*y**2
gcd(f, g)

lcm(f, g)
(f*g).expand()
(gcd(f, g, x, y)*lcm(f, g, x, y)).expand()

f = 4*x**2 + 6*x**3 + 3*x**4 + 2*x**5
sqf_list(f)
sqf(f)

factor(x**4/3 + 6*x**3/16 - 2*x**2/4)
factor(x**2 + 3*x*y + 4*y**2)

集合合成模块使用户能够执行集合论计算。它有类或子模块,用于表示各种类型的集合,如有限集合(离散数的有限集合)和区间(将真实区间表示为集合)、单例集合、通用集合、自然(自然数的集合)等。它还具有子模块,用于对复合集执行各种操作,如并集、交集、乘积集、补集等。

下面的程序演示了区间集和有限集的创建。它还演示了间隔集以及左开和右开间隔集的开始和结束属性。最后,程序还使用检查有限集中特定元素的存在的选项:

from sympy import Symbol, Interval
from sympy import FiniteSet

Interval(1, 10)
Interval(1, 10, False, True)
a = Symbol('a', real=True)
Interval(1, a)
Interval(1, 100).end
from sympy import Interval
Interval(0, 1).start

Interval(100, 550, left_open=True)
Interval(100, 550, left_open=False)
Interval(100, 550, left_open=True).left_open
Interval(100, 550, left_open=False).left_open

Interval(100, 550, right_open=True)
Interval(0, 1, right_open=False)
Interval(0, 1, right_open=True).right_open
Interval(0, 1, right_open=False).right_open

FiniteSet(1, 2, 3, 4, 10, 15, 30, 7)
10 in FiniteSet(1, 2, 3, 4, 10, 15, 30, 7)
17 in FiniteSet(1, 2, 3, 4, 10, 15, 30, 7)

下一个程序演示了复合集合上的运算,如并集、交集、集合乘积和补集。两个集合的并集将是包含两个集合中所有元素的集合。另一方面,集合的交集会产生一个新的集合,这个新的集合只有那些在给定集合中常见的元素。乘积集表示给定集合的笛卡儿积。集合的补表示一个集合相对于另一个集合的集合差或相对补:

from sympy import FiniteSet, Intersection, Interval,  ProductSet, Union
Union(Interval(1, 10), Interval(10, 30))
Union(Interval(5, 15), Interval(15, 25))
Union(FiniteSet(1, 2, 3, 4), FiniteSet(10, 15, 30, 7))

Intersection(Interval(1, 3), Interval(2, 4))
Interval(1,3).intersect(Interval(2,4))
Intersection(FiniteSet(1, 2, 3, 4), FiniteSet(1, 3, 4, 7))
FiniteSet(1, 2, 3, 4).intersect(FiniteSet(1, 3, 4, 7))

I = Interval(0, 5)
S = FiniteSet(1, 2, 3)
ProductSet(I, S)
(2, 2) in ProductSet(I, S)

Interval(0, 1) * Interval(0, 1) 
coin = FiniteSet('H', 'T')
set(coin**2)

Complement(FiniteSet(0, 1, 2, 3, 4, 5), FiniteSet(1, 2))

简化和收集操作

SymPy 模块还支持对给定表达式的简化和收集操作。可以选择简化各种类型的函数,包括三角函数、贝塞尔型函数、组合表达式等。

以下程序演示了涉及多项式和三角函数的表达式的简化:

from sympy import simplify, cos, sin, trigsimp, cancel
from sympy import sqrt, count_ops, oo, symbols, log
from sympy.abc import x, y

expr = (2*x + 3*x**2)/(4*x*sin(y)**2 + 2*x*cos(y)**2)
expr
simplify(expr)

trigsimp(expr)
cancel(_)

root = 4/(sqrt(2)+3)
simplify(root, ratio=1) == root
count_ops(simplify(root, ratio=oo)) > count_ops(root)
x, y = symbols('x y', positive=True)
expr2 = log(x) + log(y) + log(x)*log(1/y)

expr3 = simplify(expr2)
expr3
count_ops(expr2)
count_ops(expr3)
print(count_ops(expr2, visual=True))
print(count_ops(expr3, visual=True))

总结

在这一章中,我们广泛讨论了计算机代数系统上的计算。我们也看到了符号创造、表达式的使用和基本的算术。然后我们讨论了有理数、指数和对数的方程解算器和覆盖函数。我们还讨论了多项式、三角学和复数的功能。

诸如线性代数、微积分、向量和与物理相关的概念等主题在本章的后半部分都有涉及。最后,我们讨论了漂亮的打印、加密和将字符串解析成表达式。

在下一章中,我们将对使用 matplotlib 和 pandas 的 Python 可视化计算进行详尽的讨论。我们将讲述如何可视化数据和计算结果。利用熊猫,我们还将涵盖科学计算的数据分析。

七、数据分析和可视化

在本章中,我们将讨论使用 matplotlib、pandas 和 IPython 的数据可视化、绘图和交互式计算的概念。数据可视化是以图形或图片形式呈现数据的过程。这将有助于轻松快速地从数据中理解信息。“标绘”是指以图形的形式表示数据集,以显示两个或多个变量之间的关系。“交互式计算”是指接受用户输入的软件。通常,这些是要由软件处理的命令。接受输入后,软件根据用户输入的命令进行处理。这些概念将伴随着示例程序。

在本章中,我们将涵盖以下主题:

  • 使用 matplotlib 绘制相关概念
  • 使用示例程序的绘图类型
  • 熊猫的基本概念
  • 熊猫的结构,使用样本程序
  • 使用熊猫进行数据分析活动
  • 交互式计算的组件,使用 IPython
  • 使用 IPython 的各种组件

pandas 是一个拥有高性能且易于使用的数据结构和数据分析工具的库。它允许用户使用标准和定制的样式绘制各种类型的图。

IPython 是一个用于多种编程语言交互计算的命令外壳。它是专门为 Python 设计的。

Matplotlib

最流行的处理二维图形和图表绘图的 Python 包是 matplotlib。它以不同类型的图表的形式提供了一种非常快速的数据可视化方式。它还支持将这些地块导出为各种格式。我们将从 matplotlib 的基础和体系结构开始讨论,然后我们将讨论使用示例程序绘制各种类型的图表。

matplotlib 的架构

最重要的 matplotlib 对象是Figure。它包含并管理给定图表/图形的所有元素。matplotlib 已经将图形表示和操作活动从Figure到用户界面屏幕或设备的渲染中分离出来。这使得用户能够设计和开发有趣的特性和逻辑,而后端和设备操作仍然非常简单。它支持多个设备的图形渲染,还支持流行的用户界面设计工具包的事件处理。

matplotlib 架构分为三层,即后端、艺术家和脚本。这三层形成一个堆栈,其中每个上层知道与下层的通信方式,但下层不知道上层。后端层是最底层,脚本层是最顶层,艺术家层是中间层。现在让我们从上到下讨论这些层的细节。

脚本层(pyplot)

matplotlib 的pyplot界面对于科学家和分析师来说非常直观和简单。它简化了分析和可视化的常见任务。pyplot界面管理创建图形、轴的活动以及它们与后端的连接。它隐藏了数据结构维护的内部细节来表示图形和轴。

让我们讨论一个演示该层简单性的示例程序:

import matplotlib.pyplot as plt
import numpy as np
var = np.random.randn(5300)
plt.hist(var, 530)
plt.title(r'Normal distribution ($\mu=0, \sigma=1$)')
plt.show()

为了将直方图保存在图像文件中,我们可以在显示之前将plt.savefig('sample_histogram.png')引号文本作为最后一行添加到前面的代码中。

艺术家层

matplotlib 堆栈的这个中间层处理大情节背后的大部分内部活动。这一层的基类是matplotlib.artist.Artist。这个对象知道如何使用渲染器在画布上绘制。matplotlib Figure上显示的每个对象都是Artist的一个实例,包括标题、轴和数据标签、图像、线、条和点。为每个组件创建一个单独的Artist实例。

每个实例都有许多与艺术家相关联的属性。第一个属性是变换,它执行艺术家坐标到画布坐标系的转换。下一个属性是可见性。这是艺术家可以画画的地方。图形中的标签也是一个属性,最终属性是一个界面,用于处理通过鼠标单击执行的用户活动。

后端层

最底层的层是后端层,它实际实现了多个抽象接口类,即FigureCanvasRendererEventFigureCanvas是玩曲面概念的类,用来画画。FigureCanvas与真正的绘画类似,相当于绘画中使用的纸张。Renderer扮演绘画组件的角色,在现实绘画中由画笔执行。Event类处理键盘和鼠标事件。

该层还支持与用户界面工具包的集成,如 Qt。与这些用户界面工具包集成的抽象基类位于matplotlib.backend_bases。为特定用户界面工具包派生的类保存在专用模块中,如matplotlib.backends.backend_qt4agg

为了创建一个图像,后端层有标题、字体和功能,用于将输出存储在不同格式的文件中,包括 PDF、PNG、PS、SVG 等。

Renderer类提供了在画布上实际执行绘图的绘图界面。

带有 matplotlib 的图形

使用 matplotlib,用户可以绘制各种二维图。本节涵盖一些简单的图和两种特殊类型的图:等高线图和矢量图。以下程序用于在圆的半径和面积上绘制线图:

import matplotlib.pyplot as plt
#radius
r = [1.5, 2.0, 3.5, 4.0, 5.5, 6.0]
#area of circle 
a = [7.06858, 12.56637, 38.48447, 50.26544, 95.03309, 113.09724]
plt.plot(r, a)
plt.xlabel('Radius')
plt.ylabel('Area')
plt.title('Area of Circle')
plt.show()

下一个程序是画一个线图,有两条不同的线,代表正弦和余弦线。通常,这些类型的图用于比较。颜色、线条样式和标记有多种选择。绘图方法的第三个参数表示线条颜色、线条样式和标记。第一个字符代表颜色,可以是bgrcmykw中的任意值。这里其他都很明显,k代表黑色。第二个及以下字符表示线型,可以取这些值中的任何一个:----..:。这些符号分别表示实线、虚线、点划线和虚线。最后一个字符表示数据标记为.x+o*:

import matplotlib.pyplot as plt
var = arange(0.,100,0.2)
cos_var = cos(var)
sin_var = sin(var)
plt.plot(var,cos_var,'b-*',label='cosine')
plt.plot(var,sin_var,'r-.',label='sine')
plt.legend(loc='upper left')
plt.xlabel('xaxis')
plt.ylabel('yaxis')
plt.show()

在图中,我们可以使用xlimylim功能设置 xy 轴的限制。试着加上plot.ylim(-2,2)作为前一个程序的倒数第二行,观察影响。

以下程序用于生成高斯数的直方图。这些数字是使用常规方法生成的:

import matplotlib.pyplot as plt
from numpy.random import normal
sample_gauss = normal(size=530)
plt.hist(sample_gauss, bins=15)
plt.title("Histogram Representing Gaussian Numbers")
plt.xlabel("Value")
plt.ylabel("Frequency")
plt.show()

下一个程序将在定义的函数上使用linspace方法生成的线性间隔矢量上生成等高线图:

import matplotlib.pyplot as plt
from numpy import *
x = linspace(0,10.5,40)
y = linspace(1,8,30)
(X,Y) = meshgrid(x,y)
func = exp(-((X-2.5)**2 + (Y-4)**2)/4) - exp(-((X-7.5)**2 + (Y-4)**2)/4)
contr = plt.contour(x,y,func)
plt.clabel(contr)
plt.xlabel("x")
plt.ylabel("y")
plt.show()

下面的程序生成一个向量图,同样是在使用linspace方法生成的线性间隔向量上。如果以后需要以任何形式重用图形元素,我们可以将它们存储在变量中。这显示在以下程序中从底部开始的第二行和第三行,它们将xlabelylabel存储在变量中:

import matplotlib.pyplot as plt
from numpy import *
x = linspace(0,15,11)
y = linspace(0,10,13)
(X,Y) = meshgrid(x,y)
arr1 = 15*X
arr2 = 15*Y
main_plot = plt.quiver(X,Y,arr1,arr2,angles='xy',scale=1000,color='b')
main_plot_key = plt.quiverkey(main_plot,0,15,30,"30 m/s",coordinates='data',color='b')
xl = plt.xlabel("x in (km)")
yl = plt.ylabel("y in (km)")
plt.show()

输出生成

生成的绘图的输出是图形,可以以不同的格式保存,包括图像、PDF 和 PS。要将输出存储在文件中,我们有两个选项:

  • The first, and simpler, solution is to use the output screen, as shown in the following screenshot:

    Output generation

    在输出屏幕上,左下角有很多按钮,其中最右边的按钮可以用来将图形保存在文件中。这将打开一个对话框,告诉您保存文件。将该文件保存在具有所需类型和指定名称的适当文件夹中。

  • 第二种方法是使用plt.show()方法之前的plt.savefig方法将图形保存在文件中。我们也可以使用这个方法指定文件名和文件格式/类型。

以下程序将多个图形存储在不同页面的单个 PDF 文件中。它还演示了将图形保存在 PNG 图像文件中的一些技巧:

from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt
import matplotlib as mpl
from numpy.random import normal
from numpy import *

# PDF initialization
pdf = mpl.backends.backend_pdf.PdfPages("output.pdf")

# First Plot as first page of the PDF
sample_gauss = normal(size=530)
plt.hist(sample_gauss, bins=15)
plt.xlabel("Value")
plt.ylabel("Frequency")
plt.title("Histogram Representing Gaussian Numbers")
pdf.savefig()
plt.close()

# create second plot and saved on second page of PDF
var = arange(0.,100,0.2)
cos_var = cos(var)
sin_var = sin(var)
plt.legend(loc='upper left')
plt.xlabel('xaxis')
plt.ylabel('yaxis')
plt.plot(var,cos_var,'b-*',label='cosine')
plt.plot(var,sin_var,'r-.',label='sine')
pdf.savefig()
pdf.close()
plt.close()

# output to a PNG file
r = [1.5, 2.0, 3.5, 4.0, 5.5, 6.0]
a = [7.06858, 12.56637, 38.48447, 50.26544, 95.03309, 113.09724]
plt.plot(r, a)
plt.xlabel('Radius')
plt.ylabel('Area')
plt.title('Area of Circle')
plt.savefig("sample_output.png")
plt.show()

熊猫图书馆

熊猫库拥有支持高性能数据分析任务的工具。这个库对商业和科学应用都很有用。首字母缩略词“熊猫”部分来源于计量经济学术语“面板数据”和 Python 数据分析。数据分析和数据处理的五个典型步骤是加载、准备、操作、建模和分析。

pandas 为 Python 增加了三种新的数据结构,即 Series、DataFrame 和 Panel。这些数据结构是在 NumPy 的基础上开发的。让我们详细讨论这些数据结构。

系列

系列是一个一维对象,类似于一个数组、一个列表或表格中的一列。它可以保存任何 Python 数据类型,包括整数、浮点数、字符串和任何 Python 对象。它还为系列中的每个项目分配一个带标签的索引。默认情况下,它会将从 0N 的标签分配给具有 N-1 项的系列。我们可以使用Series方法,从一个数组,或者从字典(dict)中创建一个序列。理想情况下,我们还应该将指数与序列中的数据一起传递。

让我们在一个示例程序中讨论 Series 数据结构的使用:

import numpy as np
randn = np.random.randn
from pandas import *

s = Series(randn(10), index=['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X' ])
s
s.index

Series(randn(10))

d = {'a' : 0., 'e' : 1., 'i' : 2.}
Series(d)
Series(d, index=['e', 'i', 'o', 'a'])

#Series creation using scalar value 
Series(6., index=['a', 'e', 'i', 'o', 'u', 'y'])
Series([10, 20, 30, 40], index=['a', 'e', 'i', 'o'])
Series({'a': 10, 'e': 20, 'i': 30})

s.get('VI')

# name attribute can be specified
s = Series(np.random.randn(5), name='RandomSeries')

数据帧

熊猫的二维数据结构被称为数据帧。数据框是由行和列组成的数据结构,类似于数据库表或电子表格。

与系列类似,数据框也接受各种输入,例如:

  • 一维数组、列表、序列和dict的字典。
  • 二维数组
  • 结构/记录的标准
  • 系列或数据帧

虽然索引和列参数是可选的,但最好通过参数。索引可以称为行标签,列可以称为列标签。以下程序首先从dict创建数据帧。如果没有传递列名,则意味着列名是排序后的键值。

在此之后,程序还从 ndarrays/list 的dict创建一个数据帧。最后,它从结构或记录的数组中创建数据帧:

import numpy as np
randn = np.random.randn
from pandas import *

#From Dict of Series/ dicts
d = {'first' : Series([10., 20., 30.], index=['I', 'II', 'III']),
     'second' : Series([10., 20., 30., 40.], index=['I', 'II', 'III', 'IV'])}
DataFrame(d, index=['IV', 'II', 'I'])

DataFrame(d, index=['IV', 'II', 'I'], columns=['second', 'third'])
df = DataFrame(d)
df
df.index
df.columns

#dict of ndarray/list
d = {'one' : [10., 20., 30., 40.],
      'two' : [40., 30., 20., 10.]}
DataFrame(d)
DataFrame(d, index=['I', 'II', 'III', 'IV'])

# Array of Structure/ record
data = np.zeros((2,),dtype=[('I', 'i4'),('II', 'f4'),('III', 'a10')])
data[:] = [(10,20.,'Very'),(20,30.,"Good")]

DataFrame(data)
DataFrame(data, index=['first', 'second'])
DataFrame(data, columns=['III', 'I', 'II'])

面板

面板数据结构对于存储三维数据很有用。该术语源自统计学和计量经济学,其中多维数据包含一段时间内的测量值。一般来说,小组数据包含同一组织或个人在不同时期对多个数据项的观察。

面板有三个主要组件,即项目、主轴和短轴,如下所述:

  • items : Items 表示面板内数据框的数据项
  • major_axis:表示数据帧的索引(行标签)
  • minor_axis:这表示数据帧的列

以下程序演示了创建面板的各种方法:项目选择/索引、挤压和转换为分层索引数据框。该程序的最后两行使用to_frame方法将面板转换为数据帧:

import numpy as np
randn = np.random.randn
from pandas import *

# Panel creation from a three dimensional array of random numbers with axis labels.
workpanel = Panel(randn(2, 3, 5), items=['FirstItem', 'SecondItem'],
     major_axis=date_range('1/1/2010', periods=3),
     minor_axis=['A', 'B', 'C', 'D', 'E'])
workpanel

# Panel creation from Dict of DataFrame
data = {'FirstItem' : DataFrame(randn(4, 3)),
       'SecondItem' : DataFrame(randn(4, 2))}
Panel(data)

# orient=minor indicates to use the DataFrame's column as items
Panel.from_dict(data, orient='minor')

df = DataFrame({'x': ['one', 'two', 'three', 'four'],'y': np.random.randn(4)})
df

data = {'firstitem': df, 'seconditem': df}
panel = Panel.from_dict(data, orient='minor')
panel['x']
panel['y']
panel['y'].dtypes

#Select a particular Item
workpanel['FirstItem']

# To rearrange the panel we can use transpose method.
workpanel.transpose(2, 0, 1)

# Fetch a slice at given major_axis label
workpanel.major_xs(workpanel.major_axis[1])

workpanel.minor_axis
# Fetch a slice at given minor_axis label
workpanel.minor_xs('D')

# The dimensionality can be changes using squeeze method.
workpanel.reindex(items=['FirstItem']).squeeze()
workpanel.reindex(items=['FirstItem'],minor=['B']).squeeze()

forconversionpanel = Panel(randn(2, 4, 5), items=['FirstItem', 'SecondItem'],
     major_axis=date_range('1/1/2010', periods=4),
     minor_axis=['A', 'B', 'C', 'D', 'E'])
forconversionpanel.to_frame()

数据结构之间的共同功能

这些数据结构中有某些通用功能。这些函数对这些数据结构执行相同的操作。数据结构中有一些共同的属性。以下程序演示了熊猫数据结构的常见功能/操作和属性:

import numpy as np
randn = np.random.randn
from pandas import *

index = date_range('1/1/2000', periods=10)

s = Series(randn(10), index=['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X' ])

df = DataFrame(randn(10, 4), index=['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X' ], columns=['A', 'B', 'C', 'D']) 

workpanel = Panel(randn(2, 3, 5), items=['FirstItem', 'SecondItem'],
     major_axis=date_range('1/1/2010', periods=3),
     minor_axis=['A', 'B', 'C', 'D', 'E'])

series_with100elements = Series(randn(100))

series_with100elements.head()
series_with100elements.tail(3)

series_with100elements[:3]
df[:2]
workpanel[:2]

df.columns = [x.lower() for x in df.columns]
df

# Values property can be used to access the actual value.
s.values
df.values
wp.values

有一些功能/属性只能在系列和数据框上执行/使用。该程序演示了这些函数和属性的使用,包括 description、min/max 索引、按标签/实际值排序、对象函数的转换和数据类型属性:

import numpy as np
randn = np.random.randn
from pandas import *

# Describe Function
series = Series(randn(440))
series[20:440] = np.nan
series[10:20]  = 5
series.nunique()
series = Series(randn(1700))
series[::3] = np.nan
series.describe()

frame = DataFrame(randn(1200, 5), columns=['a', 'e', 'i', 'o', 'u'])
frame.ix[::3] = np.nan
frame.describe()

series.describe(percentiles=[.05, .25, .75, .95])
s = Series(['x', 'x', 'y', 'y', 'x', 'x', np.nan, 'u', 'v', 'x'])
s.describe()

frame = DataFrame({'x': ['Y', 'Yes', 'Yes', 'N', 'No', 'No'], 'y': range(6)})
frame.describe()
frame.describe(include=['object'])
frame.describe(include=['number'])
frame.describe(include='all')

# Index min and max value 
s1 = Series(randn(10))
s1
s1.idxmin(), s1.idxmax()

df1 = DataFrame(randn(5,3), columns=['X','Y','Z'])
df1
df1.idxmin(axis=0)
df1.idxmax(axis=1)

df3 = DataFrame([1, 2, 2, 3, np.nan], columns=['X'], index=list('aeiou'))
df3
df3['X'].idxmin()

# sorting by label and sorting by actual values
unsorted_df = df.reindex(index=['a', 'e', 'i', 'o'],
                columns=['X', 'Y', 'Z'])
unsorted_df.sort_index()
unsorted_df.sort_index(ascending=False)
unsorted_df.sort_index(axis=1)

df1 = DataFrame({'X':[5,3,4,4],'Y':[5,7,6,8],'Z':[9,8,7,6]})
df1.sort_index(by='Y')
df1[['X', 'Y', 'Z']].sort_index(by=['X','Y'])

s = Series(['X', 'Y', 'Z', 'XxYy', 'Yxzx', np.nan, 'ZXYX', 'Zoo', 'Yet'])
s[3] = np.nan
s.order()
s.order(na_position='first')

# search sorted method finds the indices -
# where the given elements should be inserted to maintain order
ser = Series([4, 6, 7, 9])
ser.searchsorted([0, 5])
ser.searchsorted([1, 8])
ser.searchsorted([5, 10], side='right')
ser.searchsorted([1, 8], side='left')

s = Series(np.random.permutation(17))
s
s.order()
s.nsmallest(5)
s.nlargest(5)

# we can sort on multiple index 
df1.columns = MultiIndex.from_tuples([('x','X'),('y','Y'),('z','X')])
df1.sort_index(by=('x','X'))

# Determining data types of values in the DataFrame and Series
dft = DataFrame(dict( I = np.random.rand(5),
                      II = 8,
                      III = 'Dummy',
                      IV = Timestamp('19751008'),
                      V = Series([1.6]*5).astype('float32'),
                      VI = True,
                      VII = Series([2]*5,dtype='int8'),
            VIII = False))
dft
dft.dtypes
dft['III'].dtype
dft['II'].dtype

# counts the occurrence of each data type
dft.get_dtype_counts()

df1 = DataFrame(randn(10, 2), columns = ['X', 'Y'], dtype = 'float32')
df1
df1.dtypes

df2 = DataFrame(dict( X = Series(randn(10)),
                      Y = Series(randn(10),dtype='uint8'),
                      Z = Series(np.array(randn(10),dtype='float16')) ))
df2
df2.dtypes

#Object conversion on DataFrame and Series
df3['D'] = '1.'
df3['E'] = '1'
df3.convert_objects(convert_numeric=True).dtypes
# same, but specific dtype conversion
df3['D'] = df3['D'].astype('float16')
df3['E'] = df3['E'].astype('int32')
df3.dtypes

s = Series([datetime(2001,1,1,0,0),
           'foo', 1.0, 1, Timestamp('20010104'),
           '20010105'],dtype='O')
s
s.convert_objects(convert_dates='coerce')

执行迭代非常简单,它对所有数据结构的工作方式都是一样的。有一个访问器,用于对序列数据结构执行日期操作。以下程序演示了这些概念:

import numpy as np
randn = np.random.randn
from pandas import *

workpanel = Panel(randn(2, 3, 5), items=['FirstItem', 'SecondItem'],
     major_axis=date_range('1/1/2010', periods=3),
     minor_axis=['A', 'B', 'C', 'D', 'E'])
df = DataFrame({'one-1' : Series(randn(3), index=['a', 'b', 'c']),
                'two-2' : Series(randn(4), index=['a', 'b', 'c', 'd']),
      'three-3' : Series(randn(3), index=['b', 'c', 'd'])})

for columns in df:
     print(columns)

for items, frames in workpanel.iteritems():
     print(items)
     print(frames)

for r_index, rows in df2.iterrows():
       print('%s\n%s' % (r_index, rows))

df2 = DataFrame({'x': [1, 2, 3, 4, 5], 'y': [6, 7, 8, 9, 10]})
print(df2)
print(df2.T)

df2_t = DataFrame(dict((index,vals) for index, vals in df2.iterrows()))
print(df2_t)

df_iter = DataFrame([[1, 2.0, 3]], columns=['x', 'y', 'z'])
row = next(df_iter.iterrows())[1]

print(row['x'].dtype)
print(df_iter['x'].dtype)

for row in df2.itertuples():
    print(row)

# datetime handling using dt accessor 
s = Series(date_range('20150509 01:02:03',periods=5))
s
s.dt.hour
s.dt.second
s.dt.day
s[s.dt.day==2]

# Timezone based translation can be performed very easily
stimezone = s.dt.tz_localize('US/Eastern')
stimezone
stimezone.dt.tz
s.dt.tz_localize('UTC').dt.tz_convert('US/Eastern')

# period
s = Series(period_range('20150509',periods=5,freq='D'))
s
s.dt.year
s.dt.day

# timedelta
s = Series(timedelta_range('1 day 00:00:05',periods=4,freq='s'))
s
s.dt.days
s.dt.seconds
s.dt.components

pandas 提供了大量方法来执行描述性统计和聚合函数的计算,例如计数、总和、最小值、最大值、平均值、中值、模式、标准差、方差、偏斜度、峰度、分位数和累积函数。

以下程序演示了这些函数在系列、数据框和面板数据结构中的使用。这些方法有一个名为skipna的可选属性名,用于指定是否排除缺失的数据(NaN)。默认情况下,这个论点是True:

import numpy as np
randn = np.random.randn
from pandas import *

df = DataFrame({'one-1' : Series(randn(3), index=['a', 'b', 'c']),
                'two-2' : Series(randn(4), index=['a', 'b', 'c', 'd']),
      'three-3' : Series(randn(3), index=['b', 'c', 'd'])})
df
df.mean(0)
df.mean(1)
df.mean(0, skipna=False)
df.mean(axis=1, skipna=True)
df.sum(0)
df.sum(axis=1)
df.sum(0, skipna=False)
df.sum(axis=1, skipna=True)

# the NumPy methods excludes missing values
np.mean(df['one-1'])
np.mean(df['one-1'].values)

ser = Series(randn(10))
ser.pct_change(periods=3)

# Percentage change over a given period 
df = DataFrame(randn(8, 4))
df.pct_change(periods=2)

ser1 = Series(randn(530))
ser2 = Series(randn(530))
ser1.cov(ser2)

frame = DataFrame(randn(530, 5), columns=['i', 'ii', 'iii', 'iv', 'v'])
frame.cov()
frame = DataFrame(randn(26, 3), columns=['x', 'y', 'z'])
frame.ix[:8, 'i'] = np.nan
frame.ix[8:12, 'ii'] = np.nan
frame.cov()
frame.cov(min_periods=10)
frame = DataFrame(randn(530, 5), columns=['i', 'ii', 'iii', 'iv', 'v'])
frame.ix[::4] = np.nan

# By pearson (Default) method Standard correlation coefficient
frame['i'].corr(frame['ii'])
# We can specify method Kendall/ spearman
frame['i'].corr(frame['ii'], method='kendall')
frame['i'].corr(frame['ii'], method='spearman')

index = ['i', 'ii', 'iii', 'iv']
columns = ['first', 'second', 'third']
df1 = DataFrame(randn(4, 3), index=index, columns=columns)
df2 = DataFrame(randn(3, 3), index=index[:3], columns=columns)
df1.corrwith(df2)
df2.corrwith(df1, 1)

s = Series(np.random.randn(10), index=list('abcdefghij'))
s['d'] = s['b'] # so there's a tie
s.rank()

df = DataFrame(np.random.randn(8, 5))
df[4] = df[2][:5] # some ties
df
df.rank(1)

时间序列和日期函数

熊猫有一个时间序列和日期的范围操纵函数,可以用来执行需要计算时间和日期的计算。

有许多组件可以从时间戳数据中访问。以下是所选组件的列表:

  • :日期时间的年份
  • :日期时间的月份
  • :日期时间的天数
  • 小时:日期时间的小时
  • 分钟:日期时间的分钟
  • :日期时间的秒
  • 微秒:日期时间的微秒
  • 纳秒:日期时间的纳秒
  • 日期:返回日期时间
  • 时间:返回日期时间
  • :一年中的第几天
  • 一年中的第几周:一年中的第几周
  • day fweek:周一=0,周日=6 的一周中的一天
  • 季度:1-3 月=1、4-6 月=2 的日期季度,以此类推。

这里有一个程序演示了这些功能:

import numpy as np
randn = np.random.randn
from pandas import *
# Date Range creation, 152 hours from 06/03/2015
range_date = date_range('6/3/2015', periods=152, freq='H')
range_date[:5]

# Indexing on the basis of date
ts = Series(randn(len(range_date)), index= range_date)
ts.head()

#change the frequency to 40 Minutes
converted = ts.asfreq('40Min', method='pad')
converted.head()
ts.resample('D', how='mean')
dates = [datetime(2015, 6, 10), datetime(2015, 6, 11), datetime(2015, 6, 12)]
ts = Series(np.random.randn(3), dates)
type(ts.index)
ts

#creation of period index
periods = PeriodIndex([Period('2015-10'), Period('2015-11'),
                       Period('2015-12')])
ts = Series(np.random.randn(3), periods)
type(ts.index)
ts

# Conversion to Timestamp
to_datetime(Series(['Jul 31, 2014', '2015-01-08', None]))
to_datetime(['1995/10/31', '2005.11.30'])
# dayfirst to represent the data starts with day
to_datetime(['01-01-2015 11:30'], dayfirst=True)
to_datetime(['14-03-2007', '03-14-2007'], dayfirst=True)
# Invalid data can be converted to NaT using coerce=True
to_datetime(['2012-07-11', 'xyz'])
to_datetime(['2012-07-11', 'xyz'], coerce=True)

#doesn't works properly on mixed datatypes
to_datetime([1, '1'])
# Epoch timestamp : Integer and float epoch times can be converted to timestamp
# the default using is Nanoseconds that can be changed to seconds/ microseconds
# The base time is 01/01/1970
to_datetime([1449720105, 1449806505, 1449892905,
             1449979305, 1450065705], unit='s')
to_datetime([1349720105100, 1349720105200, 1349720105300,
             1349720105400, 1349720105500 ], unit='ms')
to_datetime([8])
to_datetime([8, 4.41], unit='s')

#Datetime Range 
dates = [datetime(2015, 4, 10), datetime(2015, 4, 11), datetime(2015, 4, 12)]
index = DatetimeIndex(dates)
index = Index(dates)
index = date_range('2010-1-1', periods=1700, freq='M')
index
index = bdate_range('2014-10-1', periods=250)
index

start = datetime(2005, 1, 1)
end = datetime(2015, 1, 1)
range1 = date_range(start, end)
range1
range2 = bdate_range(start, end)
range2

日期时间信息也可以用于数据结构中的索引。下面的程序演示了使用日期时间作为索引。它还演示了DateOffset对象的使用:

import numpy as np
randn = np.random.randn
from pandas import *
from pandas.tseries.offsets import *

start = datetime(2005, 1, 1)
end = datetime(2015, 1, 1)
rng = date_range(start, end, freq='BM')
ts = Series(randn(len(rng)), index=rng)
ts.index
ts[:8].index
ts[::1].index

# We can directly use the dates and Strings for index 
ts['8/31/2012']
ts[datetime(2012, 07, 11):]
ts['10/08/2005':'12/31/2014']
ts['2012']
ts['2012-7']

dft = DataFrame(randn(50000,1),columns=['X'],index=date_range('20050101',periods=50000,freq='T'))
dft
dft['2005']
# first time of the first month and last time of month in parameter after :
dft['2005-1':'2013-4']
dft['2005-1':'2005-3-31']
# We can specify stop time
dft['2005-1':'2005-3-31 00:00:00']
dft['2005-1-17':'2005-1-17 05:30:00']
#Datetime indexing
dft[datetime(2005, 1, 1):datetime(2005,3,31)]
dft[datetime(2005, 1, 1, 01, 02, 0):datetime(2005, 3, 31, 01, 02, 0)]

#selection of single row using loc
dft.loc['2005-1-17 05:30:00']
# time trucation
ts.truncate(before='1/1/2010', after='12/31/2012')

处理缺失数据

丢失数据,我们指的是由于任何原因而为空或不存在的数据。一般表示为Na*,其中*表示单个字符,如N表示数字(NaN)T表示日期时间(NaT)。下一个程序演示了 pandas 功能,用于检查丢失的数据,如isNullnotNull,并使用fillnadropnalocilocinterpolate填写丢失的数据。如果我们在NaN上执行任何操作,都会导致NaN:

import numpy as np
randn = np.random.randn
from pandas import *

df = DataFrame(randn(8, 4), index=['I', 'II', 'III', 'IV', 'VI', 'VII', 'VIII', 'X' ], 
    columns=['A', 'B', 'C', 'D']) 

df['E'] = 'Dummy'
df['F'] = df['A'] > 0.5
df

# Introducing some Missing data by adding new index
df2 = df.reindex(['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X'])
df2
df2['A']
#Checking for missing values
isnull(df2['A'])
df2['D'].notnull()

df3 = df.copy()
df3['timestamp'] = Timestamp('20120711')
df3
# Observe the output of timestamp column for missing values as NaT
df3.ix[['I','III','VIII'],['A','timestamp']] = np.nan
df3

s = Series([5,6,7,8,9])
s.loc[0] = None
s

s = Series(["A", "B", "C", "D", "E"])
s.loc[0] = None
s.loc[1] = np.nan
s

# Fillna method to fill the missing value
df2
df2.fillna(0)  # fill all missing value with 0
df2['D'].fillna('missing') # fill particular column missing value with missing

df2.fillna(method='pad')
df2
df2.fillna(method='pad', limit=1)

df2.dropna(axis=0)
df2.dropna(axis=1)

ts
ts.count()
ts[10:30]=None
ts.count()
# interpolate method perform interpolation to fill the missing values
# By default it performs linear interpolation 
ts.interpolate()
ts.interpolate().count()

输入输出操作

熊猫输入输出 API 是一组返回熊猫对象的读取器函数。使用熊猫捆绑的工具加载数据非常容易。数据从各种类型文件中的记录加载到 pandas 数据结构中,如 逗号分隔值 ( CSV )、Excel、HDF、SQL、JSON、HTML、谷歌大查询、pickle、stats 格式和剪贴板。有几个阅读器功能—每种文件一个功能—即read_csvread_excelread_hdfread_sqlread_jsonread_htmlread_stataread_clipboardread_pickle。加载后,数据准备好进行分析。这包括删除错误条目、规范化、分组、转换和排序。

正在处理 CSV 文件

下一个程序演示如何处理 CSV 文件并对其执行各种操作。该程序使用 CSV 格式的图书交叉数据集,从http://www2.informatik.uni-freiburg.de/~cziegler/BX/下载。它包含三个 CSV 文件(BX-Books.csvBX-Users.csvBX-Book-Ratings.csv)。其中包括书籍、用户和用户对书籍的评分的详细信息。有两个传递 CSV 文件名的选项;我们可以将文件放在任意文件夹中并使用完整路径,也可以将文件保留在当前目录中,只传递其名称。以下程序中的文件路径是 Windows 操作系统上的完整路径:

import numpy as np
randn = np.random.randn
from pandas import *

user_columns = ['User-ID', 'Location', 'Age']
users = read_csv('c:\BX-Users.csv', sep=';', names=user_columns)

rating_columns = ['User-ID', 'ISBN', 'Rating']
ratings = read_csv('c:\BX-Book-Ratings.csv', sep=';', names=rating_columns)

book_columns = ['ISBN', 'Book-Title', 'Book-Author', 'Year-Of-Publication', 'Publisher', 'Image-URL-S']
books = read_csv('c:\BX-Books.csv', sep=';', names=book_columns, usecols=range(6))

books
books.dtypes

users.describe()
print books.head(10)
print books.tail(8)
print books[5:10]

users['Location'].head()
print users[['Age', 'Location']].head()

desired_columns = ['User-ID', 'Age'] 
print users[desired_columns].head()

print users[users.Age > 25].head(4)
print users[(users.Age < 50) & (users.Location == 'chicago, illinois, usa')].head(4)

print users.set_index('User-ID').head()
print users.head()

with_new_index = users.set_index('User-ID')
print with_new_index.head()
users.set_index('User_ID', inplace=True)
print users.head()

print users.ix[62]
print users.ix[[1, 100, 200]]
users.reset_index(inplace=True)
print users.head()

这里有一个程序,演示了mergegroupby以及相关操作,如排序、排序、查找最上面的 n 值以及在跨书数据集上的聚合:

import numpy as np
randn = np.random.randn
from pandas import *

user_columns = ['User-ID', 'Location', 'Age']
users = read_csv('c:\BX-Users.csv', sep=';', names=user_columns)
rating_columns = ['User-ID', 'ISBN', 'Rating']
ratings = read_csv('c:\BX-Book-Ratings.csv', sep=';', names=rating_columns)

book_columns = ['ISBN', 'Title', 'Book-Author', 'Year-Of-Publication', 'Publisher', 'Image-URL-S']
books = read_csv('c:\BX-Books.csv', sep=';', names=book_columns, usecols=range(6))

# create one merged DataFrame
book_ratings = merge(books, ratings)
users_ratings = merge(book_ratings, users)

most_rated = users_ratings.groupby('Title').size().order(ascending=False)[:25]
print most_rated

users_ratings.Title.value_counts()[:17]

book_stats = users_ratings.groupby('Title').agg({'Rating': [np.size, np.mean]})
print book_stats.head()

# sort by rating average
print book_stats.sort([('Rating', 'mean')], ascending=False).head()

greater_than_100 = book_stats['Rating'].size >= 100
print book_stats[greater_than_100].sort([('Rating', 'mean')], ascending=False)[:15]

top_fifty = users_ratings.groupby('ISBN').size().order(ascending=False)[:50]

以下程序在https://github . com/gjreda/Greg reda . com/blob/master/content/notebooks/data/city-of-Chicago-sales . CSV 上的 CSV 文件上工作?原始=真

这个程序演示了数据帧的合并和连接操作:

import numpy as np
randn = np.random.randn
from pandas import *

first_frame = DataFrame({'key': range(10), 
                           'left_value': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']})
second_frame = DataFrame({'key': range(2, 12), 
                           'right_value': ['L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U']})
print first_frame
print second_frame

#Natural Join Operation 
print merge(left_frame, right_frame, on='key', how='inner') 
# Left, Right and Full Outer Join Operation
print merge(left_frame, right_frame, on='key', how='left')
print merge(left_frame, right_frame, on='key', how='right')
print merge(left_frame, right_frame, on='key', how='outer')

concat([left_frame, right_frame])
concat([left_frame, right_frame], axis=1)

headers = ['name', 'title', 'department', 'salary']
chicago_details = read_csv('c:\city-of-chicago-salaries.csv',
                      header=False,
                      names=headers,
                      converters={'salary': lambda x: float(x.replace('$', ''))})
print chicago_detail.head()

dept_group = chicago_details.groupby('department')

print dept_group
print dept_group.count().head(10) 
print dept_group.size().tail(10) 
print dept_group.sum()[10:17] 
print dept_group.mean()[10:17] 
print dept_group.median()[10:17] 

chicago_details.sort('salary', ascending=False, inplace=True)

即食数据集

有各种各样的数据来源关于经济学和在熊猫项目中使用这些数据的具体模块。我们可以使用pandas.io.datapandas.io.ga(谷歌分析)模块从各种互联网来源提取数据,并将其添加到数据框中。目前,它支持以下来源:

  • 雅虎!金融
  • 谷歌金融
  • 圣路易斯联邦储备银行:美联储经济数据 ( 弗雷德 ) 是一个由来自 80 个来源的 267,000 多个经济时间序列组成的数据库
  • 肯尼斯·弗伦奇的数据库
  • 世界银行
  • 谷歌分析

这里有一个小程序,演示了如何从这些数据源中读取数据:

import pandas.io.data as web
import datetime
f1=web.DataReader("F", 'yahoo', datetime.datetime(2010, 1, 1), datetime.datetime(2011, 12, 31))
f2=web.DataReader("F", 'google', datetime.datetime(2010, 1, 1), datetime.datetime(2011, 12, 31))
f3=web.DataReader("GDP", "fred", datetime.datetime(2010, 1, 1), datetime.datetime(2011, 12, 31))
f1.ix['2010-05-12']

熊猫在密谋

熊猫数据结构支持包装在plt.plot()方法周围的绘图方法,用于在数据结构中绘制数据。默认情况下,它将显示线图,可以通过将名为“种类”的可选属性传递给绘图方法来更改该线图。以下列表包含了df.plot()中用于生成不同地块的变化:

  • 条形图 : df.plot(kind='bar')
  • 柱状图 : df.plot(kind='hist')
  • 方块图 : df.plot(kind='box')
  • 区域地块 : df.plot(kind='area')-
  • 散射图 : df.plot(kind='scatter')
  • 脚迹 : df.plot(kind='pie')

这个程序演示了熊猫包装方法的一个简单的绘图例子。程序的输出显示在它后面的屏幕截图中:

from pandas import *
randn = np.random.randn
import matplotlib.pyplot as plt
x1 = np.array( ((1,2,3), (1,4,6), (2,4,8)) )
df = DataFrame(x1, index=['I', 'II', 'III'], columns=['A', 'B', 'C']) 
df = df.cumsum()
df.plot(kind='pie', subplots=True)
plt.figure()
plt.show()

The pandas plotting

IPython

IPython 的设计和开发旨在提供一个增强的 Python 外壳,使得执行交互式分布式和并行计算成为可能。IPython 还有一套为科学计算构建专用交互环境的工具。它有两个组件来帮助实现 IPython 的目标:

  • 增强的交互式 IPython 外壳
  • 交互式并行计算的体系结构

在本节中,我们将首先讨论增强交互式 IPython 外壳的组件。我们将在第 8 章并行和大规模科学计算中介绍交互式并行计算的其他组件。

IPython 控制台和系统外壳

IPython 提供的界面如下图所示。我们可以对这个控制台应用不同的着色方案;默认着色方案为NoColor。我们还有其他选择,如LinuxLightBG。IPython 的一个重要特性是它是有状态的,因为它维护在控制台上执行的计算的状态。IPython 中任何步骤的输出都存储在_N中,其中N是输出/结果的数量。当我们进入 IPython 交互式外壳时,它会显示这个增强的交互式 IPython 提供的功能,如下所示:

IPython 3.0.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

如果我们在 shell 中输入问号(?)作为命令,那么它将显示 IPython 特性的详细列表。类似地,%quickref将显示大量 IPython 命令的简短引用,%magic将显示 IPython 魔法命令的详细信息。

The IPython console and system shell

如果我们输入任意一个objectname?,那么控制台将显示该对象的所有细节,例如文档字符串、函数和构造函数,如下图所示。我们已经创建了一个名为df的数据框对象,并使用df?显示了它的细节。

The IPython console and system shell

操作系统界面

有许多情况需要在操作系统的支持下执行计算。用户可以为常用命令创建新的别名。还支持ls等 Unix 命令。用户可以在任何操作命令或 shell 脚本前面加上!来执行它。

The operating system interface

在 Python shel 中执行的操作系统命令

非阻塞绘图

在正常的 Python shell 中,如果我们创建任何一个图,并使用show()方法显示它,那么这个图将显示在一个新的屏幕上,这将保持 shell 被阻止,直到用户关闭显示图的屏幕。但是,IPython 有一个名为–pylab的标志。如果我们使用IPython –pylab命令执行 IPython 外壳,那么从 IPython 外壳打开的绘图窗口将不会阻塞外壳。这显示在下面的截图中——一个绘图窗口在不阻挡外壳的情况下打开,因为 IPython 是用–pylab标志执行的:

Nonblocking plotting

调试

IPython 拥有对程序调试以及错误和异常跟踪的出色支持。脚本执行完毕后,我们可以调用%debug启动 Python 调试器(pdb)来检查问题。我们可以在这里执行调试活动,因为我们可以打印变量值,执行语句,跟踪特定问题的来源。通常,这避免了使用外部调试器应用。

该截图描述了%debug选项:

Debugging

用户可以通过调用%run -d programname.py逐步执行任何程序。这在下面的截图中显示。我们在名为stepbystep.py的程序中有一个步骤。在每个断点处,调试器界面要求用户按下 C 继续下一步:

Debugging

IPython 笔记本电脑

IPython 有一个名为 Notebook 的网络应用。它是为交互式开发和文字计算创作而设计和开发的,其中解释概念、数学方面、实际计算和图形输出的文本可以组合在一起。程序的输入和程序的输出存储在单元格中,如果需要,这些单元格可以就地编辑。

以下截图取自http://ipython.org/notebook.html,展示了 IPython 的界面:

IPython Notebook

总结

在本章中,我们从讨论 matplotlib 的基本概念和体系结构开始。之后,我们讨论了一些用于生成不同类型地块的示例程序。我们还介绍了将这些图保存在不同格式文件中的方法。然后我们讨论了熊猫在数据分析中的应用。

此外,我们还讨论了大熊猫的数据结构。在深入介绍了数据结构的使用之后,您学习了如何执行各种其他相关的数据分析活动。在最后一部分,我们讨论了使用 IPython 的交互式计算的概念、用途和应用。

在下一章中,我们将全面讨论使用 Python 进行科学计算,其中涉及并行和高性能计算。本章将涵盖并行和高性能计算的基本概念,以及可用的框架和技术。稍后,它将深入介绍 Python 在并行和高性能计算中的应用。

八、并行和大规模科学计算

本章讨论了在 Python 中使用并行和大规模计算,或者使用 IPython 解决科学计算问题的重要概念。它涵盖了大规模科学计算和大数据处理的最新趋势。我们将使用示例程序来理解这些概念。

在本章中,我们将涵盖以下主题:

  • IPython 中并行计算的基础
  • IPython 并行计算的组成部分
  • IPython 的任务接口和数据库
  • IPython 的直接接口
  • IPython 并行计算的细节
  • IPython 中的 MPI 程序
  • Python 中使用 Hadoop 和 Spark 的大数据处理

IPython 运行许多不同的进程,使用户能够执行并行计算。这些过程中的第一个是 IPython 引擎,它是一个 Python 解释器,执行用户提交的任务。用户可以运行多个引擎来执行并行计算。第二个过程是 IPython 中枢,它监控引擎和调度器,以跟踪用户任务的状态。集线器进程侦听来自引擎和客户端的注册请求;它持续监控来自调度程序的连接。第三个进程是 IPython 调度程序。这是一组用于在客户端和引擎之间传递命令和结果的进程。通常,调度程序进程运行在运行控制器进程的机器上,并连接到中心进程。最后一个进程是 IPython 客户端,它是 IPython 会话,用于协调引擎执行并行计算。

所有这些进程统称为 IPython 集群。这些进程使用 ZeroMQ 进行相互通信。ZeroMQ 支持各种传输协议,包括 Infiband、IPC、PGM、TCP 等。由集线器和调度器组成的 IPython 控制器监听套接字上客户端的请求。当用户启动引擎时,它会连接到集线器并执行注册。现在,集线器与引擎交换调度器的连接信息。稍后,引擎连接到调度器。这些连接在每台发动机的整个使用寿命中持续存在。每个 IPython 客户端都使用许多套接字连接来连接到控制器。通常,每个调度程序使用一个连接,一个集线器使用三个连接。这些连接在客户的整个生命周期中保持不变。

使用 IPython 的并行计算

IPython 允许用户以交互方式执行并行和高性能计算。我们可以使用 IPython 对并行计算的内置支持,它由四个组件组成,使 IPython 适合大多数类型的并行。具体来说,IPython 支持以下类型的并行:

  • 单程序多数据并行 ( SPMD ):这是最常见的并行编程风格,是多指令多数据 ( MIMD )的一个子类型。在这个模型中,每个任务执行同一个程序的自己的副本。每个任务处理不同的数据集以获得更好的性能。
  • 多程序、多数据并行:在多程序、多数据 ( MPMD )风格中,每个任务执行不同的程序,在每个参与计算节点上处理不同的数据集。
  • 使用 MPI 的消息传递:一个消息传递接口 ( MPI )是消息传递库开发者的规范。它是一个独立于语言的规范,使用户能够编写基于消息传递的并行程序。在其目前的形式中,它支持分布式共享内存模型及其混合模型。
  • 任务并行:任务并行在计算涉及的不同节点之间分配执行进程。该任务可以是线程、消息传递组件或其他编程模型的组件,如 MapReduce。
  • 数据并行:数据并行在并行计算涉及的不同节点之间分配数据。数据并行化的主要重点是数据在不同节点间的分布/并行化,这与任务并行化不同。
  • 上述类型的混合并行 : IPython 还支持任何上述风格的混合并行计算风格。
  • 用户定义的并行方法 : IPython 被设计得非常简单和高度灵活,这种设计重点使用户能够将其用于任何新的或用户定义的并行风格。

IPython 以交互方式支持所有类型并行应用的程序开发生命周期的各个阶段,如开发、执行、调试、监控等。

将 matplotlib 与 IPython 结合使用,使用户能够分析和可视化远程或分布式大型数据集。它还使他们能够在集群上开始作业处理,并在本地系统上提取数据进行分析和可视化。用户可以从台式机/笔记本电脑上的 IPython 会话将 MPI 应用推送到高性能计算机上。它还支持在一组 CPU 上运行的不同任务的动态负载平衡。此外,它支持许多简单的方法,允许用户用两行或三行代码交互式地并行化许多简单的应用。用户可以交互地开发、执行、测试和调试定制的并行算法。IPython 使用户能够将在不同计算节点上执行的不同 MPI 作业捆绑到单个、巨大的分布式和/或并行系统中。

IPython 并行计算的体系结构

IPython 中并行计算的体系结构有三个主要组成部分。这些组件是 IPython 并行包的一部分。IPython 并行计算的体系结构如下图所示:

The architecture of IPython parallel computing

IPython 并行计算的三个主要组件是客户端控制器引擎控制器组件由两个子组件组成: HUBSCHEDULERS 。它允许客户端通过两个主要接口与引擎交互:直接接口和负载平衡接口。

并行计算的组成部分

本小节将讨论与 IPython 并行计算架构相关的各种组件和概念。这些组件是 IPython 引擎、IPython 控制器(集线器和调度器)以及 IPython 客户端和视图。

IPython 发动机

核心组件执行作为网络请求接收的 Python 命令的实际执行。该引擎是一个普通 Python 解释器的实例,最终它将成为一个完整的 IPython 解释器。用户可以通过启动多个引擎来执行分布式计算和并行计算。用户代码在阻塞模式下在 IPython 引擎中执行。

IPython 控制器

控制器由一个中枢和一组调度器组成。IPython 控制器是客户端和引擎用于通信的一组进程。它是让引擎执行 Python 进程的用户的联系点。通常,调度程序是在集线器运行的同一台机器上运行的独立进程。在某些特殊情况下,调度程序在远程计算机上运行:

  • Hub:Hub 是最重要的组件,它跟踪调度器、客户端以及与引擎的连接。它处理客户端和引擎的所有连接以及整个流量。它还维护所有请求和结果的持久数据库,这些请求和结果将在应用的后续阶段使用。集线器提供了查询集群状态的功能,并隐藏了客户端和引擎之间许多连接的实际细节。
  • 调度器:提交给引擎处理的 Python 命令通过调度器被定向。调度器还解决了执行用户代码时引擎阻塞的问题。调度器设法对用户隐藏这个问题,并提供对 IPython 引擎集合的完全异步访问。

IPython 视图和界面

控制器提供两个接口与引擎交互。第一个接口是Direct接口,其中引擎被直接寻址用于任务分配。第二个接口是LoadBalanced接口,其中任务到引擎的正确分配留给调度器。IPython 的灵活设计使我们能够扩展视图,以实现更复杂的接口方案。

对于控制器的不同连接方式,有一个view对象。以下是通过控制器与机器交互的两种模式:

  • DirectView类,支持直接寻址。它允许在所有引擎上执行命令。
  • LoadBalancedView类以负载平衡的方式代表用户处理任务农业。它允许在任何一个引擎上执行命令,用于执行的引擎由调度程序决定。

IPython 客户端

客户端是用于连接到群集的对象。在创建客户端对象的过程中,用户可以选择前面讨论的两个视图中的任何一个。一旦创建了客户端,只要作业运行,它就会一直存在。当超时周期结束或用户调用kill功能时,它被破坏。

执行并行计算的示例

以下程序是使用 IPython 执行并行计算的一个简单示例。它计算单个引擎或所有引擎中并行的集群的功率。在执行该程序之前,建议您根据需要检查zmq包是否安装。

要在 IPython 中运行这些程序,首先使用ipcluster start --n=4 --profile=testprofile命令启动 IPython 集群。它将在<userhome>/.ipython/profile_testprofile/security目录中创建ipcontroller-engine.jsonipcontroller-client.json文件。当我们通过传递profile='testprofile'创建客户端时,这些文件将被搜索。如果我们使用parallel.Client()创建客户端,那么它将在profile_default文件夹中搜索 JSON 文件。

首先,程序定义了一个计算功率的函数,然后使用测试配置文件创建一个客户端。要在引擎中调用 Python 函数,我们可以使用客户端或视图的apply方法。Python map函数对序列执行串行计算。在DirectViewLoadBalancedView中均有map函数对序列执行并行计算。我们也可以在阻塞或非阻塞模式下执行这些调用。要设置阻挡模式,我们可以将客户端或视图的block属性设置为true;默认为false:

from IPython import parallel
def pow(a, b):
  return a ** b
clients = parallel.Client(profile='testprofile')
print clients.ids
clients.block = True
clients[0].apply(pow, 2, 4)
clients[:].apply(pow, 2, 4)
map(pow, [2, 3, 4, 5], [2, 3, 4, 5])
view = clients.load_balanced_view()
view.map(pow, [2, 3, 4, 5], [2, 3, 4, 5])

一个并行的装饰器

DirectView中有一个并行装饰器,创建parallel函数。该函数对序列进行操作,并分解元素式操作。随后,它将它们分配给并行计算,最后,它会重建结果。LoadBalancedView的装饰器把 Python 函数变成了parallel函数:

from IPython import parallel
clients = parallel.Client(profile='testprofile')
lbview = clients.load_balanced_view()
lbview.block = True
serial_computation = map(lambda i:i**5, range(26))
parallel_computation = lbview.map(lambda i: i**5, range(26))
@lbview.parallel()
def func_turned_as_parallel(x):
     return x**8
func_turned_as_parallel.map(range(26))

IPython 的神奇功能

IPython 有许多用户可以作为命令调用的神奇功能。IPython 中有两种类型的魔法命令,即线魔法和细胞魔法。线路魔法功能以%为前缀,像操作系统命令一样执行它们的功能。而细胞魔法函数的前缀是%%,它们把剩下的一行和后面的一行作为不同的参数。

当用户创建客户端时,这些神奇的功能变得可用。线魔函数的描述如下:

  • %px:这可以在选定的引擎上执行单个 Python 命令。用户可以通过设置视图实例的目标属性来选择引擎。
  • %pxconfig:即使没有任何活动视图,也可以使用pxconfig魔法功能指定--targets--block–noblock
  • %autopx:这是并联和非并联模式的切换开关。在第一次调用时,它会将控制台切换到一种模式,在这种模式下,所有键入的命令/函数调用将以并行模式执行,直到用户再次调用%autopx
  • %pxresult:在非阻塞模式下,%px不返回结果。我们可以看到使用pxresult魔法命令的最新命令的结果。

在 cell magic 模式下,px ( %%px ) magic 接受--targets选项指定要使用的目标引擎,--block--noblock指定阻塞或非阻塞执行模式。这在我们没有视图实例的情况下特别有用。它还有一个参数--group-output,可以管理多个引擎输出的呈现。

下面的程序说明了pxpxresult作为线魔法和细胞魔法的使用。它还涵盖了autopxpxconfig线魔法,并为这些魔法创建了特定的后缀。程序的第二行和第三行在 IPython 会话和所有引擎上执行导入。第二行之后创建的块内的所有导入也将在引擎上执行:

from IPython import parallel
drctview = clients[:]
with drctview.sync_imports():
   import numpy
clients = parallel.Client(profile='testprofile')
drctview.activate()
drctview.block=True
%px dummymatrix = numpy.random.rand(4,4)
%px eigenvalue = numpy.linalg.eigvals(dummymatrix)
drctview['eigenvalue']

%pxconfig --noblock
%autopx
maximum_egnvals = []
for idx in range(50):
    arr = numpy.random.rand(10,10)
    egnvals = numpy.linalg.eigvals(arr)
    maximum_egnvals.append(egnvals[0].real)
%autopx
%pxconfig --block 
%px answer= "The average maximum eigenvalue is: %f"%(sum(maximum_egnvals)/len(maximum_egnvals))
dv['answer']

%%px --block --group-outputs=engine
import numpy as np
arr = np.random.random (4,4)
egnvals = numpy.linalg.eigvals(arr)
print egnvals
egnvals.max()
egnvals.min()

odd_view = clients[1::2]
odd_view.activate("_odd")
%px print "Test Message"
odd_view.block = True
%px print "Test Message"
clients.activate()
%px print "Test Message"
%px_odd print "Test Message"

激活特定视图

默认情况下,这些魔法函数与一个DirectView对象相关联。允许用户通过在任何特定视图上调用activate()方法来更改DirectView对象。激活视图时,我们可以提到一个新的后缀,如odd_view.activate("_odd")中定义的。对于这个观点,我们现在有了一套新的魔法函数以及原来的魔法函数,比如%px_odd,它用在前面程序的最后一行。

引擎和 QtConsole

px神奇功能允许用户将 QtConsole 连接到引擎进行调试。下面的程序片段演示了如何通过绑定引擎内核来监听连接,从而将 QtConsole 连接到引擎:

%px from IPython.parallel import bind_kernel; bind_kernel()
%px %qtconsole
%px %connect_info

IPython 的高级特性

在接下来的小节中,我们将讨论 IPython 的各种高级特性。

容错执行

IPython 任务接口将引擎准备为容错和动态负载平衡的集群系统。在任务界面中,用户无权访问引擎。相反,任务分配完全依赖于调度器,这使得界面的设计简单、灵活且强大。

如果任务在 IPython 中由于任何原因失败,那么该任务将被重新排队,并再次尝试执行。如果出现故障,用户可以配置系统进行预定义次数的重试,他们也可以重新提交任务。

如果需要,用户可以显式重新提交任何任务。或者,他们可以设置一个标志,通过设置视图或计划程序的标志,在预定义的次数内重试该任务。

如果用户确定错误的原因不是代码中的错误或问题,那么他们可以将重试标志设置为从 1 到引擎总数的任何整数值。

最大限制等于引擎数量的原因是任务不会被重新提交给失败的引擎。

有两个选项可以设置重新提交次数的标志值。一种是使用LoadBalancedView(考虑对象名称为lbvw)对象设置值后,设置所有后续任务,如下:

lbvw.retries = 4

另一种是使用with ...temp_flags为单个块设置值,如下所示:

with lbvw.temp_flags(retries=4):
    lbview.apply(task_tobe_retried)

动态负载平衡

调度器还可以被配置为基于各种调度策略来执行调度。IPython 支持多种方案,在负载平衡请求的情况下将任务分配给机器。集成定制方案也非常容易。有两种选择方案的方法。一种是设置控制器的config对象的taskSchedulerscheme_name属性。第二种选择是通过将方案参数传递给ipcontroller来选择方案,如下所示:

ipcontroller --scheme=<schemename>

这里有一个例子:

ipcontroller --scheme=lru

<schemename>功能可以是以下任何一种:

  • lru : 最近最少使用的 ( LRU )是将任务分配给最近最少使用的引擎的方案。
  • plainrandom:在这个方案中,调度器随机挑选一个引擎运行任务。
  • twobin:该方案使用 NumPy 函数分配任务。它是plainrandomlru的组合,因为它随机选择两个引擎,并从这两个引擎中选择最近最少使用的。
  • leastload:这个方案是调度器的默认方案。它将任务分配给负载最小的引擎(即剩余任务数最少的引擎)。
  • weighted:这个方案是twobin方案的变体,因为它随机挑选两个引擎,并将未完成任务的负载或数量分配为权重的倒数。它将任务分配给负载相对较小的发动机。

在客户端和引擎之间推拉对象

除了在引擎上调用函数和执行代码,IPython 还允许用户在 IPython 客户端和引擎之间移动 Python 对象。push方法将对象从客户端推送到引擎,pull方法可用于将任意对象从引擎拉回客户端。在非阻塞模式下,推拉返回AsyncResult对象。要在非阻塞模式下显示结果,我们可以如下拉取对象:rslt = drctview.pull(('a','b','c'))。我们可以调用rslt.get()来显示被拉对象中的值。在某些情况下,对输入数据序列进行分区并将不同的分区推送到不同的引擎是非常有用的。这种划分实现为scattergather功能,类似于 MPI。scatter操作用于将分区序列从客户端(IPython 会话)推送到引擎,而gather操作用于将分区从引擎取回客户端。

所有这些功能将在下面的程序中演示。最后,使用scattergather实现两个矩阵的平行点积:

import numpy as np
from IPython import parallel
clients = parallel.Client(profile='testprofile')
drctview = clients[:]
drctview.block = True
drctview.push(dict(a=1.03234,b=3453))
drctview.pull('a')
drctview.pull('b', targets=0)
drctview.pull(('a','b'))
drctview.push(dict(c='speed'))
drctview.pull(('a','b','c'))
drctview.block = False
rslt = drctview.pull(('a','b','c'))
rslt.get()

drctview.scatter('a',range(16))
drctview['a']
drctview.gather('a')

def paralleldot(vw, mat1, mat2):
    vw['mat2'] = mat2
    vw.scatter('mat1', mat1)
    vw.execute('mat3=mat1.dot(mat2)')
    return vw.gather('mat3', block=True)
a = np.matrix('1 2 3; 4 5 6; 7 8 9')
b = np.matrix('4 5 6; 7 8 9; 10 11 12')
paralleldot(drctview, a,b)

下面的程序演示了将对象从客户端推送到引擎以及将结果从引擎拉回到客户端的方法。它在所有引擎上执行两个矩阵的点积,最后收集结果。它还使用allclose()方法验证所有结果是否相同,如果对象相同,则返回True。在以下程序的execute命令中,添加了print mat3语句,目的是使用display_outputs()方法显示所有发动机的标准输出设备的输出:

import numpy as np
from IPython.parallel import Client
ndim = 5
mat1 = np.random.randn(ndim, ndim)
mat2 = np.random.randn(ndim, ndim)
mat3 = np.dot(mat1,mat2)
clnt = Client(profile='testprofile')
clnt.ids
dvw = clnt[:]
dvw.execute('import numpy as np', block=True)
dvw.push(dict(a=mat1, b=mat2), block=True)
rslt = dvw.execute('mat3 = np.dot(a,b); print mat3', block=True)
rslt.display_outputs()
dot_product = dvw.pull('mat3', block=True)
print dot_product
np.allclose(mat3, dot_product[0])
np.allclose(dot_product[0], dot_product[1])
np.allclose(dot_product[1], dot_product[2])
np.allclose(dot_product[2], dot_product[3])

用于存储请求和结果的数据库支持

IPython 中枢存储关于请求的信息和处理任务的结果,供以后使用。它的默认数据库是 SQLite,目前支持 MongoDB 和一个名为DictDB的内存数据库。用户必须配置用于他们的配置文件的数据库。在活动的配置文件文件夹中,有一个名为ipcontroller_config.py的文件。这个文件将在我们启动ipcluster时创建。该文件有一个c.HubFactory.db_class条目;用户应该将其设置到他们选择的数据库中,如下所示:

#dict-based in-memory database named as dictdb
c.HubFactory.db_class = 'IPython.parallel.controller.dictdb.DictDB'
# For MongoDB:
c.HubFactory.db_class = 'IPython.parallel.controller.mongodb.MongoDB'
# For SQLite:
c.HubFactory.db_class = 'IPython.parallel.controller.sqlitedb.SQLiteDB'

该属性的默认值为NoDB,表示不使用数据库。要获得任何已执行任务的结果,用户可以在客户端对象上调用get_result函数。客户对象有一个更好的方法叫做db_query()来获得更多关于任务结果的见解。该方法是以 MongoDB 查询方式设计的。它从具有精确值的TaskRecord关键字列表中获取一个带有关键字的字典查询对象,或者 MongoDB 查询。这些论点遵循{'operator' : 'argument(s)'}语法。它还有一个名为keys的可选参数。此参数用于指定要检索的键。它返回一个TaskRecord字典列表。默认情况下,它检索除请求和结果缓冲区之外的所有键。msg_id键将始终包含在响应中,类似于 MongoDB。下表解释了各种任务记录键:

  • msg_id:该值为uuid(字节)类型。它代表消息标识。
  • header:该值为dict类型,保存请求头。
  • content:该值为dict类型,保存一般为空的请求内容。
  • buffers:这个值是list(字节)类型,它将是一个包含序列化请求对象的缓冲区。
  • Submitted:该值为datetime类型,保存提交时间戳。
  • client_uuid:该值是 uuid(以字节为单位的通用唯一标识符)。
  • engine_uuid:该值为保存发动机插座标识的uuid(字节)类型。
  • started:该值为datetime类型,保存某个引擎上任务执行开始的时间。
  • completed:该值为datetime类型,保存任务在引擎上执行完成的时间。
  • resubmitted:该值为datetime类型,如果适用,保存任务重新提交的时间。
  • result_header:该值为dict类型,保存结果的表头。
  • result_content:该值为dict类型,保存结果的内容。
  • result_buffers:这个值是list(字节)类型,它将是一个包含序列化结果对象的缓冲区。
  • queue:该值为bytes类型,代表任务的队列名称。
  • stdout:这是一串标准输出 ( 标准输出)数据。
  • stderr:这是一串标准误差 ( 标准误差)数据。

以下程序演示了用于访问结果信息的db_query()get_result()方法的概念:

from IPython import parallel
from datetime import datetime, timedelta
clients = parallel.Client(profile='testprofile')
incomplete_task = clients.db_query({'complete' : None}, keys=['msg_id', 'started'])
one_hourago = datetime.now() - timedelta(1./24)
tasks_started_hourago = clients.db_query({'started' : {'$gte' : one_hourago },'client_uuid' : clients.session.session})
tasks_started_hourago_other_client = clients.db_query({'started' : {'$le' : hourago }, 'client_uuid' : {'$ne' : clients.session.session}})
uuids_of_3_n_4 = map(clients._engines.get, (3,4))
headers_of_3_n_4 = clients.db_query({'engine_uuid' : {'$in' : uuids_of_3_n_4 }}, keys='result_header')

db_query中支持以下关系运算符作为 MongoDB:

  • '$in':这代表列表/序列中操作的
    ** '$nin':这表示列表/序列上的操作中没有** '$eq':这个用来表示等于 ( ==)* '$ne':这是用来表示不等于 ( !=)* '$gt':这个用来表示大于 ( >)* '$gte':表示大于等于 ( >=)* '$lt':这是用来表示小于 ( <)* '$lte':用于表示小于等于 ( <=)**

**## 在 IPython 中使用 MPI

通常,在多个引擎上运行的并行算法需要在引擎之间移动数据。我们已经介绍了 IPython 执行这种数据移动的内置方式。但是,这是一个缓慢的操作,因为它不是客户端和引擎之间的直接传输。数据必须通过控制器传输。获得良好性能的更好方法是使用消息传递接口 ( MPI )。IPython 的并行计算对与 MPI 的集成有出色的支持。要将 MPI 与 IPython 并行计算结合使用,我们需要安装一个 MPI 实现,如OpenMPIMPICH2 / MPICHmpi4py python 包。安装后,测试系统是否能够执行mpiexecmpirun命令。

测试安装之后,在实际运行 MPI 程序之前,用户需要使用以下命令创建 MPI 执行的配置文件:

ipython profile create --parallel --profile=mpi

轮廓创建后,在profile_mpi文件夹的ipcluster_config.py中添加以下线条:

c.IPClusterEngines.engine_launcher_class = 'MPIEngineSetLauncher'

现在,系统准备在 IPython 上执行基于 MPI 的程序。用户可以使用以下命令启动群集:

ipcluster start -n 4 --profile=mpi

前面的命令启动 IPython 控制器,并使用mpiexec启动四个引擎。

下面的程序定义了一个计算分布式数组总和的函数。将文件名保存为parallelsum.py,因为这个名称将在下一个程序中使用,该程序实际上调用了这个函数:

from mpi4py import MPI
import numpy as np

def parallelsum(arr):
    localsum = np.sum(arr)
    receiveBuffer = np.array(0.0,'d')
    MPI.COMM_WORLD.Allreduce([localsum, MPI.DOUBLE],
        [receiveBuffer, MPI.DOUBLE],
        op=MPI.SUM)
    return receiveBuffer

现在调用前面程序中定义的函数,以便在多个引擎上执行它。这样做是为了对数组执行并行求和:

from IPython.parallel import Client
clients = Client(profile='mpi')

drctview = clients[:]
drctview.activate() 
#execute the program name passed as argument
drctview.run(parallelsum.py.py')
drctview.scatter('arr',np.arange(20,dtype='float'))
drctview['arr']
# calling of the function
%px sum_of_array = parallelsum(arr)
drctview['sum_of_array']

管理任务之间的依赖关系

它对管理各种任务之间的依赖关系有很强的支持。在大多数科学和商业应用中,只有负载平衡方案不足以管理其复杂性。这些应用需要多个任务之间的依赖性。这些依赖关系描述了特定的软件、Python 模块、操作系统或硬件需求;序列;计时;和任务集合中任务的执行位置。IPython 支持两种依赖,即函数依赖和图依赖。

功能依赖

功能相关性用于确定特定引擎是否能够运行任务。这个概念是使用来自IPython.parallel.error的特殊异常UnmetDependency实现的。如果任务因UnmetDependency异常而失败,调度程序不会将此错误传播给客户端。相反,它会处理这个错误,并将这个任务提交给其他引擎。调度程序重复这个过程,直到找到合适的引擎。此外,调度程序不会两次向引擎提交任务。

功能依赖的装饰者

虽然允许用户手动引发UnmetDependency异常,但是 IPython 提供了两个装饰器来管理这个依赖问题。有两个装饰器和一个用于函数依赖的类:

  • @require: This decorator manages the dependency of a task that requires that a particular Python module, local function, or local object be available on an engine when the decorated function is called. Functions will be pushed to the engine with their names, and objects can be passed using the arg keyword. We can pass the names of all the Python modules required to execute this task. Using this decorator, a user can define a function to be executed on only those engines where the module names passed to this decorator are available and importable.

    例如,下面代码片段中定义的函数依赖于 NumPy 和 pandas 模块,因为它使用 NumPy 中的randn和 pandas 中的Series。如果对于某个任务,我们调用这个函数,那么它将在这两个模块可导入的机器上执行。调用此函数时,将导入 NumPy 和 pandas。

    from IPython.parallel import depend, require
    # the following function uses randn and Series
    @require('pandas', 'numpy')
    def func_uses_functions_from_numpy_pandas():
      return performactivity()
    
  • @depend: This decorator allows users to define a function that has a dependency on some other function. It determines whether the dependency is met or not. Before starting the task, the dependency function will be called, and if this function returns true, then the actual processing of the task will be started. Moreover, if this dependency function returns false, then the dependency is considered to be unmet and the task is propagated to some other engine.

    例如,下面的代码片段首先创建一个依赖函数,用于验证引擎的操作系统是否与给定的操作系统匹配。这是因为用户希望编写两个不同的函数来执行 Linux 和 Windows 操作系统上的特定活动:

    from IPython.parallel import depend, require
    def find_operating_system(plat):
        import sys
        return sys.platform.startswith(plat)
    @depend(find_operating_system, 'linux')
    def linux_specific_task():
        perform_activity_on_linux()
    @depend(platform_specific, 'win')
    def linux_specific_windows():
        perform_activity_on_windows()
    

图形相关性

还有另一类重要的依赖关系,任务之间相互依赖,任务必须在某些或所有特定任务成功执行后才能执行。另一个依赖关系可能如下:任务必须在满足一组特定依赖关系的目标上执行。通常,用户需要一个选项来指定运行给定任务的时间和位置,作为时间、位置和其他任务结果的函数。有一个单独的名为Dependency的类来管理图形依赖关系,Dependency是类Set的子类。它包含一组与任务相对应的消息标识,并且它还具有一些属性。这些属性有助于检查是否满足指定的依赖关系:

  • any|all:这些属性指定是否完成或满足任何指定的依赖关系。这将通过设置默认为True的所有依赖属性来指定。
  • success:该属性默认为True,用于指定如果指定任务成功,则认为满足依赖关系。
  • failure:该属性默认为False,用于指定如果指定任务失败,则认为满足依赖关系。
  • after:该属性用于指定依赖任务在执行指定任务后执行。
  • follow:follow属性指定从属任务应与其中一个从属任务在同一目的地执行。
  • timeout:该属性用于指定调度程序必须等待依赖项满足的持续时间。默认为0,表示从属任务将永远等待。超时后,从属任务失败,出现DependencyTimeout异常。

有些任务可以作为清理任务。它们应该只在指定任务失败时运行。用户应使用failure=True,success=False进行此类任务。对于某些依赖任务,需要依赖任务成功完成。在这种情况下,用户必须设置success=Truefailure=False。在某些情况下,用户希望独立于依赖任务的成功或失败来执行依赖任务。在这种情况下,用户必须使用success=failure=True

不可能的依赖

可能有些依赖是不可能满足的。如果调度程序没有处理这种可能性,那么调度程序可能会一直等待依赖性得到满足。为了应对这种情况,调度程序会分析图的依赖关系,以估计满足依赖关系的可能性。如果调度程序能够识别出某个任务的依赖性无法满足,那么该任务将失败并出现ImpossibleDependency错误。下面的代码片段演示了任务之间的图形依赖关系的使用:

from IPython.parallel import *
clients = ipp.Client(profile='testprofile')
lbview = clients.load_balanced_view()

task_fail = lbview.apply_async(lambda : 1/0)
task_success = lbview.apply_async(lambda : 'success')
clients.wait()
print("Fail task executed on %i" % task_fail.engine_id)
print("Success task executed on %i" % task_success.engine_id)

with lbview.temp_flags(after=task_success):
    print(lbview.apply_sync(lambda : 'Perfect'))

with lbview.temp_flags(follow=pl.Dependency([task_fail, task_success], failure=True)):
    lbview.apply_sync(lambda : "impossible")

with lbview.temp_flags(after=Dependency([task_fail, task_success], failure=True, success=False)):
    lbview.apply_sync(lambda : "impossible")

def execute_print_engine(**flags):
    for idx in range(4):
        with lbview.temp_flags(**flags):
            task = lbview.apply_async(lambda : 'Perfect')
            task.get()
            print("Task Executed on %i" % task.engine_id)

execute_print_engine(follow=Dependency([task_fail, task_success], all=False))
execute_print_engine(after=Dependency([task_fail, task_success], all=False))
execute_print_engine(follow=Dependency([task_fail, task_success], all=False, failure=True, success=False))
execute_print_engine(follow=Dependency([task_fail, task_success], all=False, failure=True))

DAG 依赖关系和网络库

一般来说,最好用有向无环图 ( DAG )来表示并行工作流。Python 有一个流行的库,叫做 NetworkX,用于使用图形。该图是节点和有向边的集合。边连接各种节点;每个边都有一个相关的方向。我们可以用这个概念来表示依赖关系。例如,从任务 1 到任务 2 的edge(task1, task2)表示任务 2 依赖于任务 1。类似地,edge(task2, task1)表示任务 1 依赖于任务 2。这个图不能包含任何循环,这就是为什么它被称为非循环图。

现在考虑下图中描述的六节点 DAG。表示 Task0 不依赖任何任务,因此可以立即启动。而任务 1任务 2 依赖于任务 0 ,因此它们将在任务 0 完成后开始。那么任务 3 同时依赖于任务 1任务 2 ,所以在任务 1任务 2 结束后执行。同样的,任务 4任务 5 将在任务 3 结束后执行。任务 6 仅依赖于任务 4 。因此,它将在任务 4 完成执行后启动。

The DAG dependency and the NetworkX library

这是一个源代码片段,代表上图中描述的 DAG。在代码中,任务由它们的编号表示;即任务 0 用 0 表示,任务 1 用 1 表示,以此类推:

import networkx as ntwrkx
import matplotlib.pyplot as plt

demoDAG = ntwrkx.DiGraph()
map(demoDAG.add_node, range(6))
demoDAG.add_edge(0,1)
demoDAG.add_edge(0,2)
demoDAG.add_edge(1,3)
demoDAG.add_edge(2,3)
demoDAG.add_edge(3,4)
demoDAG.add_edge(3,5)
demoDAG.add_edge(4,6)
pos = { 0 : (0,0), 1 : (-1,1), 2 : (1,1), 3 : (0,2), 4 : (-1,3), 5 : (1, 3), 6 : (-1, 4)}
labels={}
labels[0]=r'$0$'
labels[1]=r'$1$'
labels[2]=r'$2$'
labels[3]=r'$3$'
labels[4]=r'$4$'
labels[5]=r'$5$'
labels[6]=r'$6$'

ntwrkx.draw(demoDAG, pos, edge_color='r')
ntwrkx.draw_networkx_labels(demoDAG, pos, labels, font_size=16)
plt.show()

以下程序用彩色边和顶点标签创建相同的图表:

import networkx as ntwrkx
import matplotlib.pyplot as plt

demoDAG = ntwrkx.DiGraph()
map(demoDAG.add_node, range(6))

pos = { 0 : (0,0), 1 : (-1,1), 2 : (1,1), 3 : (0,2), 4 : (-1,3), 5 : (1, 3), 6 : (-1, 4)}

ntwrkx.draw(demoDAG, pos)
ntwrkx.draw_networkx_edges(demoDAG,pos,
                       edgelist=[(0,1),(0,2),(1,3),(2, 3),(3, 4)],edge_color='r')
ntwrkx.draw_networkx_edges(demoDAG,pos,
                       edgelist=[(3,5),(4,6)],edge_color='b')

ntwrkx.draw_networkx_nodes(demoDAG,pos,
                       nodelist=[0,1,2,3,4],
                       node_color='r',
                       node_size=500,
                   alpha=0.8)
ntwrkx.draw_networkx_nodes(G,pos,
                       nodelist=[5,6],
                       node_color='b',
                       node_size=500,
                   alpha=0.8)

labels={}
labels[0]=r'$0$'
labels[1]=r'$1$'
labels[2]=r'$2$'
labels[3]=r'$3$'
labels[4]=r'$4$'
labels[5]=r'$5$'
labels[6]=r'$6$'

ntwrkx.draw_networkx_labels(demoDAG, pos, labels, font_size=16)
plt.show() 

在带有 StarCluster 的 Amazon EC2 集群上使用 IPython

StarCluster 旨在简化在亚马逊弹性计算云 ( EC2 )上使用虚拟机集群的过程。它是亚马逊 EC2 上集群计算的开源工具包。除了执行自动集群配置,星簇还提供亚马逊机器映像 ( AMIs )定制支持科学计算和软件开发的工具包和库。这些 AMIs 由 ATLAS、IPython、NumPy、OpenMPI、SciPy 等组成。用户可以在安装了 StarCluster 的机器上使用以下命令检索可用的 AMIs 列表:

starcluster listpublic

StarCluster 有一个非常简单直观的界面,用于计算集群的弹性管理和存储管理。安装后,用户必须更新其默认配置文件,以更新 Amazon EC2 帐户的详细信息,包括地址、地区、凭据和公钥/私钥对。

安装和配置完成后,用户可以使用以下命令从本地 IPython 安装中控制 Amazon EC2 集群:

starcluster shell --ipcluster=clusterName

如果配置中有任何错误,将通过前面的命令显示。如果配置是正确的,那么这个命令启动 StarCluster 的开发外壳,并在 Amazon EC2 上为远程集群配置一个并行会话。StarCluster 会自动创建一个名为ipclient的并行客户端,并以ipview的名称查看整个集群。用户可以使用这些变量(ipclientipview)在亚马逊 EC2 集群上运行并行任务。以下代码片段使用ipclient显示集群的引擎标识,并使用ipview运行一个小的并行任务:

ipclient.ids
result = ipview.map_async(lambda i: i**5, range(26))
print result.get()

用户还可以使用带有星簇的 IPython 并行脚本。如果用户希望从本地 IPython 会话在远程 Amazon EC2 集群上运行 IPython 并行脚本,那么他们应该在创建并行客户端的过程中使用一些配置细节,如下所示:

from IPython.parallel import Client
remoteclients = Client('<userhome>/.starcluster/ipcluster/<clustername>-<yourregion>.json',  sshkey='/path/to/cluster/keypair.rsa')

具体来说,假设一个集群的名称是packtcluster,区域是us-west-2,而keypair的名称是packtKey,存储在/home/user/.ssh/packtKey.rsa中。然后,前面的代码将更改为以下内容:

from IPython.parallel import Client
remoteclients = Client('/home/user/.starcluster/ipcluster/packtcluster-us-west-2.json', sshkey='/home/user/.ssh/packtKey.rsa')

在这两行代码之后,所有剩余的代码都将在 Amazon EC2 上的远程集群上执行。

关于 IPython 安全性的一个注记

在设计 IPython 的体系结构时,已经考虑到了安全问题。基于能力的客户端身份验证模型,以及 SSH 隧道传输的 TCP/IP 通道,管理主要的潜在安全问题,并允许用户在开放网络中使用 IPython 集群。

ZeroMQ 不提供安全性。因此,SSH 隧道是建立安全连接的主要来源。Client对象从ipcontroller-client.json文件获取与控制器建立连接的信息,然后使用 OpenSSH/Paramiko 创建隧道。

它还使用 HMAC 摘要的概念,使用保护共享机器用户的共享密钥对消息进行签名。有一个处理消息协议的会话对象。此对象使用唯一密钥验证消息的有效性。默认情况下,这个密钥是一个 128 位的伪随机数,类似于uuid.uuid4()生成的数字。一般来说,在并行计算过程中,IPython 客户端用于向 IPython 引擎发送 Python 函数、命令和数据,以执行和处理数据。IPython 确保只有客户端负责并能够使用引擎的功能。引擎从启动引擎的用户那里继承能力和权限。

为了防止未经授权的访问,身份验证和密钥相关的信息被编码在 JSON 文件中,客户端使用该文件来访问 IPython 控制器。用户可以通过限制密钥的分发来授予授权人员访问权限。

众所周知的并行编程风格

由于计算机硬件和软件的发展,并行程序可以用几种方式来设计、开发和实现。我们可以使用并发、并行或分布式的方式来实现一个程序。通常,前面提到的技术之一用于实现程序,以实现高效执行和提高性能。接下来的小节将讨论这些模型以及与之相关的常见问题。

并行编程中的问题

所有这些模型都依赖于程序的不同部分在独立的计算元素(中央处理器和计算节点)上执行的基本概念。通常,这些模型将程序分成多个工作程序,每个工作程序在不同的计算元素上开始执行。尽管有性能上的好处,这种类型的程序执行——使用多个工作人员——在通信中带来了多种复杂性。这个问题叫做进程间通信 ( IPC )。

有几个经典的 IPC 问题需要开发人员注意,即死锁、饥饿和竞争条件:

  • 死锁:死锁是两个或两个以上的工作者处于无限等待状态,以获取另一个等待工作者所占用的资源的情况。对此有四个充要条件,即互斥、保持等待、不抢占和循环等待。如果在任何程序的执行过程中出现这些情况,则该程序将被阻止,并且无法继续执行:
    • 互斥意味着资源不可共享
    • 我们所说的“等待”是指处于死锁状态的每个工作人员都持有一些资源并请求一些额外的资源
    • 无优先权意味着分配给一个工作者的资源不能被优先分配给另一个工作者
    • 最后,通过循环等待,我们意味着死锁下的工人形成一个链,或循环列表,其中每个工人都在等待列表中下一个工人持有的资源
  • 饥饿:当多个工人争夺单一资源时,就会出现这种情况。在这种情况下,每个工作人员都被分配了资源分配的优先级。有时,这种优先分配变得不公平,一些工人的执行被拖延了很长时间。假设有两种类型的员工在竞争一种资源:高优先级的员工和低优先级的员工。如果高优先级工作人员不断到来,那么可能会出现这样一种情况,即一些低优先级工作人员为了获得高优先级工作人员释放的资源而经历漫长(无限)的等待。
  • 竞态条件:当有多个工作人员同时对公共数据执行读和写操作,并且他们执行的操作之间缺乏同步时,就会出现这个问题。例如,假设两个工作人员从数据库中读取一条公共数据,修改其值,然后将该数据写回数据库。如果这些操作没有以良好同步的顺序执行,它们将使数据库处于不一致的状态。

有一些技术可以用来避免这些问题,尽管它们的详细讨论超出了本书的范围。让我们在后续小节中讨论并行计算的类型。

并行编程

在并行风格的程序开发中,程序被分成多个工作人员,他们在独立的 CPU 上执行,而不会争夺一个 CPU,如下图所示。这些 CPU 可以是多核计算机的单个处理器,也可以位于不同的计算机上,并使用诸如消息传递接口 ( MPI )等技术进行通信。

Parallel programming

并发编程

在并发编程中,用户程序的多个工作者在单个 CPU 上执行,或者在比工作者数量更少的 CPU 上执行(如下图所示)。这些工人在中央处理器调度程序的控制下争夺中央处理器。中央处理器调度器使用多种方案将工作人员分配给中央处理器。中央处理器调度方案被用来创建一个工人的排名,工人按照这个排名的顺序得到执行。

这些工作者可以使用多个进程或多个线程来实现。进程和线程同时执行主程序的某些部分。线程和进程的主要区别在于线程比进程消耗更少的内存。因此,螺纹被称为轻质

Concurrent programming

分布式编程

在分布式编程中,程序的工作人员在通过网络连接的不同计算机上执行。这些程序的执行有不同的框架。网络还使用不同的拓扑,在某些情况下,方案数据和流程都可能是分布式的。随着时间的推移,这种并行计算模式变得越来越流行,因为它提供了几个优势,包括低成本、容错、高可扩展性等。在分布式编程中,每个组件都有独立的内存和处理,而在并行编程中,多个处理器/CPU 共享公共内存。

Distributed programming

分布式程序执行

Python 中的多处理

多处理模块支持在多核环境下在多个处理器上独立运行的多个进程的创建和执行。它有两个支持多处理的重要模型;一个基于Process类,另一个基于Pool类。

该程序使用Process类演示多处理:

import multiprocessing as mpcs
import random
import string

output_queue = mpcs.Queue()

def strings_random(len, output_queue):
  generated_string = ''.join(random.choice(string.ascii_lowercase  + string.ascii_uppercase + string.digits)
    for i in range(len))
  output_queue.put(generated_string)

procs = [mpcs.Process(target=strings_random, args=(8, output_queue)) for i in range(7)]

for proc in procs:
  proc.start()

for proc in procs:
  proc.join()

results = [output_queue.get() for pro in procs]
print(results)

基于流程的类按照流程完成的顺序返回结果。如果用户需要检索一个有序的结果,他们必须付出额外的努力,如下面的代码所示。为了获得有序的结果,另一个参数被添加到函数中,最后添加到输出中。这表示过程的位置或顺序,最后结果根据参数排序。这个想法在下面的程序中使用Process类和输出中的一个位置参数进行了演示:

import multiprocessing as mpcs
import random
import string

output_queue = mpcs.Queue()

def strings_random(len, position, output_queue):
  generated_string = ''.join(random.choice(string.ascii_lowercase  + string.ascii_uppercase + string.digits)
    for i in range(len))
  output_queue.put((position, generated_string))

procs = [mpcs.Process(target=strings_random, args=(5, pos, output)) for pos in range(4)]

for proc in procs:
  proc.start()
for proc in procs:
  proc.join()

results = [output_queue.get() for pro in procs]
results.sort()
results = [rslt[1] for rslt in results]
print(results)

Pool类提供了用于并行计算的mapapply方法,并且还支持这些方法的异步版本。mapapply方法锁定主程序,直到一个过程完成,这个概念可以用来产生特定应用所需的顺序输出。

Python 中的多线程

Python 的线程模块允许用户创建一个进程的多个线程来执行并发计算。进程的线程与主进程/线程共享相同的数据空间,这使得数据共享和彼此之间的通信变得容易。线程也被称为轻量级进程,因为它们比进程需要更少的内存。

以下程序演示了线程的创建和启动:

import threading
import time
class demoThread (threading.Thread):
  def __init__(self, threadID, name, ctr):
    threading.Thread.__init__(self)
    self.threadID = threadID
    self.name = name
    self.ctr = ctr
  def run(self):
    print "Start of The Thread: " + self.name
    print_time(self.name, self.ctr, 8)
    print "Thread about to Exit:" + self.name

def print_time(threadName, delay, counter):
    while counter:
      time.sleep(delay)
      print "%s: %s" % (threadName, time.ctime(time.time()))
      counter -= 1

thrd1 = demoThread(1, "FirstThread", 4)
thrd2 = demoThread(2, "SecondThread", 5)
thrd1.start()
thrd2.start()
print "Main Thread Exits"

这个程序启动两个线程。如果你观察程序的输出,你会注意到没有线程执行的顺序。首先显示"Main Thread Exits"字符串,然后是线程名称和"Thread about to Exit: ThreadName"的随机序列。

我们可以选择同步这个输出,这样就可以保持线程完成的顺序。下面的程序首先执行第一个线程。然后,在其退出后,第二个线程被执行。最后,主线程退出。通过获取锁来维护线程序列,并且在退出之前释放该锁,以便可以启动第二个线程。主线程对所有线程对象调用join方法。该方法阻止主线程完成其他各种线程:

import threading
import time
class demoThread (threading.Thread):
  def __init__(self, threadID, name, ctr):
    threading.Thread.__init__(self)
    self.threadID = threadID
    self.name = name
    self.ctr = ctr
  def run(self):
    print "Start of The Thread: " + self.name
    threadLock.acquire()
    print_time(self.name, self.ctr, 8)
    print "Thread about to Exit:" + self.name
    threadLock.release()

def print_time(threadName, delay, counter):
    while counter:
      time.sleep(delay)
      print "%s: %s" % (threadName, time.ctime(time.time()))
      counter -= 1

threadLock = threading.Lock()
thrds = []

thrd1 = demoThread(1, "FirstThread", 4)
thrd2 = demoThread(2, "SecondThread", 5)
thrd1.start()
thrd2.start()

thrds.append(thrd1)
thrds.append(thrd2)
for thrd in threads:
  thrd.join()

print "Main Thread Exits"

Python 中基于 Hadoop 的 MapReduce

Hadoop 是一个开源框架,用于计算集群中巨大数据集的分布式存储和处理。Hadoop 系统有三个主要组件:用于处理的 MapReduce、 Hadoop 分布式文件系统 ( HDFS )和一个名为 HBase 的大规模数据库,用于存储数据集。HDFS 支持存储非常大的数据集文件。它将用户提交的数据集分布在各个集群节点上。它将数据集分成多个块,并保存关于块和节点的簿记信息。HBase 是一个为支持大规模数据库而设计的数据库,是在 HDFS 之上开发的。它是一个开源的、面向列的、非关系的分布式数据库。

MapReduce 是一个框架,旨在对计算集群中的巨大数据集执行分布式处理。Hadoop 是 MapReduce 框架的开源实现。MapReduce 程序由两个主要组件组成:map 和 Reduce。map函数用于对输入数据集进行过滤,并将其排序后的输出写入文件系统。稍后,reduce 函数使用该输出来执行总结,最终输出再次写入文件系统。MapReduce 框架遵循 单程序,多数据 ( SPMD )模型,因为它在多个数据集上处理同一个程序。

在 Hadoop 系统中,完整的功能分为许多组件。有两个主节点。一个是作业跟踪器,它跟踪地图并减少从节点的进程,称为任务跟踪器节点。第二个主节点是 namenode,它包含有关哪个分割数据文件块存储在称为 data node 的特定从节点上的信息。为了避免单点故障,用户可以安装辅助名称节点。建议有多个称为任务跟踪器节点/数据节点的从节点来执行实际的映射并减少进程。每个从节点充当任务跟踪器节点和数据节点。MapReduce 应用的性能与从节点的数量成正比。Hadoop 系统还执行自动故障恢复;如果其中一个任务跟踪器节点在运行时出现故障,那么它的责任将自动分配给另一个任务跟踪器,处理将继续进行,不会出现故障。

下面的程序演示了用 Python 开发一个基于 Hadoop 的 MapReduce 程序。它处理常见的爬网数据集。这些数据集包含长期收集的数千兆字节的网络爬行数据。它包含以【Web ARChive】(WARC)格式存储的网页数据、提取的元数据和提取的文本。这些数据集作为亚马逊公共数据集计划的一部分存储在亚马逊 S3。关于这些数据集的更多信息可在http://commoncrawl.org/the-data/get-started/找到:

import sys
for line in sys.stdin:
  try:
    line = line.strip()
    # split the line into words
    words = line.split()
    # increase counters  
    if words[0] == "WARC-Target-URI:" :
      uri = words[1].split("/")
      print '%s\t%s' % (uri[0]+"//"+uri[2], 1)
  except Exception:
    print "There is some Error"

前面的程序是贴图部分,后面的程序是缩小部分:

from operator import itemgetter
import sys

current_word = None
current_count = 0
word = None

for line in sys.stdin:
    line = line.strip()

    word, count = line.split('\t', 1)

    try:
        count = int(count)
    except ValueError:
        continue

    if current_word == word:
        current_count += count
    else:
        if current_word:
            print '%s\t%s' % (current_word, current_count)
        current_count = count
        current_word = word

if current_word == word:
    print '%s\t%s' % (current_word, current_count)

在执行前一个程序之前,用户需要将名为web-crawl.txt的输入数据集文件转移到他们的HDFS home文件夹中。要执行该程序,用户应该运行以下命令:

#hadoop jar /usr/local/apache/hadoop2/share/hadoop/tools/lib/hadoop-streaming-2.6.0.jar -file /mapper.py    -mapper /mapper.py -file /reducer.py   -reducer /reducer.py -input /sample_crawl_data.txt -output /output

Python 中的火花

Spark 是一个通用的集群计算系统。它支持 Java、Python 和 Scala 的高级 API。这使得并行任务的编写变得容易。它是相对于 Hadoop 基于磁盘的 MapReduce 的两阶段模型而提出和开发的,因为它遵循内存模型,并为某些特定应用提供了最大 100%的性能提升。它非常适合实现机器学习应用/算法。

Spark 需要集群管理和分布式存储系统。它为各种分布式存储提供了一个简单的接口,包括亚马逊 S3、卡珊德拉、HDFS 等等。此外,它支持独立的——也就是说,用于集群管理的 spark 原生集群、Hadoop、纱和 Apache Mesos。

Spark Python API 命名为 PySpark ,将 Spark 编程模型暴露给 Python。我们可以在使用 PySpark 打开的 Python 外壳中或者通过使用 IPython 会话来开发基于 Spark 的应用。我们也可以先开发程序,然后使用pyspark命令运行。

总结

在本章中,我们讨论了使用 IPython 的高性能科学计算的概念。我们从并行计算的基本概念开始讨论。在基本概念之后,我们讨论了 IPython 并行计算的详细体系结构。后来,我们讨论了示例并行程序、IPython 魔法函数和并行装饰器的开发。

我们还介绍了 IPython 的高级功能:容错、动态负载平衡、管理任务之间的依赖关系、客户端和引擎之间的对象移动、IPython 数据库支持、使用来自 IPython 的 MPI 以及使用来自 IPython 的 StarCluster 管理 Amazon EC2 集群。然后我们讨论了 Python 中的多处理和多线程。最后,我们介绍了使用 Python 中的 Hadoop 和 Spark 开发分布式应用。

在下一章中,我们将讨论几个使用 Python 工具/API 进行科学计算的真实案例研究。我们将考虑各种基础和高级科学分支的应用。**

九、回顾真实案例研究

本章讨论了科学计算应用、API/库以及用 Python 设计和开发的工具的几个案例研究。

在本章中,我们将讨论在以下科学领域应用 Python 的一些案例研究:

  • 专用硬件/软件
  • 气象学家的申请
  • 设计和建模
  • 高能物理的应用
  • 计算化学
  • 生物科学
  • 嵌入式系统

这些应用、工具和库涵盖各种社会、科学和商业领域,包括非政府组织的应用、科学教育的软件或硬件以及气象学家的应用。它们还包括用于飞机概念设计的工具和应用接口,用于地震风险评估的应用,以及用于制造过程能效的应用。除此之外,还包括高能物理的分析代码生成器、计算化学的应用、盲音频触觉映射系统、空中交通控制工具、节能灯的嵌入式系统、海事设计 API 和分子建模工具包。

用 Python 开发的科学计算应用

Python 是开发科学应用的流行语言。特别是,它最适合要求低成本的应用和要求高性能的应用。在接下来的小节中,我们将介绍一些以某种形式使用 Python 的应用、工具和产品。

每个孩子一台笔记本电脑项目使用 Python 作为用户界面

每个孩子一台笔记本电脑(【OLPC】)是一个项目,始于 麻省理工学院 ( 麻省理工学院)。该项目在软件和硬件开发者的支持下发展壮大,并通过坚实的社区参与来完成 OLPC 的使命。这个项目背后的想法是开发具有创新硬件和软件的低成本教育笔记本电脑。OLPC 的简单而令人信服的使命是为贫困儿童创造教育机会,为他们提供低成本、低功耗的笔记本电脑,其中包含为协作学习设计的软件和应用。此次任务的主要目标是生产和销售一款名为 OLPC XO 的低成本低功耗笔记本电脑。这款 XO 由台湾公司广达电脑制造。与其他计算机不同,XO 使用闪存而不是硬盘和基于 Fedora Linux 的操作系统。它还使用基于 802.11s 无线网状网络协议设计的移动自组网。XO 笔记本电脑如下图所示:

The one Laptop per Child project used Python for their user interface

来源:http://images . flat world knowledge . com/陆乐/陆乐-fig13_004.jpg

Sugar 是用设计的免费开源桌面环境,高贵专注于交互学习,是 XO 的交互界面。Sugar 没有桌面、文件夹和窗口的概念。取而代之的是,它从家庭视角开始;在此屏幕上,用户可以选择任何活动。为糖业设计的应用被称为 活动。活动包括应用以及共享和协作功能。为了保存应用的状态和历史,Sugar 实现了一个日志,允许用户恢复活动。日志自动存储用户的会话,并提供按日期检索历史记录的界面。每个活动都可以访问日志和其他功能(如剪贴板)的内置界面。Sugar 的活动以全屏模式运行,用户一次只能使用一个程序。

许多平台都提供糖,如下所示:

  • XO 笔记本电脑:一台 XO 笔记本电脑运行 Sugar 作为默认界面
  • 现场光盘和现场 u 盘:糖也可以在现场光盘/u 盘上买到
  • Linux 发行版的软件包 : Sugar 作为大多数 Linux 平台的软件包提供,作为一个替代桌面
  • 操作系统映像(使用虚拟化):用户也可以使用虚拟化在 Windows 或 Macintosh 操作系统上安装 Sugar

Python 语言用于开发 Sugar 和 Sugar 中的各种活动。开发人员可以使用 Python 扩展 Sugar 并添加新的应用/活动。Sugar 的主屏幕如下图所示:

The one Laptop per Child project used Python for their user interface

前面截图的来源是http://2 . BP . blogspot . com/_ PPJgknwAe5o/S _ 8kh 3r 1 qii/aaaaaaaagagk/qmjdlae1pq 8/S 1600/2009-SugarLabs-homeview . png

XO 推出后不久,就获得了社区的大力支持,因为它是免费运行的,是一款开源软件,允许开发者理解和改进软件。XO 拥有高分辨率、易读的屏幕,支持读本模式和多种语言。 XO 笔记本电脑的读书模式如下图所示:

The one Laptop per Child project used Python for their user interface

资料来源:http://regmedia . co . uk/2008/01/16/ebook . jpg

expyes–科学之眼

印度大学间加速器中心(【IUAC】)启动了一个名为 自制设备物理与创新实验 ( PHOENIX )的项目。这个项目背后的想法是通过实验来提高科学教育的质量。项目的主要活动是低成本实验室设备的开发。该倡议下的另一个项目是 青年工程师和科学家实验(experies),设计的重点是通过探索学习。ExpEYES 适合高中和更高的班级。设计经过优化,以满足主要目标,即低成本设备。这个设备运行在 5 伏的 USB 电源上。

要使用 ExpEYES,用户可以通过将其连接到计算机的 USB 端口和接口应用来访问它。它有 32 个输入输出端子,排列在两侧,用于连接外部信号。用户可以控制和监控终端的电压。为了测量其他参数,如力、压力、温度等,用户应该使用适当的传感器元件将它们转换成电信号。例如,温度传感器会给出指示温度的电压。下图显示了 ExpEYES:

ExpEYES – eyes for science

来源:http://exp yes . in/sites/default/fiimg/diode-整流器-photo.jpg

实际学习需要探索和进行实验。物理实验需要控制和测量各种参数,如加速度、电流、力、压力、温度、速度、电压等。许多属性需要自动测量,因为它们的值变化很快(例如,交流电源电压)。这些自动化测量需要计算机的参与。

在任何计算机上运行 ExpEYES 都需要一个 Python 解释器和一个用于访问串口的 Python 模块。设备驱动程序处理 USB 接口;驱动程序将 USB 端口作为 RS232 端口呈现给应用。ExpEYES 的通信部分是通过使用 Python 语言编写的库来处理的。为每个支持的实验开发了一个图形用户界面程序。用户还可以开发 Python 程序进行新的实验。ExpEYES 以实时光盘和 Linux 和 Windows 安装的形式提供。这是一个负担得起的科学实验室,既便携又可扩展。它支持从高中到研究生阶段的广泛实验。

expyes 的最新版本叫做expyes Junior。这个版本增加了一些功能,而一些早期的功能已经被删除。它还可以与基于安卓的智能设备接口。下图描述了小 ExpEYES:

ExpEYES – eyes for science

来源:http://exp yes . in/sites/default/file/experiences/Photos/半波. jpg

最初的软件是用 C 语言编写的,但很快就改成了 Python。这一变化带来了两大优势。第一个优势是对基于图形用户界面的程序开发的支持大幅增加。另一个优点是,由于 Python 支持硬件交互,这使得新实验的开发变得容易。

Python 中的一个天气预报应用

一般来说,气象学家将他们的预测与相关时期的实际天气进行比较。这样做的目的是优化和提高他们的模型质量,该模型收集收集实际读数的实际测量的天气信息。预测观察 帮助气象学家和其他人比较、交流和理解他们天气预报的准确性。它提供基本的分析和无偏的数据,目的是提高预测的质量。ForecastWatch 始终如一地从各种天气预报来源收集数据,并将这些数据与实际观测数据相吻合。它将每个预测与在美国和加拿大 850 多个地点进行的观测进行比较。在这次比较中,高低温、不透明度、降水和风力预报都得到了验证。ForecastWatch 为数据的准确性生成大量按月统计的度量标准,并按国家、州和特定位置进行汇总。

ForecastWatch 由四个主要组件组成,如下所示:

  • 获取预测的输入流程:这就是所谓的预测解析器,它从各个预测提供者的门户网站收集预测进行验证。它解析数据并将其插入数据库,以便与实际数据进行比较。
  • 获取实测气候数据的输入过程:这被称为实际解析器。它从 国家气候数据中心检索国家气象局 提供的实际数据。这些数据包含高低温、降水和重大天气事件。实际的解析器将这些数据存储在数据库中,并根据实际数据对天气预报进行评分。它也将这些信息存储在数据库中。
  • 数据聚合引擎:数据采集打分后,由数据聚合引擎进行处理,按照地点、天数、提供者等进行月块、年块的排列。
  • Web 应用框架:最初 web 界面是用 PHP 设计的,后来用 Python 重新设计。使用 Python 重新设计简化了 web 开发,并改进了它与系统其他三个组件的集成。一个基于 Python 的网络应用框架吉诃德 被用来开发纯基于 Python 的网络应用。

这是一个纯基于 Python 的应用,因为 Python 用于开发所有四个组件,从有趣的 web 界面到耗时的输入/输出绑定数据收集过程和高性能聚合引擎。开发人员选择 Python 是因为它有许多标准库,可用于数据收集、解析和存储在数据库中。多线程库用于在数据收集过程中将数据收集扩展到大量城市。聚合引擎也是用 Python 开发的。它使用名为MySQL 数据库到的 Python 数据库库为 MySQL 数据库执行数据库查询,该数据库由输入过程创建,用于存储预测和气候数据。

Python 中的飞机概念设计工具和 API

在本节中,我们将讨论为支持飞机概念设计而开发的工具和 API。首先,我们将讨论 VAMPzero 工具。然后,我们将讨论 pyACDT API。

德国航空航天中心(德语缩写为 DLR )是德国航空航天、能源和交通研究的国家中心。他们的重点是开展航空航天研究,并为相关研发项目开发软件。DLR 使用 Python 开发软件工具和 API。

VAMPzero 是一款用于飞机概念设计的软件工具;它使德国航天中心能够应对挑战,并在飞机概念设计过程中提供灵活性和透明度。飞机设计的要求经常变化,因为它们使用了新技术。VAMPzero 的灵活流程使用户能够采用这些变化。VAMPzero 基于众所周知的手册方法,具有高度可扩展性。它允许用户追溯计算历史,并以 CPACS 格式导出数据。用 VAMPzero 设计一个新系统包括外部几何形状,以及发动机、结构、系统和成本。VAMPzero 是第一个为飞机概念设计制作的开源工具,支持在多学科环境中工作。VAMPzero 的编程是用 Python 完成的。它的开发目标是拥有一个快速执行飞机设计过程的工具。

在加拿大皇家军事学院高级飞机设计实验室有一个科学家开发的框架,叫做 Python 飞机概念设计工具箱 ( pyACDT )。pyACDT 是一个基于 Python 的面向对象框架,用于分析、定义、设计和优化飞机配置。它由几个模块组成,用于表示概念设计阶段所需的每个主要学科分析。该框架使用面向对象编程的概念表示各种飞机部件、发动机部件、特性和学科分析的模型。下图描述了 pyACDT 的各个模块,对应各个学科。框架的设计允许用户轻松改变约束、设计变量、学科分析和目标函数。

**An aircraft conceptual designing tool and API in Python

打开地震引擎

全球地震模型是区域、国家和国际级别的几个组织和一些个人的合作努力,为全球地震风险的计算和交流制定统一和开放的标准。该基金会是一个公私伙伴关系,成千上万的人以各种可能的方式做出贡献,包括他们的时间和知识。这是为了在各种全球项目中工作,作为软件的用户,通过使用和测试它们,审查项目的结果和参加会议。由于地震的脆弱性与日俱增,而且世界大部分地区仍然缺乏可靠的风险评估工具和数据,创业板所管理的活动至关重要。此外,我们缺乏全球标准来比较各种风险分析方法。为了正确理解地震的后果和行为,人们认为在全球范围内合作更好。创业板的设立就是为了管理这些问题。

创业板基金运作以下主要区域:

  • 地震风险评估工具:主要重点是设计、开发和增强高质量的地震风险评估工具
  • 地震风险信息 : GEM 还致力于收集和生成地震风险信息数据集和模型的方法和指南
  • 协同风险评估项目:创业板基金会致力于各种规模的协同风险评估项目的开发和实施
  • 技术转让和能力发展 : GEM 还致力于地震风险评估相关的能力建设和知识转让

在这个大框架下,科学家们正在开发最佳实践,创建通用数据集,并开发地震危害和风险评估模型。GEM 基金会正在将所有这些贡献整合到一个基于网络的 OpenQuake 工具包中。该工具包可供全球利益相关者使用。OpenQuake 引擎是用 Python 语言开发的,被工程师、金融专家、政府官员和科学家用来执行地震危害和风险评估。

OpenQuake 是一个基于网络的风险评估工具包,它提供了一个单一的集成环境来计算、可视化和调查地震风险;获取新数据;分享协作学习的发现。

OpenQuake 引擎使用五个主要计算器在地震风险评估和缓解的不同领域工作。这些计算器的简要说明如下:

  • 情景风险计算器:这个计算器对于提高社会对地震风险的认识以及正确的应急计划和管理非常有用。它用于计算给定资产组的单一地震场景的损失和损失统计。
  • 情景损害评估计算器:这个计算器对于评估研究中的各种资产的地震易损性是有用的。它支持从资产集合中估计对特定资产造成的损害。
  • 基于概率事件的风险计算器:这个计算器对于计算资产集合的累计预期损失非常有用。它能够使用概率风险计算给定资产集合的损失概率和损失统计。
  • 基于经典 PSHA 的风险计算器:该计算器的输出可用于对不同位置的各种资产的风险缓解工作进行优先排序。该计算器计算单一资产的损失概率和损失统计。此外,对几个地点的不同资产的这些计算可用于在资产之间进行比较风险评估。
  • 收益-成本比率计算器:这个计算器对于确定需要加强活动的各个区域的优先次序和确定经济上适合给定区域的抗震设计是有用的。它计算并发现对一组特定的建筑采用改造或加固措施是否有经济效益。

短信 Siemag AG 应用节能

SMS Siemag AG 是冶金工厂和轧机技术的市场领导者。该公司正在与他们的客户合作,以提高他们铸造厂的能源效率及其对环境的影响。公司将这一操作命名为生态模式。在这种模式下,在特定时间,生产不需要的设备会自动关闭或切换到省电模式。这个自动过程由基于 Python 的软件控制。这个基于 Python 的应用用于测量和记录各种消费者的功耗。通过这种方式,它对不同运行模式下的各种发电机组的功耗进行记录和评估。

用于高能物理数据分析的自动代码生成器

大型强子对撞机(【LHC】)是世界上最大的人造机器,旨在进行粒子物理实验。这些实验的主要目的是证实粒子物理的理论和发现新的粒子。这开启了另一个 高能物理 ( HEP )的时代。

这是有史以来最大的科学实验。以下是一些事实:

  • 近 100 个国家参与其中
  • 大约 500 个研究所正在合作
  • 大约有 10,000 人正在进行实验/从实验中受益
  • 该项目的成本约为 40 亿欧元
  • LHC 隧道全长 27 公里

这台巨大的机器产生 10pb/年规模的大量数据。不可能在一个站点存储和管理这么多数据。为了解决这个问题,欧洲核子研究中心与世界上几乎所有的 HEP 机构合作开发了一个网格计算环境。这个网格是一个大规模的并行处理系统,有一个机构网络,共享存储空间和处理能力。为了获得更好的性能,分析作业透明地在具有要分析的数据的系统上执行。

在 LHC 隧道中,两个质子束循环流动。它们每 25 纳秒在四个实验点碰撞一次。由于这些碰撞,产生了许多粒子。其中一些产生的粒子是众所周知的,预计其他一些可能是新的和未知的。

为了从碰撞数据中正确提取信息,物理学家必须为他们感兴趣的每个物理特征编写代码。只有当一次处理一个签名时,该代码才会有效。然而,他们需要编写许多这样的分析代码来扫描所有可能的新物理特征。所有这些代码大多相似,都是通过复制公共代码创建的;一般来说,这种常见的代码可能是易错的,因为有很多代码需要调试和维护。

为了解决这个问题,欧洲核子研究中心的科学家们为 HEP 社区提出了一个新的想法——用 Python 开发一个计算机辅助软件工程包,该包处理常见的代码和算法,并自动生成分析代码。由于该代码是从用户输入中自动生成的,因此它被证明更高效且不易出错。它使物理学家能够适当地处理物理部分,因为分析代码是自动生成的。这个包裹名叫WatchMan。WatchMan 是一个完全用 Python 开发的面向对象框架。它允许物理学家专注于他们的想法,而不用担心分析代码,因为它从用户设置中构建完整的分析代码。它是使用欧洲核子研究中心用 Python 开发的两个工具开发的:PyROOT(用于数据分析的 Python 工具箱)和 rootcint(Python 和 C++绑定系统)。WatchMan 的流程如下图所示:

Automated code generator for analysis of High-energy Physics data

用于计算化学应用的 Python

阿斯利康,一家知名的制药公司,为癌症、心血管疾病、胃肠和其他感染、疼痛控制和其他疾病提供有效的药物。一般来说,发现一种新药需要很长时间(通常是几十年)。最大的挑战是尽早从大量可能产生好药物的分子中找出可能的候选分子。

有几种技术可以预测分子的性质和行为。这些技术是由计算化学家开发的,用于确保特定的分子不会对身体有毒,并且能够保持稳定,能够执行所需的活动,最终会自动消除。

这些技术的问题是它们的结果本身是不够的,化学家必须进行实际的实验。这些分子必须在实验室进行测试,以观察它们的行为和反应。为了节省时间,各种计算模型被用来列出要测试的好候选人。

在阿斯利康加强药物鉴定过程之前,实验化学家和计算化学家在药物鉴定方面相互依赖。由于实验化学家不太接触计算技术,计算化学家应该帮助他们运行计算机预测,这是一个复杂的过程。这种依赖性正在影响计算化学家和实验化学家的进步,因为计算化学家投入时间频繁运行常规模型,而不是开发新的预测技术。如果有某种技术能够使实验化学家进行计算预测,那么它将改进这一过程,使药物预测过程变得更容易和更快。

皮埃尔·布鲁诺使用 Perl 脚本设计了一个成功的基于网络的工具。这个工具使用了一个叫做无人机的分子属性计算器工具。它被阿斯利康采用,以增强其后端工具无人机的可管理性、可扩展性和健壮性。这个新的后端工具被命名为py 无人机

强大的显式错误处理和严格的类型检查在 Python(py 无人机)中实现时增强了无人机的健壮性。最初在测试阶段,py 无人机不断抛出一些由无人机静默执行的异常。开发人员发现,这些异常已经确定了以前没有处理过的几个新的错误案例。添加了错误处理编码的新代码提高了健壮性,因为代码处理了许多新的错误情况。

为了提高 py 无人机的扩展性,增加了一个规则库。该规则库由数据缓存和用于预测函数映射的属性名组成。

规则库的工作方式类似于 Python 字典对象。对于每个请求的属性,它首先查找缓存。如果找到了,那就用。否则,调用关联函数进行计算。

结果将被返回并存储在缓存中以备将来使用。对于新的预测,开发人员将新函数添加到函数表中。这样,py 无人机就能够管理所有现在和未来的预测方法。

开发盲音频触觉映射系统的 Python

为视觉残障人士设计的盲人音频触觉地图系统 ( BATS ) 为他们提供了地图。在这个系统发明之前,没有视觉障碍的人可以获得古代世界的地图。该项目始于北卡罗来纳大学的一个小组。选择了 Python,而不是 C++或 Java。这最初是一个艰难的决定,因为团队对 Python 没有太多了解,他们精通 C++和 Java。最终,这个决定是一个明智的决定,因为 Python 拥有大量的库和模块,这些库和模块对于开发这样的应用来说是非常理想的。

BATS 使用古代世界制图中心提供的 ArcView 数据文件。ArcView/ArcGIS 是一款功能齐全的 GIS 软件,用于可视化、管理、创建和分析地理数据。最初,他们为地图的表面类型和高程生成了两个 ASCII 文本文件。该信息准备为 1024 x 768 的网格,与系统中使用的显示器和触摸板的分辨率相匹配。该网格信息被读取并存储在 Python 数组中。数据缩小以适合 BATS 模型。然后将其存储在压缩文件中;程序将这些数据解压缩并加载到适当的数据结构中,以执行快速启动。显示像素与文件中的值一一对应。该系统反应迅速,能及时处理用户的移动。各种音频/视觉效果被用来表示不同区域的运动,例如海洋或陆地。

BATS 由两个主要组件组成,即图形用户界面和数据管理器。数据管理器使用户界面能够管理数据。用户界面有一个触摸板、一个数字键盘和一个语音合成器,用于帮助视力残疾人。触摸板上的用户动作通过 wxPython 捕捉。对于用户移动,wxPython 中有鼠标运动事件;这些事件用于触发对各个城市的地表类型和数据库的查询。鼠标和按键事件由 wxPython 处理,产生语音反馈。BATS 也使用微软的语音 API。

wxPython 是跨平台 GUI API,允许 Python 程序员开发具有丰富用户界面和事件处理的基于 GUI 的程序。

数据管理器将各种值存储在三个数字数组和一个到 MS Access 数据库的 ODBC 连接中。这些数组存储高度、土地类型和数据库中的键值。键值用于查询 Access 数据库,该数据库检索与给定位置对应的城市信息。

空中交通管制工具

开发通用航空交通控制解决方案需要额外的努力,因为每个机场的特点在各个方面都是独特的,例如设计、法规遵从性和基础设施。空中交通管制系统最重要的组成部分是用户界面定制。

frequency is是空中交通管理、公共安全和运输领域的一线解决方案提供商。他们使用 Python 开发他们的 TAPTools 产品系列,该产品系列适用于作为空中交通管制一部分的塔台和机场工具。空中交通管制员使用这些来控制跑道照明和导航辅助仪器,监控导航仪器,并跟踪天气情况。

为每个客户设计一个全新的用户界面是一项乏味且耗时的任务。为了解决这个问题,Frequentis 开发了一个设计用户界面布局的工具,名为 PanView。这个工具可以用来设计和构建一个将由相关软件执行的用户界面,称为 PanMachine。这个软件运行在一个专门设计的硬件上,叫做 动力面板。这些工具可以用来轻松开发布局的原型。最初,PanView 和 PanMachine 使用了一种叫做 Lua 的脚本语言。Lua 用于连接用户界面和空中交通管制系统的实际功能。

与 Python 相比,使用 Lua 有很多问题。如果出现错误,它提供的信息有限。它没有任何列表数据结构,并且由于标准库有限,很难编写更大的程序。

芬兰民航局希望不仅在 PowerPanel 上,而且在网络浏览器上运行用户界面布局。这个项目强制在 Java 中重新实现 PanMachine,以便在浏览器中执行。由于 Lua 不能在 Java 下运行,所以 Frequentis 将其重新设计为基于 Python 的实现。他们选择了 Python 和 Python 的 Java 实现,叫做 Jython 。这将使用户能够在 PowerPanel 和 PanMachine 上运行用户界面布局,它们都是用 Java 实现的。对于 PowerPanel,Python 用 C 实现,Jython 用 Java 实现,用于浏览器。在这一步之后,常客开发人员重新设计了 Python 中的 Lua 布局。与 Lua 布局相比,为布局编写的 Python 代码非常短,因此易于管理。

嵌入式系统节能灯

卡玛那科技公司是太阳能发光二极管照明市场的领导者。该公司是一系列可用于不同用途的灯的制造商和供应商,包括机场照明、工业标记、海洋应用、铁路、公路、公交等。该公司最初生产用于海上航行的自给式和自主式太阳能灯。现在,卡玛拿的市场横跨全球,特别是条件极端的地方,如开阔的海洋、沙漠、极北地区等。如今,电灯已经变得如此复杂,以至于它应该满足自主和独立照明等特性。灯周围可用的太阳辐射随天气、季节、灯的位置、太阳能电池板的方向和其他属性而变化。有一些特殊的应用;这些灯还支持可编程接口,根据输入提供不同的输出,通过无线网络连接到集中控制站,适合其他复杂场景。

开发这种灯需要电气、电子、机械和光学设计的完美结合。每个灯都是使用运行在微控制器上的嵌入式软件程序来操作的。这些灯是自主的,因为每个灯都根据模型化的要求保持自身并执行其功能。

通常,嵌入式系统需要高可靠性、低功耗和小尺寸的组件。为了满足这些要求,已经设计了称为微控制器的特殊处理器芯片。这些微处理器以非常低的成本将中央处理器存储器和外围设备结合在一个芯片上。除了写在微处理器只读存储器上的嵌入式功能之外,在开发和维护期间,还有几个功能需要台式机/笔记本电脑系统。

现在,考虑一个例子,其中嵌入式软件在常规系统上编译;然后将目标代码加载到所需的微控制器上。同样,在维护期间,对部署的设备进行故障排除需要额外的硬件,如笔记本电脑,以执行诊断实用程序。Python 提供了许多特性来执行嵌入式系统开发的实际和支持活动。这些特性包括 Python 程序的紧凑性、自动化内存管理、Python 简单而强大的面向对象工具等等。

Carmanah 在其嵌入式系统生命周期的几个关键领域采用了 Python。例如,他们使用 Python 程序来控制软件构建过程、压力和单元测试、设备模拟器和其他领域。

用 Python 开发的科学计算库

在 Python 中,许多库是为不同的应用领域开发的。这些库是为了构建商业应用和科学应用而开发的。以下小节涵盖了一些选定的科学计算库。

一个由 Tribon 开发的海事设计 API

Tribon Solutions 在计算机辅助设计和建模解决方案领域工作。他们的重点是提高海事应用的整体效率。Tribon 软件套件支持船舶建造的整个生命周期。这需要高度并发的进程来处理这些情况。他们为从事船舶设计和建造的人员开发了一个中央存储库和一个单一的信息源。这个模型叫做 T3【产品信息模型】T4(PIM)。这些人可能是设计师、材料管理员、制造团队成员、计划员以及参与整个流程的其他人。

一般来说,船的设计是独一无二的;然而,他们的设计者的重点是通过标准化和参数驱动的设计来证明过程,从而降低成本。由于不同的设计原则、政府法规和标准以及供应商的设施和基础设施,该过程主要依赖于供应商。Tribon 处理这个问题是为了让供应商自行开发。Tribon 技术已经创建了一个易于使用、独立于平台、可扩展和可嵌入的 API。

Tribon 之所以选择 Python,是因为它有很多特性,比如产品是可嵌入和可扩展的,没有许可成本,平台无关性。Tribon 的解决方案不会受到 Python 任何更新版本的影响。客户开发的应用是独立于平台的,因此客户可以跨平台移动它们,而没有很多问题和代码变化。这些解决方案将一些零件的设计过程从几周改进到几天,整体质量得到提高。这是因为设计、计算和其他过程正在自动化。他们将这种产品命名为 Tribon Vitesse。

分子建模工具包

分子建模工具包 ( MMTK )是一个 Python 库,用于以生物分子系统为重点的分子建模和模拟。这是一个使用 Python 和 C 语言开发的开源库。生物分子模拟比一般需要更长的时间,一般需要几周。这个过程需要复杂的数据结构来描述生物分子。Python 和 C 语言被选为高级解释语言和高性能编译语言。对于复杂和高性能要求的模拟来说,这是一个很好的组合。

之所以选择 Python 而不是 TCL 和 Perl,是因为它具有许多想要的特性,例如与编译语言的集成、库支持、面向对象的编程风格和可读性。

MMTK 库的用户以纯 Python 库的形式访问它,因为用于开发 MMTK 的 C 语言代码完全是以 Python 扩展模块的形式编写的。这段代码只为库的时间和性能关键方面编写。例如,相互作用能量评估是一个时间关键的函数,能量最小化和分子动力学是迭代过程,需要更多的时间来完成;它们需要高性能处理。这些函数是用 C 语言实现的,以避免 Python 语言的开销。另一方面,MMTK 广泛使用数字 Python、LAPACK 和 NetCDF Python 库。MMTK 还支持共享内存并行处理(使用多线程)和分布式内存并行处理(使用 MPI)。

MMTK 的设计目的是使其高度可扩展。无需修改 MMTK 代码来添加算法、能量项和专门的数据类型。对于可视化相关活动,MMTK 依赖外部工具;VMD 和皮摩尔尤其与 MMTK 融为一体。通常,MMTK 用户使用 Python 脚本来访问库。然而,有几个程序使用带有图形用户界面的 MMTK,例如域控制器和 nMOLDYN 程序。

MMTK 由三大类班级组成。最大的类别是用于表示原子和分子的一组类,以及管理分子和片段数据库的类。通用分子类别中有一个单独的子类,用于表示生物分子,如脱氧核糖核酸、蛋白质和核糖核酸。MMTK 的第二个(也是重要的)部分实现了各种模式来计算相互作用能。MMTK 的第三部分处理与输入和输出相关的功能。该代码旨在为一些流行的文件格式和基于 NetCDF 格式的自定义 MMTK 格式执行读写功能。MMTK 的文件可以跨各种平台移植,并且是二进制类型。由于这些文件是二进制文件,因此它们的大小较小,并且允许有效的访问。

标准 Python 包

除此之外,还有特定的工具、应用接口和应用可用;您可以访问http://pypi.python.org在线提供的 Python 包索引。它包含数千个用于特定应用的模块(大部分是用 Python 开发的)。这些应用也涵盖了许多科学、商业和计算领域。有生物信息学、医疗保健、地理空间分析、仪器仪表、工程、数学和其他分支的模块。门户网站维护一个包的分类列表。以下列表包含一些从科学和工程领域选择的软件包:

  • fluiddyn:研究流体动力学的框架
  • DeCiDa:装置和电路数据分析
  • python-vxi11:通过以太网控制仪器的 Python VXI-11 驱动程序
  • pygr:这个是一个主要面向生物信息学应用的 Python 图形数据库工具包
  • Brainiac:这些是人工智能系统中使用的各种组件,完全可以自己使用
  • pyephem:这个计算行星和恒星的位置
  • PyMca:这是一个 X 射线荧光分析工具包及应用
  • openallure:一个语音视觉对话系统
  • BOTEC:一个简单的天体物理学和轨道力学模拟器
  • pyDGS:基于小波的数字粒度分析
  • MetagenomeDB:宏基因组序列和注释的数据库
  • biofrills:这些是用于分子序列分析的生物信息学工具
  • python-bioformat:读写生命科学文件格式
  • psychopy_ext:用于神经科学和心理学实验的快速可复制设计、分析和绘图的框架
  • Helmholtz:创建神经科学数据库的框架
  • pysesa : PySESA 是一个开源项目,致力于提供一个通用的 Python 框架,用于点云和其他空间和频率域的地理空间数据的空间显式统计分析,供地球科学使用
  • nitime:神经科学数据的时间序列分析
  • SpacePy:空间科学应用工具
  • Moss:神经影像和认知科学的统计工具
  • cclib:解析器和计算化学算法
  • PyQuante:Python 中的量子化学
  • phoebe:恒星、恒星和行星系统的物理学
  • mcview:用于高能物理事件模拟的 3D/图形事件查看器
  • yt:用于天体物理模拟的分析和可视化工具包
  • gwpy:Python 中支持引力波天体物理的包

总结

在本章中,我们讨论了使用 Python 语言开发的科学计算应用、库和工具的几个案例研究。我们讨论了 Python 在各个领域的应用,包括专业软件和硬件的设计(如 OLPC 和 ExpEYES),以及为照明系统设计基于 Python 的嵌入式系统。我们介绍了 Python 在计算化学和分子建模中的一些用途。我们还看到了 Python 在科学和其他领域的计算机辅助建模中的用途。

在下一章中,我们将讨论开发科学计算应用和 API 的最佳实践,特别关注 Python。**

十、科学计算的最佳实践

本章讨论科学计算应用、API 和工具的开发人员将采用的最佳实践。最佳实践是通过研究和经验建立的定义明确的流程/陈述。遵循这些实践可以用更少的努力和更少的问题实现预期的结果。

特别是,本章将涵盖以下主题:

  • 基于 Python 的设计的最佳实践
  • Python 实现的最佳实践
  • 数据管理和应用部署的最佳实践
  • 实现高性能的最佳实践
  • 隐私和安全的最佳实践
  • 维护和支持的最佳实践
  • Python 开发的最佳实践

一般来说,科学家使用计算工具来支持他们的研究,他们中的大多数人不会接受正式的计算机科学培训。这可能会导致他们开发低效的解决方案,并且开发周期可能会更长、更耗时。此外,实现的算法可能不是最优的,开发时间较长,并且代码不符合期望的标准。最佳实践帮助他们解决这些问题。遵循最佳实践让科学家将科学作为软件开发的正确方法来实践,并使他们的代码没有不必要的错误。

有许多科学图书馆/应用/工具包完全由非计算机科学背景的科学家设计和开发。尽管如此,这些最佳实践帮助他们获得更好的结果,并提高开发的效率和整体体验。

最佳实践可以被认为是在软件开发中执行期望任务的可重复的标准方法。

设计的最佳实践

本节涵盖了软件开发设计阶段应遵循的最佳实践:

  • Task division among different teams: This best practice says that it is better to distribute the activities of the different steps of the development life cycle among different people. This will reduce the burden on one person and achieve better results in less time. It is better to choose one team (maybe one to two members per team) for each of the design, implementation, and testing phases. These teams will work in collaboration with each other, as they have their respective responsibilities to be performed at different times. This is always better than different teams collaborating with each other. This collaboration is depicted in the following figure with common shape in different steps. The designers may support the developer team in programming, and this approach can be considered as pair programming. Similarly, the collaboration of an implementation team and a testing team will result in fixing of future bugs, and ultimately improve the overall performance of the system.

    The best practices for designing

  • 将大任务分成一组更小的任务:与其一次写一个大程序去执行一个大活动,我们更应该喜欢将任务分成更小的子任务。这是一种渐进的方法,通过逐个完成较小的子任务来完成较大的任务。这将改善整体实现体验和实现代码的质量。遵循这种方法将产生更好的代码,它需要更少的开发工作,并且易于管理。

  • The life cycle for each subtask: Following the development life cycle (that is, designing, developing, and testing) for each small subtask will definitely produce code that is less prone to errors, as each subtask is very well tested. This will also improve the overall quality of the code as the team will be dealing with smaller pieces of code. This approach is presented in the following figure:

    The best practices for designing

    各子任务的生命周期

    采用这种方法将防止开发团队突然陷入重大错误。这也将节省整个应用最终测试期间的工作量。

  • 为每个活动使用专门的软件:建议团队为开发生命周期的每个活动使用专门的软件。大多数活动都有各种各样的标准软件。例如,有一些用于设计和建模工具的软件(例如,Visio)。为了支持开发活动,我们集成了开发环境软件(例如,Eclipse for Java)、版本控制软件(例如,CVS 或 Git)、调试器(例如,GDB)和构建工具(例如,ANT)。还有用于测试应用和性能分析的特定软件。

最佳实践的实施

本节涵盖了软件开发实施阶段采用的最佳实践:

  • 最大化代码和文档中的注释:大多数科学应用都涉及复杂的算法和计算;因此,它们的实现也很复杂。如果大多数复杂的实现都有描述性的注释来解释代码正在做什么,那么对未来的增强会更好。有必要最大限度地增加评论和文档,以便用户/开发人员很好地了解程序背后的想法。特别是,具有复杂逻辑的适当注释将使开发团队能够致力于开发的应用/工具/API 的未来增强。注释应该解释代码的逻辑。

  • 提升可重用性:与其重新发明轮子,不如在开始开发周期之前,为此目的搜索合适的库。这将通过开发一些已经存在的库来节省大量的工作。此外,使用现有且经过良好测试的库开发的代码出现运行时错误或错误的可能性要低得多,因为这些库应该已经被测试并使用过多次。利用现有的图书馆将使科学家的思想自由地沉浸在科学中。这样会省很多力气;唯一需要做的工作就是了解这个库,并将其用于要执行的任务。

  • 先开发一个完整的工作模型:开发一个应用、工具或 API 的好方法是先开发一个工作模型,然后计划优化所开发的解决方案。即使是简单的商业应用也应该遵循这种方法。可以对工作模型进行优化以提高其性能。然而,随着开发一起规划优化可能会转移团队的注意力。因此,开发阶段的重点应该放在实现所需的功能上,并且可以对正常工作的应用、工具和 API 进行优化,以提高其性能。

  • 考虑未来错误的可能性:采取积极主动的方法来应对未来的错误。这种方法包括使用断言、异常处理、自动化测试和调试器。断言可以用来确保特定代码片段的前置条件和后置条件是完整的。自动化测试有助于开发人员确保程序的行为保持不变,即使程序中有修改。在测试过程中检测到的每个错误都应该被转换成一个测试用例,这样它将在未来被自动测试。使用调试器总是比插入print语句来测试程序的有效性更好的选择。使用调试器将帮助开发人员深入了解程序的每个语句的影响。异常处理帮助开发人员主动处理可能的错误。下面的代码片段演示了 Python 中断言的使用:

    # assertion for precondition testing
    def centigradeToFahrenheit (centigrade)
    assert type(centigrade) is IntType, "Not an integer"
      assert (centigrade >= 0), "Less then absolute Zero"
      return (9 * centigrade/5 + 32)
    print centigradeToFahrenheit(40)
    print centigradeToFahrenheit(15)
    print centigradeToFahrenheit(-10)
    # assertion for both pre and post condition testing
    def calculate_percentage (marks1, marks2, marks3)
      assert (marks1 >= 0), "Less then absolute Zero"
      assert (marks2 >= 0), "Less then absolute Zero"
      assert (marks3 >= 0), "Less then absolute Zero"
      result = (marks1 + marks2 + marks3)/100.0)
      assert (0.0 <= result <= 100) "Percentage should be between 0 and 100"
      return result
    
  • Open source/standard publication of data and code: Code development and the preparation of data for experimentations should ideally be done with the aim of publishing them as open source/standards so that both the code and the data will be adopted by peer scientists working in the same field. This will increase awareness about the application, tool, or API, and ultimately result in a large user base.

    发布数据和代码增加了用户基础,这些用户将支持测试和未来增强的努力。数据也将得到改善,并将随着新的用户需求不断更新。通常,开源软件是与来自不同地理位置的许多开发者和科学家合作更新的。为了支持大量的分布式开发人员,版本控制软件的最新趋势是分布式版本控制。分布式版本控制是一个基于 web 的系统,可高度扩展以支持大量开发人员。传统的版本控制软件不是为了支持大量用户在软件仓库中处理代码而设计的。

    The implementation of best practices

    分布式版本控制软件的工作

数据管理和应用部署的最佳实践

本节涵盖应用的数据管理和部署的最佳实践:

  • Data replication: This practice especially focuses on mission-critical applications, where data loss is intolerable, which may be due to the high cost of the experiment, or where the experiment's failure can result in a loss of life. For such mission-critical applications, data replication should be properly planned such that a failure of some components of the system will not affect the overall functionality of the system. The replicated data must be placed at different locations so that a natural disaster at one location will not affect the ultimate processing.

    下图描述了数据复制的概念。每条数据在全球不同位置复制三次。即使一个或两个具有特定部分的系统出现故障,处理也不会停止,因为还有另一个副本。

    The best practices for data management and application deployment

  • 真实和合成数据的测试:应用的测试既要在真实数据上进行,也要在合成数据上进行。如果没有真实的测试数据,那么对合成数据进行测试。为了准备合成数据,使用适当的基于统计分布的随机数生成技术,如第 3 章中所述,有效地制作和管理科学数据。正如第 3 章高效制造和管理科学数据所指出的,一般来说,大多数常见的科学应用都有开放数据集。如果发现合适,这些数据集可以用于应用的实验和测试。

实现高性能的最佳实践

这部分是专门针对要求高性能的应用。本节介绍了实现高性能的最佳实践:

  • 考虑未来的可扩展性需求:不如主动考虑系统未来的可扩展性需求。系统的数据大小可能从非常小的数据到高达“千兆”或“千兆”的巨大数据集不等;在设计过程中,这一方面必须在设计过程中加以考虑。根据需求,可以规划硬件基础设施、软件开发框架和数据库。这个设计过程应该考虑到未来系统可能需要处理巨大数据集的可能性。
  • 硬件和软件选择:投入足够的时间为应用、工具或 API 选择最合适的技术。这一过程将需要初始努力的投资,以选择合适的环境,从而令人满意地实现所需的功能。这种技术选择包括选择合适的编程语言和开发框架、合适的数据库/数据存储、所需的硬件、合适的部署环境等。
  • API 选择:如果有一些现有的 API 来实现期望的功能,那么选择最合适的 API 来实现期望的结果对于成功和高效的实现是至关重要的。在最终确定要使用的 API 之前,应该针对功能和性能需求对其进行适当的分析。最终产品的最终性能直接取决于用于构建系统的 API。
  • 使用适当的性能基准:对于性能关键型应用,使用适当的性能基准。有许多基准可以用来评估不同类型的应用、工具和 API 的性能。例如,DEISA 基准测试套件是专门设计的高性能科学计算应用。通常,基准测试由一组来自应用领域的定制或真实程序组成。这些程序将被执行几次,以评估所研究系统的性能。

数据隐私和安全的最佳实践

数据隐私和安全是成功采用和广泛使用应用需要关注的最重要领域。本节涵盖了应用和数据的适当隐私和安全的最佳实践:

  • 数据隐私:有某些应用需要收集数据,对于一些特定的应用,开发者必须最大限度的照顾用户数据的隐私。这种数据隐私非常重要,因为数据可能是财务或医疗数据,以某种方式丢失它可能会给利益相关者带来巨大损失。在系统开发生命周期的所有阶段,都必须仔细考虑这个问题。
  • web 应用/服务的安全考虑:如果应用被设计为 web 应用/服务,那么在安全方面就必须特别小心,因为基于 web 的系统是安全攻击的主要焦点。几种定义明确的策略可用于保护和攻击基于网络的系统。应该从应用的系统开发生命周期的第一步就考虑预防措施。应该采用适当的授权和认证机制来实现应用的隐私和安全。

测试和维护最佳实践

适当的测试和维护对于适当的软件开发是非常必要的。本节强调在测试和维护活动中应遵循的最佳实践:

  • 先进行单元测试:先进行单元测试会更好。单元测试成功后,系统就可以进行集成测试了。最后,在成功的集成测试之后,应该执行验证测试。单元测试确保系统的不同模块完美工作,并有助于早期发现错误。这不仅会修复模块中的 bug,还支持查找原始想法实现中缺失的部分。由于单元测试是一次针对一个特定的模块执行的,并且关注点很小,所以它可能会识别出在实现阶段遗漏的规范部分。
  • 不同的测试团队:测试是最终产品成功的关键活动。测试阶段的不同功能最好有不同的团队。这些团队可能会合作以获得更好的结果。这将有助于识别实现中的错误和问题,并为最终产品提供更好的整体质量。
  • 支持工作组:为大型系统提供适当的支持和维护活动,最好为系统的每个实质性子部分创建多个工作组。优选地,该特定子任务的至少一个编码员也是其支持组的成员。这样,这个编码员(和成员)可以很容易地识别问题并修复它。每个工作组负责一个特定的子部分。这样,小组中的每个成员都会对该子任务有一个透彻的了解。这些成员将轻松管理支持和维护活动。
  • 多个工作组:对于大型应用,创建多个工作组来划分工作量。每个工作组负责提供支持、维护和增强活动。针对特定模块的专门工作组将有助于提高系统的整体质量,并提供更好的支持。当团队在短时间内遇到与特定模块相关的问题时,他们将了解与系统相关的问题,并最终向系统推荐所需的更新。
  • 用户帮助和支持邮件列表:为每个工作组创建一个用户邮件/反馈列表。用户将向此邮件列表提出问题,支持团队成员将在邮件列表上回复解决方案。这个列表将作为用户和开发者之间的沟通桥梁。

一般 Python 最佳实践

本节讨论 Python 程序员应该遵循的一些一般最佳实践:

  • Python 代码的 PEP 0008 风格指南:这一类的第一个最佳实践是清楚地理解并遵循 PEP 0008。参考https://www.python.org/dev/peps/pep-0008/

  • 命名约定:建议所有编码者遵循一致且有意义的命名约定。这个建议是有帮助的,不仅对最初的开发者,而且对未来可能致力于增强系统的开发者。统一且有意义的名称提高了代码的可读性。命名约定应遵循统一的命名方案,并采用所使用的特定语言的推荐方案,例如,使用下划线或 camel 大小写将多个单词连接到一个变量或函数名中。下表代表推荐名称和不推荐名称:

    |

    不推荐

    |

    被推荐的

    |
    | --- | --- |
    | 变量:var1,var2,mycalculation,S7-1200 可编程控制器,f1,35 | 变量:面积、收入、生产成本、计数器,λ,σ,乘积之和 |
    | 功能:func1(),func 2(),calculation_func(),执行 _func() | 功能:T57】计算面积(),总和的乘积()sinx() |

  • Uniform coding style: Generally, it is recommended that you follow a standard and uniform coding style throughout the system. The use of assertions, indentation, comments, and other things must be uniform in the code. Adopt or develop a standard style for comments and follow it in the coding throughout the system. Similarly, formatting should also be the same in the entire code for the system. It should consider spacing and indentations in the code.

    以下示例描述了较差的和推荐的格式样式:

    |

    不均匀的间距和压痕

    |

    均匀的间距和压痕

    |
    | --- | --- |
    | x=(bd- 4ac)/2ay = 2 * x * x + 4 * x + 5def sample 函数()打印“正在运行”打印“最后一行”def second_sample()打印“正在运行”打印“最后一行” | x =(b * d–4 * a * c)/2 * ay = 2 * x * x + 4 * x + 5def sample 函数()打印“正在运行”打印“最后一行”def second_sample()打印“正在运行”打印“最后一行” |

总结

在本章中,我们讨论了从事科学计算的团队应该遵循的最佳实践。本章首先讨论了设计的最佳实践。之后,讨论了编码的最佳实践。稍后,将介绍数据管理和应用部署的最佳实践。

接下来,讨论了高性能计算的最佳实践,然后介绍了安全性和数据隐私的最佳实践。然后,我们看到了维护和支持的最佳实践。最后,讨论了基于 Python 的一般开发的最佳实践。

posted @ 2025-10-26 09:00  绝不原创的飞龙  阅读(8)  评论(0)    收藏  举报