Python和HDF 5大数据应用

978-7-115-41294-2
作者: 【美】Andrew Collette(科莱特)
译者: 胡世杰
编辑: 陈冀康
分类: Python

图书目录:

详情

本书的目标在于填补市场的空白,对于在Python中,使用HDF5来存储和共享二进制数据给出实践性的介绍。日前,Python-NumPy在数据分析领域然然上升,而且,目前此领域还处在用文档存储大规模科学数据集的阶段。讨论这个主题的时候,会设计Python科学计算包、包所使用开放的格式,包括HDF格式的各种细节,最佳实践,以及用Python处理大规模数据集合的陷阱和问题。

图书摘要

版权信息

书名:Python和HDF 5大数据应用

ISBN:978-7-115-41294-2

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

• 著     [美]Andrew Collette

  译     胡世杰

  责任编辑  陈冀康

• 人民邮电出版社出版发行 北京市丰台区成寿寺路11号

  邮编 100164 电子邮件 315@ptpress.com.cn

  网址 http://www.ptpress.com.cn

• 读者服务热线:(010)81055410

  反盗版热线:(010)81055315

  广告经营许可证:京崇工商广字第0021号


Andrew Collette拥有UCLA的物理学博士学位,目前是科罗拉多大学的实验室研究科学家。他已经在两台几百万美元的研究设备上用Python-NumPy-HDF5进行过科学分析:第一台是UCLA的大型等离子设备(完全基于HDF5标准),第二台是位于科罗拉多大学波德分校的科罗拉多月面粉尘和大气研究中心的超高速粉尘加速器。另外,Collette博士还是HDF5 for Python(h5py)项目的开发领袖。

本书特色

Python语言在科学计算和数据处理领域应用前景广阔。大数据时代,催生了人们处理大量数据的实际需求。

Python应用领域的拓展,越来越多的人将Python用于处理大型数值数据集,使用标准格式来进行数据的存储和通信也显得越来越重要,而HDF5也正迅速成为人们存储科学数据的选择。

图书评论

本书会带你迅速了解使用HDF5对大小从GB至TB的数字数据集进行存档和共享的细节、最佳实践以及陷阱,体验在Python语言中用HDF5存储科学数据。

通过真实世界的例子以及动手练习,你将依次学习科学数据集、层次性组织的组、用户定义的元数据,以及有互操作性的文件等主题。本书的例子对于Python2和Python3都适用。

本书包括以下内容:

本书生产力和创造力的推进器的一个真实的完美例子。本书会让你觉得“HDF5很简单”。


Copyright © 2014 by O’Reilly Media, Inc.

Simplified Chinese Edition, jointly published by O’Reilly Media, Inc. and Posts & Telecom Press, 2015. Authorized translation of the English edition, 2005 O’Reilly Media, Inc., the owner of all rights to publish and sell the same.

All rights reserved including the rights of reproduction in whole or in part in any form.

本书中文简体版由O’Reilly Media, Inc.授权人民邮电出版社出版。未经出版者书面许可,对本书的任何部分不得以任何方式复制或抄袭。

版权所有,侵权必究。


随着Python应用领域的拓展,越来越多的人将Python用于处理大型数值数据集,使用标准格式来进行数据的存储和通信也显得越来越重要,而HDF5也正迅速成为人们存储科学数据的选择。

本书向任何有Python数据分析基本背景的人介绍如何在Python下使用HDF5。本书将侧重于HDF5的本地功能集,而不是Python的高层抽象。熟悉Python和NumPy的读者,更容易阅读和掌握本书的内容。

本书适合有一定基础的Python开发者,尤其适合要使用Python开发数据存储和处理等相关应用的读者阅读参考。


过去的几年里,Python已经和IDL或MATLAB一样,成为科学分析领域值得信赖的选择。它拥有稳健的核心模块,可用于处理数值数组(NumPy)、分析(SciPy)以及绘图(matplotlib),同时还拥有十分丰富的专用模块。它能帮助人们减少编写科学代码的工作量,同时还能提高计算结果的质量。

已经有越来越多的人将Python用于大型数值数据集处理,使用标准格式来进行数据的存储和通信也显得越来越重要。国家超级电脑应用中心(National Center for Supercomputing Applications,NCSA)开发的“层次性数据格式”(Hierarchical Data Format,HDF)的最新版本HDF5正迅速成为人们储存科学数据的选择。很多使用(或有意使用)HDF5的研究人员也被Python的易用性和快速开发能力吸引。

本书向所有有Python数据分析基本背景的人介绍如何在Python下使用HDF5。本书假定读者只熟悉Python和NumPy。本书将侧重于HDF5的本地功能集,而不是Python的高层抽象,以尽力确保在本书建议下创建的HDF文件可移植。

最后,本书将尽力同时支持Python 2和Python 3的用户。本书所有的示例都以Python 2写就,任何有可能导致误会的区别都将在文本中特别注明。

本书使用下列排版规范:

斜体

用于新的名词,URL,E-mail地址,文件名,文件扩展名。

等宽

用于程序列印以及正文内的程序元素,如变量或函数名、数据库、数据类型、环境变量、语句和关键字。

等宽加粗

用于命令或其他需要用户输入的文字。

等宽斜体

用于需要被替换成用户提供的值或根据上下文决定的值。

提示


该图标表示一个提醒、建议,或注意。


警告


该图标表明一个警告。

本书帮助你完成你的任务。一般来说,只要是本书提供的示例代码,你都可以在你的程序和文档中使用它们,而不需要联系我们获得许可,除非你打算将大段代码重新发售。举例来说,你写一个程序用到了本书代码不需要得到许可。但如果你出售或发布一个包含O’Reilly书籍中示例代码的CD-ROM却需要得到许可。引用本书段落及书中例子回答问题不需要得到许可。将本书示例代码大量并入你的产品文档却需要得到许可。

我们会感激但不强求引用注明出处。通常包括书名、作者、出版商和ISBN。比如:“Book Title by Some Author (O’Reilly).Copyright 2012 Some Copyright Holder, 978-0-596-xxxx-x.”

如果你觉得你对代码示例的使用不属于上述的免许可范围,请通过permissions@ oreilly.com联系我们。

在线Safari书籍是一个云端数字图书馆,以书籍和视频的形式提供来自世界顶级的技术作者和商业作者的专业内容。

技术专家、软件开发者、网页设计者和商业创新专家将在线Safari书籍作为他们研究、解决问题、学习和培训认证的首选资源。

在线Safari书籍为组织、政府和个人提供一批产品组合和定价项目。订阅者可以通过一个全文搜索数据库访问出版商提供的成千上万的书籍、培训视频及正式出版前的手稿。这些出版商包括但不限于:O’Reilly Media, Prentice Hall Professional, Addison-Wesley Professional,Microsoft Press, Sams, Que, Peachpit Press, Focal Press, Cisco Press, JohnWiley & Sons, Syngress, Morgan Kaufmann, IBM Redbooks, Packt, Adobe Press, FTPress, Apress, Manning, New Riders, McGraw-Hill, Jones & Bartlett, Course Technology。更多信息请访问我们的网站https://www.safaribooksonline.com/

请将对本书的评论和问题发送给出版商:

美国:

O’Reilly Media, Inc.

1005 Gravenstein Highway North

Sebastopol, CA 95472

中国:

北京市西城区西直门南大街2号成铭大厦C座807室(100035)

奥莱利技术咨询(北京)有限公司

我们为本书制作了一个网页,列出了勘误表、代码示例及各种附加信息。你可以通过这个网址访问:http://www.oreilly.com/catalog/<catalog page>

评论或技术问题可发电子邮件到bookquestions@oreilly.com。

更多信息请访问http://www.oreilly.com网站。

我们的Facebook: http://facebook.com/oreilly

我们的Twitter: http://twitter.com/oreillymedia

我们的YouTube: http://www.youtube.com/oreillymedia

我要感谢HDF组织的Quincey Koziol、Elena Pourmal、Gerd Heber以及其他人在Python社区上对HDF5的支持。感谢来自Eli Bressert和AnthonyScopatz等评审者的评论和来自O’Reilly编辑Meghan Blanchette的指导,他们的奉献令本书得益匪浅。感谢Darren Dale以及其他很多人在h5py项目上的贡献。感谢Francesc Alted,Antonio Valentino和PyTables的共同作者们第一次将HDF5带入Python的世界。最后,我还要感谢UCLA(加利福尼亚大学洛杉矶分校)基础等离子研究机构的Steve Vincena和Walter Gekelman,我曾在那里跟他们一起共事,并第一次接触到大规模科学数据集。


我刚毕业那会遇到过一个严重的问题——一部国家公认的等离子体研究设备花了整整一周时间收集的上千万个数据的值不太对劲。

比正常情况小了约40个数量级

我跟我的咨询师挤在他的办公室,在一台崭新的G5 Mac Pro上运行我们的可视化软件,试图搞明白哪里出了问题。从机器中获得的数据是正确的,实验所使用的数字转换器提交的原始数据看上去没有问题。我在Thinkpad笔记本上用IDL语言编写了一个巨大的脚本将原始数据转换成可视化软件能够识别的文件。这些文件的格式十分简单:一个简短的定长头部后面加上一堆二进制浮点数据。我还另外又花了一个小时写了一个程序来验证这些文件,它们也没问题。但当我将所有这些在IDL中看上去如此优雅的数据导入可视化软件以后,它们看上去就像是一锅粥,毫无特色、杂乱无章,所有的值大约都只有10−41左右。

最后我们发现了问题所在:数字转换器和我的Thinkpad使用了“little-endian”格式,而G5 Mac使用了“big-endian”格式。一台机器输出的原始数据值无法被另一台机器正确地读入,反过来也一样。当时我所有想法中最有礼貌的一句是:这也太笨了。哪怕最后发现此类问题是如此司空见惯以至于IDL专门提供了一个SWAP_ENDIAN函数来处理也并没有令我的情绪变得更好。

在此之前我从不关心数据是如何存储的。这个事件以及其他一些类似事件改变了我的想法。作为一名科学家,我最终意识到,我们不仅需要选择数据的组织和存储,同时也需要选择数据的通信方式。设计优雅的标准格式不仅让每个人的生活变得简单(消除了上面愚蠢而又浪费时间的“endian”问题),而且也使得全世界都能共享这些数据。

在Python的世界里,人们在数值类型大数据的存储机制上进行选择时,迅速对层次性数据格式第5版(Hierarchical Data Format version 5,HDF5)达成了共识。当数据量越来越大的时候,数据的组织就变得越来越重要。命名数据集(第3章)、层次性分组(第5章)和用户自定义元数据“特征”(第6章)等HDF5特性对于数据分析的过程极为必要。

HDF5这种结构化的自我描述格式跟Python相辅相成。目前HDF5已经有两大开发成熟、功能丰富的Python接口模块h5py和PyTables,在两者之上还有许多为特定用途开发的小型封装模块。

这是一个利用HDF5的结构化能力帮助应用程序的简单例子。不要太担心文件结构和HDF5使用API等方面的细节,后续章节自会一一解释。就把这个当成是一次HDF5尝鲜。如果你想要运行这个例子,你需要Python 2并安装NumPy(第2章)。

假设我们有一个NumPy数组,它代表了某次实验获取的一些数据:

  

假设这些数据来自某个气象站十秒一次的温度采样。为了让这些数据有意义,我们还需要记录采样的时间间隔“delta-T”。目前我们把它放到一个Python变量中。

  

同时我们还需要记录第一个数据获取的时间起点,以及这些数据来自15号气象站:

  

我们可以用一个简单的NumPy内建函数np.savez来将这些数据存入磁盘,该函数将每个数据以NumPy数组的格式保存并打包进一个指定名字的zip文件:

  

我们可以用np.load从文件中获取这些数据:

  

目前为止一切顺利。但如果每个气象站的数据不止一组怎么办?比如说还要记录一组风速数据?

  

再假设我们有不止一个气象站。也许我们可以引入某种命名规范,比如“wind_15”作为15号气象站的风速数据,“dt_wind_15”作为采样时间间隔。又或许我们可以使用多个文件……

作为对比,让我们看看如果用HDF5来存储会是怎样:

  

这个例子演示了HDF5的两个杀手级特性:层次性分组和特征。组就像文件系统里的目录,使你可以将相关的数据集保存在一起。本例将来自同一个气象站的温度和风速分别保存在名为“/15”和“/20”的组里。特征允许你在数据上直接附加描述性的元数据。一旦你将这个文件给其他同事,他们可以轻易发现这些信息并明白这些数据的意义:

  

人们正在越来越多地将Python用于大数据集的快速可视化项目,在大规模计算中将Python作为一种高层粘合性语言来协助那些编译型语言如C和FORTRAN。现在一个数据集动不动就是上千GB甚至TB的数据需要处理,HDF5自身最大可以支持EB的规模。

大多数的机器不可能将如此大规模的数据集直接导入内存。HDF5最大的优点之一在于支持子集分片和部分I/O。让我们看一下之前创建的拥有1024个元素的“temperature”数据集:

  

这里的dataset对象是一个HDF5数据集的代理对象。它支持数组切片操作,NumPy用户可能会觉得很熟悉:

  

记住,真正的数据保存在磁盘上,切片操作会去寻找合适的数据并读入内存。这种形式的切片利用了HDF5底层的子集分片功能,所以非常迅速。

HDF5另一个伟大之处在于你可以控制存储的分配。当你创建了一个全新的数据集,除了一些元数据以外它不会占用任何空间,默认情况下仅当你真的需要写入数据时才会占用磁盘上的空间。

比如下面这个2TB的数据集,你可以在几乎任何计算机上创建出来:

  

虽然还没有为其真正分配任何存储,但整个数据集的空间对我们都是可用的。我们可以在数据集的任何地方写入,而磁盘上只会占用必要的字节:

  

在存储非常昂贵的情况下,你甚至可以对数据集进行透明压缩(第4章):

  

HDF5是一种存储相同类型数值的大数组的机制,适用于可被层次性组织且数据集需要被元数据标记的数据模型。

它跟SQL风格的关系型数据库区别相当大,HDF5在组织结构方面有一些特殊的技巧(第8章中有一个例子)。如果你需要在多个表上保持关系,或者想要在数据上进行JOIN,那么一个关系型数据库可能更适合你。又或者你需要在一台没有安装HDF5的机器上读取一个小型的1维数据集,那么CSV这样的文本格式是更合理的选择。

但如果你需要处理多维数组,对性能有非常高的要求,需要在数据集上支持子集分片和部分I/O,需要用特征来给数据集做标记,对关系型特性没有要求,那么HDF5就是完美的选择。

那么说到底,“HDF5”究竟是指什么?我确信它包含下面3点:

1.一种文件规格及相关的数据模型;

2.一个可被C、C++、Java,Python以及其他语言使用的API标准库;

3.一个软件生态系统,由使用HDF5的客户程序以及MATLAB、IDL和Python等“分析平台”组成。

你已经在上面的例子见到HDF5数据模型的三大要素:

数据集:一种数组型对象,在磁盘上保存数值类型的数据;

:层次性容器,可以包含数据集和子组;

特征:自定义元数据信息,可被附加在数据集(以及组!)上。

用户可以使用这些基本抽象构建适合自己问题域的应用格式。比如,我们之前的气象站代码为每个气象站分了一个组,为每个测量参数分配一个数据集,并附加了一些特征以描述数据集的额外信息。这种统一使用“格式内格式”来决定如何用组、数据集和特征来保存信息的方式在实验室或者其他机构中是非常普遍的。

既然HDF5处理一切如“endian”的跨平台问题,数据的分享就只需要对组、数据集和特征进行简单操作并获得结果。由于文件是自我描述的,你甚至不需要了解应用格式就可以从文件中获取数据。你只需打开文件并浏览其内容:

  

任何曾经在读取“简单”二进制格式文件上花费数小时琢磨字节偏移量的人都应该对此充满感激。

最后,HDF5文件的底层字节布局是开放的规格。比起专利软件的二进制格式,这里面没有任何隐秘。虽然基本上人们都会使用HDF组织提供的库来访问这些文件,但是你自己写一个软件去读也没有任何问题。

HDF5文件规格及开源库由一个非营利性组织HDF组织(http://www.hdfgroup.org)维护,其总部位于伊利诺伊州尚佩恩县,原本是伊利诺伊大学香槟分校的一部分。HDF组织的主要产品是HDF5标准库。

该库主要用C语言写成,对C++和Java有一些额外的绑定。人们说起“HDF5”时通常就是指这个库。两大脍炙人口的Python接口模块PyTables和h5py使用的就是这个由HDF组织提供的C库。

这个标准库最主要的一点在于开发者对它的积极维护以及在向下兼容方面花费的巨大精力。标准库的向下兼容不仅仅是API的兼容,亦包括文件格式的兼容。对于HDF5这样的归档文件格式来说,兼容性是一个非常必需的特性。而API兼容则使h5py和PyTables这样的模块有能力处理世界上各种不同版本的HDF5。

对于科学数据的存储,包括长期的存储,你应该对HDF5有信心。由于标准库和文件格式都是开源的,哪怕一颗流星摧毁了伊利诺伊州,你的文件依然能够被读取。

最后,让HDF5特别有用的一个原因是你可以在几乎任何平台上读写文件。IDL语言已经支持HDF5好多年了;MATLAB现在甚至以HDF5作为其“.mat”保存文件的默认格式;Python、C++、Java、.NET和LabView以及其他语言对其都有支持。NASA地球观测系统等机构用户使用的“EOS5”格式是建立在HDF5容器之上的应用格式,刚才我们见到的其实是其简化以后的例子。甚至作为HDF5竞争对手之一的NetCDF,其最新的NetCDF4格式也是实现在HDF5的组、数据集和特征之上。

希望我上面介绍的这些能够让你了解HDF5在科学用途上所向披靡的原因。接下来,我们将看到HDF5工作的基本原理并开始在Python上使用它。


在迫不及待跳进Python代码样例之前,我们有必要花几分钟时间着重关注一下HDF5自身是如何组织的。图2-1展示了HDF5的各种逻辑层。蓝色表示该层处于HDF5标准库内部;绿色则代表使用HDF5的客户软件。

图2-1 HDF5标准库。蓝色代表标准库内部组件;绿色代表调用HDF5的客户代码。灰色代表操作系统提供的资源

大多数客户代码,包括Python模块h5py和PyTables都使用C API(HDF5自己就是用C写成的)。在简介里我们已经知道HDF5的数据模型包含三大公开抽象:数据集(第3章)、组(第5章)和特征(第6章)。C API(以及其上的Python代码)操作这些对象。

HDF5使用各种内部数据结构来表示组、数据集和特征。比如,组使用一种被称为“B树”的数据结构来索引其成员,这使得我们能非常迅速地在一个组内获取成员以及创建新成员,哪怕这个组内存储了上百万个对象(61页,组如何存储)。在考虑性能问题的时候,你通常只需要关心这些数据结构。比如,在使用分块存储(第4章)时,理解数据在磁盘上实际被如何组织非常重要。

下面两层则跟你的数据如何进入磁盘有关。HDF5对象都生存在一个1维逻辑地址空间,就好像一个普通文件。然而这个地址空间和磁盘上的字节之间还有一个额外的HDF5驱动层,负责磁盘的写入机制,同时亦能在处理过程中做一些令人惊叹的事情。

比如说,HDF5的core驱动能够让你的文件完全保存在内存中,读写速度超快。family驱动让你能够将一个文件分成固定大小的多个文件块。mpio驱动则利用消息传递接口(MPI)库使得多个并发的进程访问同一个文件。所有这些驱动对于在上层操作组、数据集和特征的代码来说都是透明的。

背景就介绍到这里。现在让我们开始使用Python!不过,用哪个Python?

Python社区正在经历一场大变。多年以来Python已经积攒了一大堆功能和错误,比如不遵守命名规范的模块或者字符串处理上的缺陷等。为了解决这些问题,人们决定启动Python 3,从Python 2过去的错误中释放出一个全新的Python主版本。

Python 2.7将是最后一个2.X的发行版。虽然为了修理bug,对它的更新还会继续持续一段时间,但是新的Python代码开发工作将只在3.X上进行。NumPy、h5py、PyTables以及其他很多模块现在都支持Python 3。虽然(我认为)对新手直接推荐Python 3还有些操之过急,但未来的趋势却是已经十分明显。

目前来说,两大版本的Python还将同时存在一段时间。因为Python社区的大多数用户都已经习惯了Python 2,本书中的例子也都是以Python 2写就。两大版本在大多数地方都仅有细微差别。比如,Python 3中print的格式是print(foo),而不是print foo。在本书的任何地方,只要出现由于Python版本差异导致的不一致(主要是有关字符串类型和某些字典形式的方法),都会在文本中加以标明。

将Python 2代码“移植”到Python 3并不难,毕竟都是Python。Python 3中一些最有价值的功能其实已经存在于Python 2.7中了。有一个免费工具(2to3)可以自动完成大部分改动,比如将print语句转换成print()函数调用。你可以在http://www.python.org查阅移植手册(以及2to3 工具)。

大多数代码示例都将遵循下面的形式:

  

或者是下面这样更加简单的形式(得益于Python会默认打印出对象):

  

以>>>开头的行代表Python的输入(>>>是Python的默认提示符),其余行代表输出。在某些较长的代码样例中,如果没有显示程序的输出,那么为了清晰起见,我们会略去>>>。

需要在命令行执行的样例会以Unix风格的“$”提示符开头:

  

最后,为了避免样例过于冗杂,大多数代码都默认你已经导入了下面的模块:

  

“NumPy”是世界公认的Python数值型数组模块。本书默认你已经有一定的NumPy经验(当然也包括Python的经验),包括如何使用数组对象。

就算你以前用过NumPy,复习一下NumPy数组的一些基本概念还是有必要的。首先,所有的NumPy数组都有一个固定数据类型“dtype”,由dtype对象表示。下面的例子会创建一个具有10个整型元素的简单数组:

  

我们可以通过arr.dtype获得数组中数据的类型:

  

NumPy通过这些dtype对象来获取内存中数据的类型这种底层信息。本例中我们的10元素数组内的数据是4字节(32位)的整型,NumPy称其为int32。在内存的某处有一个40字节长度的区域保存了0到9这10个值。接收这个arr对象的代码可以根据其dtype属性解析这块内存中的实际内容。

提示


上例在你的系统可能打印出dtype(int64)。这意味着你系统中的Python默认的整型长度是64位而非32位。

HDF5使用了类似的类型系统。HDF5文件中每一个“数组”,也就是数据集,都有一个固定的类型对象表示其类型。h5py模块会自动将HDF5类型系统映射为NumPy的dtype,这使得两者之间的数据交换变得简便。第3章会详细介绍这一过程。

数组切片是NumPy的另一核心功能。这意味着可以对NumPy数组的局部进行访问。下例会抽取arr数组的前4个元素:

  

你还可以指定切片中每两个点之间的距离:

  

在使用HDF5时,我们也会借用这样的“切片”格式来读取一个数据集的部分数据。

在NumPy的世界里,切片以一种高明的方式实现:新创建的数组引用原始数组中的数据而不是另外复制一份。比如,下面的out对象就是原始数组arr的一个视图,我们可以做这样的测试:

  

这意味着切片操作将会非常迅速。但如果你需要修改切片数组而又不希望这个修改影响原始数组时,就必须显式进行复制:

  

警告


忘记在修改切片数组前进行复制是一个常见的错误,尤其是对于那些习惯了IDL的人来说。如果你是NumPy新手,你需要特别小心!

幸好HDF5数据集的“切片”并不是这样。当你读取文件时,由于数据保存在磁盘上,你得到的始终是一个复制。

我们将会通过“h5py”模块来使用HDF5。该模块包含了文件、组、数据集以及特征等HDF对象的上层封装类,同时还包含了HDF5的C语言数据结构和函数的底层封装类。本书中的样例假定h5py的版本是2.2.0或更高,你可以从http://www.h5py.org 获取。

值得注意的是h5py并不是唯一一个跟HDF5打交道的常用模块。PyTables(http://www.pytables.org )是一个基于HDF5的科学数据库模块并增加了数据集索引和额外的类型系统。不过我们这里只关注原生HDF5,所以我们将只讨论h5py,但我强烈推荐你去调查一下PyTables,看看它有没有什么吸引你的功能。

如果你使用Linux,最好用包管理器安装HDF5标准库。Windows上,你可以从http://www.h5py.org 下载安装程序或下载某个自带HDF5/h5py的Python安装包,如PythonXY,Continuum Analytics公司提供的Anaconda,或者Enthought公司提供的Python安装包等。

如果你想用Python进行大规模分析或开发,那么除了NumPy和h5py/HDF5以外,IPython也是一个必需的组件。IPython最基本的功能是一个可以增添如命令历史和TAB补全等特性的解释器shell,可用于替换Python。除此之外它还具有如并发处理、MATLAB风格的记事本等很多额外的功能。

想要了解本书中所提到的特性最好的方法就是打开IPython提示符,然后输入本书的样例。光TAB补全这一个功能就很不错了,因为它能够让你快速查阅模块和对象的特征。h5py模块在设计上就充分考虑了这种可查阅能力。比如,如果你需要查看File对象上具有哪些属性和方法(2.4节),输入h5py.File,然后按TAB键:

  

如果需要获得某个属性或方法更多的信息,只需要在其名字后面使用“?”即可:

  

提示


IPython默认会在一个特殊的隐藏变量中记录你语句的输出。一般来说这没什么问题,但是如果它记录了某个你认为已经丢弃的HDF5对象,或者一个耗费大量内存的大数组,那它也许就会让你大吃一惊。你可以将IPython的配置项cache_size设置为0来关闭这一功能。详情请见http://ipython.org中的文档。

我们用Python内置的timeit模块来进行性能测试。相关样例会默认你已经导入了timeit模块,如下所示:

  

timeit函数需要一个可执行命令(字符串或可执行对象)和一个可选参数指定其运行次数。然后它会打印出执行该命令花费的总时间。在下面的例子里,我们将执行5次time.sleep

  

IPython有一个类似的内建“魔法”函数%timeit,它可以多次执行给定的语句并报告最短执行时间:

  

考虑到普通的timeit函数是由Python标准库提供的,我们在本书中将只使用普通的timeit函数。

既然人们用HDF5处理的一般都是大数据集,那么性能就是一个不得不考虑的问题。不过你会注意到本书对于性能优化和性能测试的讨论将不会深入到缓存命中、数据转换率等细节。h5py模块的设计将所有这些细节都交给HDF5掌管。开发者们在HDF5性能调优上凝结了上千人几年的心血,已经达到了可能的极致。

作为一个应用程序开发者,在性能上你能做的最好的事就是明智地使用API并让HDF5来做背后的工作。下面是一些建议:

1.不要优化任何东西,除非存在可以验证的性能问题。在改变任何东西之前先仔细隔离可能导致错误行为的代码部分。

2.先从简单直观的代码开始,充分利用API提供的功能。比如,当你需要遍历一个文件中所有的对象时,应该使用HDF5的Visitor功能(63页,用Visitor模式多级遍历)而不是用你自己粗制滥造的方法。

3.首先考虑算法上的改进。比如,在写入一个数据集(见第3章)时,每次写入一个合理大小的块而不是一个值一个值地写。这使得HDF5可以充分利用文件系统。

4.确保你使用了正确的数据类型。比如你正在运行一个计算密集型程序,它的功能是从文件中读取浮点数,如果计算只要求单精度,那么你最好使用双精度浮点。

5.最后,勇于在h5py邮件列表、NumPy/Scipy邮件列表、Stack Overflow或别的社区网站上提问。这些年来已经有无数人在使用NumPy和HDF5,大多数的性能问题都有一个已知的解决方案。Python社区欢迎你。

在后续章节里,我们将创建大量的文件,需要一种方法能够独立地查看其中的内容。特别是当你需要将文件归档或者共享给其他同事的时候,对错误数据类型的检查是越早越好。

HDFView是HDF组织提供的一个免费的图形界面HDF5文件浏览器。虽然功能比较简单,但它是用Java写的,所以在Windows、Linux和Mac上都可以使用。它有一个内建的表格样式的数据浏览器,也能进行基本的绘图功能。

图2-2显示了一个HDF5文件的内容。左边的面板上列出了多个组。组1被打开,并显示了其包含的数据集。其中一个数据集又被打开,其内容被显示在右边的表格视图上。

图2-2 HDFView

HDFView还允许你查看数据集和组的特征。基本上只要是HDF5支持的数据类型它都支持,除了某些长度可变的数据结构。

ViTables是另一个免费的图形界面浏览器,图2-3显示了同一个HDF5文件在ViTables上打开的界面。它为PyTables文件做了优化,不过也能完美处理原生的HDF5文件。ViTables的一大优势在于它是随着某些版本的Python打包安装的,比如PythonXY,所以你可能已经拥有它了。

图2-3 ViTables

如果你已经习惯了命令行,那一定要安装HDF命令行工具。基本上所有的包管理器都可以帮你安装它,如若不然,你可以在http://www.hdfgroup.org 上下载。连Windows版的都有。

本书多处用到了一个名字叫h5ls的程序,它可以列出HDF5文件的内容。下例用h5ls列出了一个HDF5文件包含的多个数据集和一个组:

  

我们可以用-vlr选项来打印一些额外信息并递归地打印组的成员:

  

这个格式有点用了,我们可以看到array数据集内的对象的类型是本地整型,且是一个有10个元素的1维数组。同样,在group组内有一个2维的subarray数据集,对象类型也是本地整型。

查看元数据像这样用h5ls就足够了。还有一个叫做h5dump的程序,它以更为清晰的格式打印出数据。

  

  

在我们研究组和数据集之前,让我们先看一下File对象能做些什么,来作为你进入HDF5世界的起点。

这里有一个最简单的使用HDF5的程序:

  

File对象是你的起点。它提供方法使你能够在文件内创建新的数据集或组,另外还有一些一目了然的属性如.filename.mode等。

说到.mode,HDF5文件支持Python对普通文件的读写模式:

  

还有一个额外的HDF5专有模式用于保护你不会意外覆盖某个已存在的文件:

  

如果一个同名文件已经存在则该函数会失败,否则会创建一个新文件。如果你需要长期运行一个计算程序而且不希望当脚本第二次运行时覆盖你已有的输出文件,你可以用w-模式打开它:

  

另外,你可以随意使用Unicode文件名!假设你的操作系统支持UTF-8编码,你只需提供一个普通的Unicode字符串:

  

提示


你可能在想如果你的程序在打开文件时崩溃会怎样。如果你的程序抛出Python异常,别担心!HDF库会在程序退出时自动帮你关闭所有打开的文件。

Python 2.6的最酷特性之一是支持了环境管理器。环境管理器通过with语句使用,它们是一些具有特殊方法的对象,这些特殊方法在进入和离开代码块时被调用。下面这个经典的例子使用了Python内建的file对象:

  

上面的代码打开的全新的file对象仅在f代码块中有效。当f退出时文件被自动关闭(哪怕抛出了异常!)。

h5py.File对象完全支持这种用法。这可以确保文件总是能被正确地关闭,而不需要把所有的代码包含在try/except块中:

  

文件驱动处于文件系统和HDF5高级抽象(组、数据集和特征)之间。它们处理HDF5地址空间到磁盘上的字节之间的映射关系。一般情况下你无需担心当前使用了哪个驱动,因为默认的驱动适用于大部分的应用程序。

一旦文件被打开,驱动模块就完全透明了。你只需要跟HDF5库打交道,驱动会帮你处理底层存储。

下面是一些比较有意思的驱动,可以帮助你解决一些不常见的问题。

1.core驱动

core驱动会将你的文件整个保存在内存中。它对于你能够存储的数据量显然是有限制的,带来的好处则是超快速的读写。当你需要以内存级的高速来访问HDF5结构时,这是一个很好的选择。你可以将driver关键字设为“core”来开启这个驱动:

  

你还可以要求HDF5在磁盘上创建一个“备份存储”文件,当内存中的文件映象被关闭时,其内容会被保存到磁盘上:

  

另外,backing_store关键字同时也告诉HDF5在打开文件时从磁盘读取已存在的文件。所以只要整个文件都能被放入内存,那么你只需要对磁盘文件读写各一次。像数据集的读写、特征的创建等操作都完全不会占用磁盘I/O。

2.family驱动

有时候你会需要将一个大文件分成多个大小一致的文件,这个功能最初是为了支持那些不能处理2GB以上文件的文件系统。

  

由于历史上的原因,默认的memb_size是231−1。

3.mpio驱动

这个驱动是并发HDF5的核心。它允许多个同时运行的进程访问同一个文件。你可以同时有成百上千个并发计算的进程,它们在共享访问磁盘上同一个文件时能保证数据的一致性。

使用mpio驱动需要一些技巧。第9章会详细介绍该驱动以及在并发环境下使用HDF5的最佳实践。

HDF5一个有意思的特性是文件内容可以被任意用户数据占用。当一个文件被打开时,HDF5库会在文件最开头搜索HDF5头部,然后是前512字节,前1024字节这样以2的指数递增。这种处于文件开头的数据被称为用户块,你可以在用户块里放任何你需要的数据。

唯一的限制是块的大小(必须是2的指数且最小512),而且当你往用户块内写入数据时,记得要先在HDF5中关闭该文件,示例如下:

  

接下来我们将要看到的是NumPy用户非常熟悉的数组类型,同时也是HDF5数据模型中的第一个主要对象:数据集。


相关图书

深度学习的数学——使用Python语言
深度学习的数学——使用Python语言
动手学自然语言处理
动手学自然语言处理
Web应用安全
Web应用安全
Python高性能编程(第2版)
Python高性能编程(第2版)
图像处理与计算机视觉实践——基于OpenCV和Python
图像处理与计算机视觉实践——基于OpenCV和Python
Python数据科学实战
Python数据科学实战

相关文章

相关课程