精通 Python 数据可视化(一)

原文:Mastering Python Data Visualization

协议:CC BY-NC-SA 4.0

零、前言

数据可视化旨在清晰地提供信息,并帮助查看者定性地理解它们。一幅画胜过千言万语这一广为人知的说法,可以改写为“一幅画讲述一个故事,也是一大堆文字的集合”。因此,可视化是一个非常宝贵的工具,可以帮助观众快速理解一个概念。然而,数据可视化与其说是一种技能,不如说是一门艺术,因为如果你试图过度使用它,它可能会产生相反的效果。

我们目前面临着大量的数据,这些数据包含了许多洞见,这些洞见是现代成功的关键。重要的是找到数据,清理它,并使用正确的工具来可视化它。这本书解释了使用 Python 包可视化数据的几种不同方法,以及在许多不同领域非常有用的例子,如数值计算、金融模型、统计和机器学习以及遗传学和网络。

本书展示了在 Mac OS X 10.10.5 上使用 Python 2.7、IPython 0.13.2、matplotlib 1.4.3、NumPy 1.9.2、SciPy 0.16.0 和 conda build 1 . 14 . 1 版本开发的示例代码。

这本书涵盖了什么

第一章,一个数据可视化概念框架,阐述了数据可视化实际上应该被称为“知识推理的信息可视化”。本章涵盖了框架,解释了从数据/信息到知识的过渡,以及有意义的表示(通过对数、颜色图、散点图、相关性等)如何使知识更容易掌握。

第二章数据分析与可视化,说明了可视化的重要性,展示了可视化过程中的几个步骤,包括几个可供选择的工具选项。可视化方法已经存在很久了,我们很早就接触到了;例如,即使是小孩子也能解读条形图。交互式可视化有许多优点,本章用例子来解释它们。

第 3 章Python IDE 入门解释了如何使用 Continuum Analytics 中的 Anaconda,而无需担心单独安装每个 Python 库。Anaconda 简化了打包和部署方法,使 IPython 笔记本与其他库一起运行变得更加容易。

第 4 章数值计算和交互式绘图,涵盖了交互式绘图方法,并附有计算物理和应用数学中的工作示例。一些值得注意的例子是插值方法、逼近、聚类、采样、相关和使用 SciPy 的凸优化。

第 5 章金融和统计模型探讨了金融工程,其中有许多数值和图形方法,成为探索 Python 的有趣用例。本章包括股票报价,回归分析,蒙特卡罗算法,模拟方法和例子。

第 6 章统计和机器学习,涵盖了统计方法,如线性和非线性回归以及使用 numpy、scipy、matplotlib 和 scikit-learn 的聚类和分类方法。

第 7 章生物信息学、遗传学和网络模型,涵盖了一些有趣的例子,比如现实生活中的社交网络和有向图实例,适合这些问题的数据结构,以及网络分析。本章使用特定的库,如图形工具、网络、matplotlib、scipy 和 numpy。

第八章高级可视化,涵盖仿真方法和信号处理实例,展示几种可视化方法。这里,我们还对其他高级工具进行了比较,例如 Julia 和 D3.js。

附录前进探索可视化,给出了 conda 的概述,并列出了各种 Python 库。

这本书你需要什么

对于这本书,您需要在操作系统上安装 Python 2.7.6 或更高版本。对于本书中的示例,使用了 Mac OS X 10.10.5 的 Python 默认版本(2.7.6)。本书使用的其他软件包是 IPython,这是一个交互式 Python 环境。IPython 的新版本叫做 Jupyter,它现在有 50 种不同语言的内核。

如果可能的话,安装预先打包的科学 Python 发行版,例如来自 Continuum 的 Anaconda 或 entorn Python 发行版。Anaconda 通常附带 300 多个 Python 包。对于预打包列表中没有包含的 Python 包,您可以使用 pip 或 conda 来安装它们。在附录前进探索可视化中提供了一些示例。

这本书是给谁的

有很多关于 Python 和数据可视化的书籍。然而,很少有人可以推荐给那些想在现有的 Python 知识基础上进行构建的人,更少有人讨论利基技术来使您的代码更容易使用和重用。如果你知道一些关于 Python 编程的知识,但是有一种永不满足的动力去学习更多,这本书将向你展示获得分析结果和产生惊人的视觉显示的方法。

这本书涵盖了使用现实问题产生分析结果的方法。不是写给初学者的,但是如果需要澄清,可以按照书中建议的阅读提示来做。如果这本书是你第一次接触 Python 或数据可视化,你最好学习一些介绍性的文本。我最喜欢的是约翰·古塔格教授的《计算机科学与编程导论》和加州大学洛杉矶分校的内森·尤的《T2 可视化》。

惯例

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

文本中的码字、数据库表名、文件夹名、文件名、文件扩展名、路径名、伪 URL、用户输入和 Twitter 句柄如下所示:“首先我们使用 SciPy 中的norm()来创建正态分布样本,稍后,使用 NumPy 中的hstack()来水平堆叠它们并应用 SciPy 中的gaussian_kde()

代码块设置如下:

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
students = pd.read_csv("/Users/Macbook/python/data/ucdavis.csv")
g = sns.FacetGrid(students, palette="Set1", size=7)
g.map(plt.scatter, "momheight", "height", s=140, linewidth=.7, edgecolor="#ffad40", color="#ff8000")
g.set_axis_labels("Mothers Height", "Students Height")

当我们希望将您的注意力吸引到代码块的特定部分时,相关的行或项目以粗体显示:

import blockspring 
import json  

print blockspring.runParsed("stock-price-comparison", 
   { "tickers": "FB, LNKD, TWTR", 
   "start_date": "2014-01-01", "end_date": "2015-01-01" }).params

任何命令行输入或输出都编写如下:

conda install jsonschema

Fetching package metadata: ....
Solving package specifications: .
Package plan for installation in environment /Users/MacBook/anaconda:

The following packages will be downloaded:

 package                    |            build
 ---------------------------|-----------------
 jsonschema-2.4.0           |           py27_0          51 KB

The following NEW packages will be INSTALLED:

 jsonschema: 2.4.0-py27_0

Proceed ([y]/n)?

新名词重要词语以粗体显示。您在屏幕上看到的单词,例如菜单或对话框中的单词,会出现在文本中,如下所示:“此外,您可以选择复制代码选项,将代码块的内容复制到 Canopy 的复制粘贴缓冲区中,以便在编辑器中使用。”

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

型式

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

读者反馈

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

要给我们发送一般反馈,只需发送电子邮件<[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/8327 OS _ graphics . 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)>联系我们,我们将尽最大努力解决问题。

一、数据可视化的概念框架

互联网和社交媒体在现代的存在导致了大量的数据,数据量的增长超乎想象。这是如何以及何时开始的?

十年前,一种新的经营方式出现了:公司从整个企业的来源收集、组合和处理大量数据。他们的目标是使用大量数据来改进决策过程。大约在同一时间,亚马逊、雅虎和谷歌等处理大量数据的公司取得了重大进展。这些里程碑导致了支持大数据的多项技术的诞生。我们不会详细讨论大数据,但会尝试探索为什么许多组织改变了他们的方式,使用类似的想法来进行更好的决策。

这些大量的数据究竟是如何用来做出更好的决策的?我们最终会做到这一点,但首先让我们试着理解数据、信息和知识之间的区别,以及它们如何与数据可视化相关联。人们可能会想,为什么我们在谈论数据、信息和知识。有一个故事绘图连接了我们如何开始,我们从什么开始,所有这些事情如何有益于业务,以及可视化的作用。我们将通过简要回顾相关步骤来确定数据可视化所需的概念框架。

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

  • 数据、信息、知识和洞察力之间的区别
  • 信息转化为知识,进而转化为洞察力
  • 收集、处理和组织数据
  • 数据可视化的历史
  • 可视化数据如何帮助决策?
  • 可视化图

数据、信息、知识和洞察力

术语数据信息知识在计算机科学的上下文中被广泛使用。这些术语有许多定义,往往相互冲突,不一致。在我们深入这些定义之前,我们将了解这些术语如何与可视化相关。数据可视化的主要目标是获得对数据或信息的洞察(隐藏的真相)。本书中关于数据、知识和洞察力的整个讨论都是在计算机科学的背景下进行的,而不是心理学或认知科学。对于认知语境,可以参考https://www . UCSF . edu/news/2014/05/114321/converting-data-knowledge-insight-and-action

数据

术语数据 意味着一个可以从中得出结论的前提。虽然数据和信息在某种背景下看起来是相互关联的,但数据实际上是指数字形式的离散客观事实。数据是基本的构建模块,当以不同的方式组织和排列时,会产生有助于回答一些业务问题的信息。

数据可以是非常简单的东西,但是数量庞大且没有组织。这种离散的数据不能单独用于决策,因为它没有意义,更重要的是,因为它们之间没有结构或关系。数据收集、传输和存储的过程因数据类型和存储方法而异。数据有多种形式;一些值得注意的形式如下:

  • CSV 文件
  • 数据库表
  • 文档格式(Excel、PDF、Word 等)
  • HTML 文件
  • JSON 文件
  • 文本文件
  • XML 文件

信息

信息是经过处理的数据,作为一个商业问题的答案。当我们添加关系或关联时,数据就变成了信息。关联是通过为数据提供上下文或背景来实现的。背景是有帮助的,因为它允许我们回答关于数据的问题。

例如,让我们假设给定的篮球运动员的数据包括身高、体重、位置、大学、出生日期、选秀、选秀轮次、NBA 首秀和招募排名。问题的答案“身高超过六尺,打控卫位置的选秀状元是谁?”也是信息。

同样,每个玩家的分数都是一条数据。“今年谁的场均得分最高,他的得分是多少”这个问题的答案是“勒布朗·詹姆斯,27.47”,这也是信息。

知识

当人类解释和组织信息并利用这些信息来推动决策时,知识就出现了。知识是通过经验获得的数据、信息和技能。知识包括做出适当决策的能力以及执行决策的技能。

基本要素——连接数据——让我们了解每条信息的相对重要性。通过比较过去的结果和识别模式,我们不必从头开始构建问题的解决方案。下图总结了数据、信息和知识的概念:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_01.jpg

知识以递增的方式变化,特别是当信息被重新排列或重组时,或者当一些计算算法改变时。知识就像一个指向算法结果的箭头,依赖于来自数据的过去信息。在许多实例中,知识也是通过与结果的视觉交互获得的。另一方面,洞察力打开了通往未来的道路。

数据分析与洞察

在我们深入洞察的定义及其与业务的关系之前,让我们看看捕捉洞察的想法是如何开始的。十多年来,组织一直在努力理解他们拥有的所有数据和信息,尤其是在数据量爆炸式增长的情况下。他们都意识到了数据 分析(也称为数据分析分析)的重要性,以便根据现有数据和信息做出最佳或现实的业务决策。

分析依赖于数学算法来确定数据之间的关系,从而产生洞察力。理解洞察力的一个简单方法是考虑一个类比:当数据没有结构和与业务的适当一致时,它通过将数据转换为更结构化的形式并使其更接近业务目标来给出更清晰和更深刻的理解。顿悟就是有突破性结果出来的“灵光乍现”时刻。人们不应该混淆术语分析和商业智能。分析具有预测能力,而商业智能基于对历史数据的分析提供结果。

分析通常适用于更广泛的数据,因此,数据协作通常发生在内部和/或外部。在一些商业范例中,协作只发生在广泛的数据集集合的内部,但在大多数其他情况下,外部连接有助于连接点或完成难题。外部数据连接的两个最常见来源是社交媒体和消费者群。

在本章的后面,我们将参考现实生活中的商业故事,这些故事通过应用分析来获得洞察力和推动商业价值,改进决策,并更好地了解他们的客户,从而取得了一些显著的成果。

数据的转换

到现在我们已经知道什么是数据,但是现在的问题是:收集数据的目的是什么?数据对于描述物理或社会现象以及进一步回答关于该现象的问题是有用的。因此,确保数据没有错误、不准确或不完整非常重要;否则,基于该数据的响应也将是不准确或不完整的。

有不同类别的数据,有些是过去的性能数据实验数据基准数据。过去的性能数据和实验数据是非常不言自明的。另一方面,基准数据是将两个不同项目或产品的特性与标准测量进行比较的数据。数据被转换成信息,被进一步处理,然后用于回答问题。因此,很明显,我们的下一步是实现这一转变。

将数据转化为信息

数据被收集并根据内容及其重要性以几种不同的形式存储。例如,如果数据是关于季后赛篮球比赛的,那么它将是文本和视频格式的。另一个例子是一个国家所有城市的温度记录,通过不同的格式收集和提供。从数据到信息的转换涉及数据的收集、处理和组织,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_02.jpg

收集到的数据需要一些处理和组织,这些数据以后可能有也可能没有结构、模型或模式。然而,这个过程至少给了我们一个有组织的方式来寻找关于数据的问题的答案。这个过程可以是基于篮球运动员总得分的简单排序,也可以是基于城市和州名的排序。

从数据到信息的转换也可能不仅仅是排序,比如统计建模或计算算法。正是这种从数据到信息的转换非常重要,它使得数据能够被查询、访问和操作。在某些情况下,当有大量不同的数据时,转换可能涉及处理方法,如过滤、聚合、应用相关性、缩放和归一化以及分类。

数据收集

数据采集是一个耗时的过程。因此,企业正在寻找更好的方法来自动化数据捕获。然而,对于许多过程来说,手动数据收集仍然很普遍。现代通过自动过程进行的数据收集使用传感器等输入设备。例如,水下珊瑚礁通过传感器进行监测;农业是传感器用于监测土壤特性、控制灌溉和施肥方法的另一个领域。

另一种自动收集数据的方法是扫描文档和日志文件,这是服务器端数据收集的一种形式。手动过程包括通过基于网络的方法收集数据,这些数据存储在数据库中,然后可以转换成信息。如今,基于网络的协作环境正受益于改进的通信和数据共享。

传统的可视化和可视化分析工具通常是为在单台机器上与可视化应用交互的单个用户设计的。扩展这些工具以包括对协作的支持,显然已经在增加可视化在现实世界中的范围和适用性方面取得了很大进展。

数据预处理

今天,由于数据的大小和可能来自多个不同的来源和类型,数据非常容易受到噪声和不一致性的影响。有数据清理数据整合数据约简数据转换等多种数据预处理技术。数据清理可用于消除噪声和纠正数据中的不一致。数据集成将来自多个来源的数据合并成一种连贯的格式,通常称为数据仓库。例如,数据缩减可以通过合并、聚合和消除冗余特征来减少数据大小。数据转换可以应用于数据被缩放到较小范围内的情况,从而提高处理和可视化数据的准确性和效率。数据的转换周期如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_03.jpg

异常检测是对收集的数据中可能不符合预期行为或模式的异常数据的识别。异常也被称为异常值或噪声;例如,在信号数据中,不寻常的特定信号被认为是噪声,而在交易数据中,异常值是欺诈性的交易。准确的数据收集对于保持数据的完整性至关重要。除了异常的负面影响,另一方面,异常值也非常重要——例如,特别是在人们想要发现欺诈性保险索赔的情况下。

数据处理

数据处理是转化过程中的重要一步。当务之急是将重点放在数据质量上。有助于准备数据以便更好地分析和理解数据的一些处理步骤是相关性建模聚类。还有其他处理技术,但我们将在这里只讨论两种最流行的处理方法。

依赖建模是对数据进行建模以确定表示的性质和结构的基本原则。该过程搜索数据元素之间的关系;例如,百货公司可能会收集顾客购买习惯的数据。这个过程有助于百货商店推断关于频繁购买的信息。

聚类的任务是发现数据中以某种方式具有“相似模式”的组,而不使用数据中已知的结构。

组织数据

数据库管理系统允许用户以结构化格式存储数据。但是,数据库太大,无法放入内存。结构化数据有两种方式:

  • 以表格、树或图形等结构化格式将大数据存储在磁盘中
  • 使用数据结构格式将数据存储在内存中,以加快访问速度

数据结构包括一组不同的格式,用于构造能够存储和访问数据的数据。一般的数据结构类型有数组、文件、表、树、列表、映射等。任何数据结构都是为了组织数据以适应特定的目的而设计的,这样就可以在运行时存储、访问和操作数据。可以选择或设计数据结构来存储数据,以便使用各种算法对其进行处理,从而实现更快的访问。

被收集、处理和组织起来以便有效存储的数据更容易理解,这导致可以更好地理解信息。

获取数据集

对于无法访问组织数据的读者来说,互联网上有大量的资源,这些资源包含来自几个不同来源的丰富数据集,例如:

将信息转化为知识

信息是可量化、可度量的,它有形状,可以访问、生成、存储、分发、搜索、压缩、复制。它可以用信息量来量化。

信息通过离散算法的应用转化为知识,知识被期望比信息更具定性。在一些问题领域,知识继续经历一个不断发展的循环。这种演变尤其发生在数据实时变化的时候。

知识就像食谱,让你用信息做面包,在这种情况下,面粉和酵母的成分。另一种看待知识的方式是将数据和信息结合起来,在此基础上增加经验和专家意见来帮助决策。知识不仅仅是过滤或算法的结果。

这一转变涉及哪些步骤,变化是如何发生的?自然,它不能自己发生。尽管信息这个词根据定义会有不同的解释,但我们将在计算的背景下进一步探讨它。

一个简单的类比来说明信息和知识的区别:特定课程的课程材料为你提供了关于概念的必要信息,老师后来通过讨论帮助学生理解概念。这有助于学生获得课程知识。通过类似的过程,需要做一些事情来将信息转化为知识。下图展示了从信息到知识的转化:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_04.jpg

如图所示,当信息通过一些离散算法聚集和运行时,就会转化为知识。需要对信息进行汇总,以获得更广泛的知识。通过这种转变获得的知识有助于回答关于数据或信息的问题,例如公司哪个季度的销售收入最大?广告在多大程度上推动了销售?或者说,今年发布了多少新品?

将知识转化为洞察力

在传统系统中,信息被处理,然后被分析以生成报告。自从互联网出现以来,经过处理的信息已经并且总是可用的,社交媒体已经成为一种新的商业方式。

组织一直在使用外部数据,通过数据分析获得洞察力。例如,消费者通过推特发推来衡量用户情绪,用来跟踪对产品品牌的意见。在某些情况下,有更高比例的用户在社交媒体上对新产品给出积极的信息,比如 iPhone 或平板电脑。分析工具可以提供这种情绪的数字证据,而这正是数据可视化发挥重要作用的地方。

另一个说明这种转变的例子是,网飞在 2009 年宣布了一项最佳协同过滤算法竞赛,根据以前的评分来预测电影的用户评分。该竞赛的获胜者使用了实用主义理论,在预测用户评级方面取得了 10.05%的改进,这增加了网飞的商业价值。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_05.jpg

使用协作和分析将知识转化为洞察力,如前面的图所示。洞察意味着看到解决方案并意识到需要做什么。获取数据和信息很容易,组织有已知的方法来实现这一点,但获得洞察力非常困难。获得洞察力需要新的创造性思维和连接点的能力。除了应用创造性思维,数据分析和数据可视化在获得洞察力方面也发挥着重要作用。数据可视化被认为是一门艺术,也是一门科学。

数据可视化历史

可视化的根源在于一个悠久的历史传统,即使用原始绘画和墙上的地图、数字表和粘土上的绘画来表示信息。然而,它们并不被称为可视化或数据可视化。数据可视化是一个新名词;它表达了这样的想法,即它不仅仅涉及以图形形式表示数据。数据背后的信息应该通过良好的展示以直观的方式展现出来;图形应该有助于观众看到数据的结构。

计算机前的可视化

在巴比伦时代早期,图画是在粘土上画的,在后期则是在纸莎草纸上画的。这些绘画和地图的目的是为观众提供对信息的定性理解。我们也知道理解图片是我们的自然本能,因为信息的视觉呈现更容易被感知。本节仅包括可视化历史的部分细节。对于详细的细节和例子,我们推荐两个有趣的资源:

米纳德的俄国战役(1812)

查尔斯·米纳德是一名在巴黎工作的土木工程师。他用形象的地图概括了 1812 年的战争——拿破仑向莫斯科进军。这张地图是一张简单的图片,它既是一张视觉时间线,也是一张地理地图,描绘了军队的规模和方向、温度以及地标和位置。爱德华·塔夫特教授将这张图片描述为有史以来最好的统计图表,这是出了名的。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_06.jpg

楔形从左边的厚开始,我们看到军队在波兰边境开始了 422,000 人的战役。随着越来越深入俄罗斯,温度越来越低,楔形变得越来越窄。这种可视化设法将许多不同的数字和地理事实浓缩成一幅图像:当军队减少时,减少的原因,以及随后他们的撤退。

伦敦的霍乱流行(1831-1855)

1831 年 10 月,英国发生了第一例亚洲霍乱,超过 52000 人死于这场流行病。随后,在 1848-1849 年和 1853-1854 年,更多的霍乱流行导致大量死亡。

1855 年,约翰·斯诺博士绘制了一张地图,显示了聚集在伦敦布罗德街水泵周围的霍乱死亡人数。约翰·斯诺博士的这张地图是一个里程碑式的图形发现,但不幸的是,它是在那个时期结束时设计出来的。他的地图显示了每个死者的位置,这为他的结论提供了一个视角,即疫情的源头可能是布罗德街一个水泵的污染水。大约在那个时候,图表的使用在经济和国家规划中变得很重要。

统计图形(1850-1915)

到了 18 世纪中期,视觉化在整个欧洲迅速发展。1863 年,高尔顿的欧洲多元天气图中有一页显示了 1861 年 12 月的气压、风向、雨量和温度(资料来源:剑桥大学出版社弗朗西斯·高尔顿的生平、书信和著作)。

在这一时期,统计图形成为主流,有许多教科书都是这样写的。这些教科书包含了图解方法的详细描述,讨论了频率,以及尺度和基线的选择对差异和比率的视觉估计的影响。它们还包含历史图表,其中两个或多个时间序列可以显示在一个图表上,以便对它们的历史进行比较。

数据可视化的后期发展

1962 年,约翰·图基呼吁承认数据分析是统计学的一个合法的分支;不久之后,他开始在标题为探索性数据分析 ( EDA )下发明各种新的、简单而有效的图形显示,随后是探索性空间数据分析 ( ESDA )。图基后来在 1977 年写了一本名为探索性数据分析的书。有许多工具可用于图形技术的电子设计自动化,如下所示:

  • 方块-触须图(方块图)
  • 柱状图
  • 多元 ari 图表(来自烛台图表)
  • 运行序列图
  • 帕累托图(以维尔弗雷多·帕累托命名)
  • 散点图
  • 多维标度
  • 目标投射追踪

科学计算中的可视化正在成为一个重要的基于计算机的领域,其目标是提高对数据的理解并做出快速的实时决策。今天,医生诊断疾病的能力取决于视力。例如,在髋关节置换手术中,定制的髋关节现在可以在手术前制造。可以在手术前使用无创 3D 成像进行精确测量,从而将术后身体排斥反应的数量从 30%减少到仅 5%(来源:http://bone smart . org/hip/hip-imports-specialized-and-custom-fited-options/)。

三维人脑结构和功能的可视化是一个具有深远意义的研究前沿。几乎没有什么进步改变了神经科学和脑成像技术的领域,比如看内部和阅读活人大脑的能力。为了大脑研究的持续进展,有必要在许多抽象层次上整合结构和功能信息。

硬件性能功率一直在上升的速度告诉我们,我们已经能够分析脱氧核糖核酸序列并直观地表示它们。计算机的未来发展预示着医学和其他科学领域将会有更光明的进步。

可视化如何帮助决策?

有多种方式可以直观地表示数据。然而,只有很少的几种方法可以描述数据,使人们能够直观地看到一些东西并观察新的模式。数据可视化并不像看起来那么容易;这是一门艺术,需要大量的实践和经验。(就像画画一样——一个人不可能从第一天就成为大师级的画家,这需要大量的练习。)

人类感知在数据可视化领域发挥着重要作用。一双健康的人眼具有大约 200 度的水平总视场(其中大约 120 度由双眼共享)。大约四分之一的人脑参与视觉处理,这比任何其他感觉都多。在听觉、视觉和嗅觉这三种感官中,人类视觉的感知能力最强,达到了 60%。

有效的可视化帮助我们分析和理解数据。作者斯蒂芬·利特尔(Stephen Light)描述了以下八种定量信息(通过可视化),这些信息可能有助于我们理解或交流一组数据(来源:https://www . Perceptual edge . com/articles/ie/the _ right _ graph . pdf):

  • 时间序列
  • 等级
  • 部分对整体
  • 偏差
  • 频数分布
  • 相互关系
  • 名义比较
  • 地理或地理空间

科学家绘制了人类基因组图谱,这也是为什么我们面临着将知识转化为可视化表示以便更好地理解的挑战的原因之一。换句话说,我们可能必须找到新的方法来直观地呈现人类基因组,这样普通人就不难理解了。

可视化适合哪里?

需要注意的是数据可视化不是科学可视化。科学可视化处理具有固有物理结构的数据,例如流过飞机机翼的空气分子。另一方面,信息可视化处理抽象数据,并帮助解决涉及大型数据集的问题。挑战之一是确保数据是干净的,然后减少维度,从而丢弃不必要的信息。

无论我们在哪里看到知识或数据价值的增加,可视化都可以使用。这可以通过做更多的数据分析和运行算法来确定。数据分析可能从最简单的形式变化到更复杂的形式。

有时候,观察平均值、中位数或总数之外的数据是有价值的,因为这些测量只测量看起来很明显的东西。有时,区域周围的聚合或值隐藏了需要特别关注的有趣细节。一个经典的例子是“安斯科姆四重奏”,它由四个数据集组成,这些数据集具有几乎相同的简单统计属性,但在绘制图表时却显得非常不同。有关这方面的更多信息,可以参考链接:https://en.wikipedia.org/wiki/Anscombe%27s_quartet

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_07.jpg

大多数情况下,非常适合可视化的数据集可以采取不同的形式,但是有些数据集比其他数据集更容易理解。在某些情况下,有必要对它们进行多次分析,以便更好地理解可视化,如上图所示。

一个好的可视化不仅仅是一个人可以看的静态图片,就像博物馆里的展览一样。这是允许我们深入并找到更多关于数据变化的东西。例如,先查看,缩放和过滤,更改某些显示比例的值,并以增量方式查看结果,如本·施内德曼的所述。有时候,在一个显示器上和一个标尺上显示所有东西要困难得多,只有通过经验,人们才能更好地理解这些可视化方法。进一步总结,可视化在组织和理解数据方面都很有用,尤其是当数据丰富的时候。

交互式可视化作为一种新的交流形式正在出现,它允许用户分析信息,以便构建他们自己对数据的新理解。

今天的数据可视化

虽然计算的许多领域旨在用自动化取代人类的判断,但可视化系统是独一无二的,并且被明确设计成不取代人类。事实上,它们旨在让人类积极参与整个过程;为什么会这样?

数据可视化是一门艺术,由数据驱动,但由人类在各种计算工具的帮助下创造。一个艺术家用画笔和颜色等工具和材料画一幅画。同样,另一位艺术家试图借助计算工具创建数据可视化。视觉化可以在美学上令人愉悦,并有助于使事情变得清晰;有时,根据创建它的用户,它可能缺少这些品质中的一个或两个。

如今,有超过 30 种不同的数据可视化表示,每一种都有理由以特定的方式表示数据。随着可视化方法的进步,我们拥有的不仅仅是条形图和饼图。尽管数据可视化有许多好处,但由于缺乏理解,在某些情况下,由于仪表板上的东西杂乱无章,变得过于繁琐,这些好处被削弱了。

呈现数据的方式有很多种,但在大多数情况下,其中只有少数有意义;这将在本章后面的章节中详细解释。在那次讨论之前,让我们来看看一些重要的东西的列表,这些东西可以很好地可视化。

什么是好的可视化?

良好的可视化帮助用户探索和理解数据,提供价值和深刻的见解。它是有效的,视觉上吸引人的,可扩展的,并且容易理解(好的可视化不必太复杂)。可视化是一个中心工具,通过进行研究和分析,使用任何可以回答数据问题的工具来发现数据中的模式和趋势。

有效可视化背后的主要原则是确定您想要表达的主要观点,识别受众的水平和背景,准确地表示数据,然后创建一个清晰的演示文稿,向该受众传达信息。

示例:使用一个小样本数据源创建了以下表示,该数据源显示了 1970-2012 年间获得十个不同学科学位的男女比例(womens-undergrad-degrees.csv和来自【http://www.knapdata.com/python/】mens-undergrad-degrees.csv):

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_08.jpg

http://nces.ed.gov/programs/digest/d11/tables/dt11_290.asp 的完整数据源维护着整套数据。

一个简单的方法是在一个尺度上表示它们,尽管不同学科之间的数字没有关系。让我们分析一下,看看这种表示是否有意义,如果没有意义,那么我们还需要什么?还有其他的表述吗?

首先,关于不同学科的所有数据都显示在一个屏幕上,这是一个很好的比较。然而,如果我们需要获得 2000 年的信息,没有简单的方法。除非有类似于金融股票图表的交互式显示模式,否则没有简单的方法来确定 2000 年多学科授予学位的信息。这些图中另一个令人困惑的部分是百分比加起来并不是 100%。另一方面,一个学科内授予学位的男女比例加起来是 100%;例如,男性和女性在卫生专业学科中获得学位的比例分别为 15.2%和 84.8%。

我们可以通过其他可视化方法来表示这些吗?人们可以为每一年创建气泡图,有一个带有年份选择的交互式可视化,也有一个播放按钮来转换每一年的气泡。

这种可视化更适合我们正在查看的数据。我们还可以使用与原始图相同的滑块,并通过突出显示所选年份的数据使其具有交互性。一个好习惯是用几种不同的方式来可视化数据,看看某个显示是否比另一个更有意义。如果数值范围非常大(例如,从 20 到 200,000),我们可能必须在对数标度上对数值进行标度。

人们可以用 Python 编写一个程序来完成这个气泡图。其他替代语言是使用 D3.js 的 JavaScript 和使用 R-Studio 的 R。留给读者去探索其他的可视化选项。

Google Motion Chart 可以在developers . Google . com/Chart/interactive/docs/gallery/Motion Chart 进行可视化来表示这个交互图表?csw = 1 #示例显示了一个类似于这个气泡图的工作示例。这里显示的气泡图只有三年,但你可以为所有年份创建另一个气泡图。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_09.jpg

数据可视化是在数据分析之后必须使用的过程。我们之前也注意到,数据转换、数据分析、数据可视化都做了几次;为什么会这样?我们都知道那句名言,知识就是有正确的答案,智慧就是问正确的问题。数据分析有助于我们更好地理解数据,从而能够回答关于数据的问题。然而,当数据以几种不同的方式被可视化表示时,一些新的问题出现了,这也是为什么会有重复的分析和可视化过程的原因之一。

数据可视化是数据探索的主要工具之一,几乎总是先于或启发数据分析。可视化显示数据的工具很多,但做分析的工具就少了。像 Julia、R 和 Python 这样的编程语言在执行数据分析方面排名较高,但是在可视化方面,基于 JavaScript 的 D3.js 在生成交互式数据可视化方面具有更大的潜力。

在 R 和 Python 之间,R 是一门比较难学的语言。另一方面,Python 要容易得多。这一点在 Quora 上也有争论;人们可以在互联网上查看这一点的有效性。如今,Python 中有许多用于统计建模和数据分析的工具,因此,它是数据科学的一个有吸引力的选择。

可视化图

我们进行可视化的原因之一是为了确认我们对数据的了解。然而,如果数据不被很好地理解,你可能不会对数据提出正确的问题。

创建可视化时,第一步是明确要回答的问题。换句话说,可视化将如何帮助?接下来还有另一个挑战——知道正确的绘图方法。一些可视化方法如下:

  • 条形图和饼图
  • 箱线图
  • 泡泡图
  • 柱状图
  • 核密度估计 ( KDE )图
  • 线和曲面图
  • 网络图
  • 散点图
  • 树形图
  • 小提琴绘图

在确定可视化应该传达的信息的过程中,查看以下问题是有意义的:

  • 我们在处理多少变量,我们试图描绘什么?
  • x 轴和 y 轴是指什么?(对于 3D, z 轴也是如此。)
  • 数据大小标准化了吗?数据点的大小有什么意义吗?
  • 我们是否使用了正确的颜色选择?
  • 对于时间序列数据,我们是试图识别趋势还是相关性?

如果变量太多,在不同的数据子集上绘制同一个图的多个实例是有意义的。这种技术被称为格子格子绘图。它允许查看者快速提取大量关于复杂数据的信息。

考虑一个学生数据子集,其中包含关于(gender, sleep, tv, exercise, computer, gpa)(height, momheight, dadheight)的不同寻常的混合信息。computertvsleepexercise的单位是小时,height单位是英寸,gpa单位是 4.0。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_10.jpg

前面的数据是一个变量比通常更多的例子,因此,做一个网格图来可视化和查看这些变量之间的关系是有意义的。

我们执行可视化的原因之一是确认我们对数据的了解。然而,如果数据没有被很好地理解,人们可能不会对它提出正确的问题。

由于数据中只有两种性别,因此有 10 种可能的变量组合(sleeptv)、(sleepexercise)、(sleepcomputer)、(sleepgpa)、(tvexercise)、(tvcomputer)、(tvgpa)、(exercisecomputer)、(exercisegpa)和(computer另外两个,(heightmomheight)和(heightdadheight)为第二套。以下是除(sleeptv)、(tvexercise以外的所有组合。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_11.jpg

我们的目标是找到什么样的变量组合可以用来使这些数据变得有意义,或者看看这些变量是否有任何有意义的影响。因为数据是关于学生的,所以gpa可能是驱动其他变量相关性的关键变量。上图描绘的散点图显示,更多的女学生比男学生拥有更高的gpa,更多的男学生花更多的时间在电脑上,并获得类似的gpa值范围。虽然这里显示了所有散点图,但目的是找出哪些数据起着更重要的作用,以及我们能从这些数据中得出什么意义。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_12.jpg

更高的蓝点数量(对于 y 轴上的gpa来说)表明有更多的女生拥有更高的gpa(该数据是从 UCSD 收集的)。

数据可从http://www.knapdata.com/python/ucdavis.csv下载。

可以使用 seaborn包,用很少的代码行显示散点图,下面的例子显示了与学生花在电脑上的时间相比,gpa沿 x 轴的散点图:

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

students = pd.read_csv("/Users/kvenkatr/Downloads/ucdavis.csv")

g = sns.FacetGrid(students, hue="gender", palette="Set1", size=6)
g.map(plt.scatter, "gpa", "computer", s=250, linewidth=0.65,
  edgecolor="white")

g.add_legend()

型式

下载示例代码

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

这些图是使用matplotlibpandasseaborn库包生成的。Seaborn是基于matplotlib的统计数据可视化库,由斯坦福大学的 Michael Waskom 创建。关于这些库的更多细节将在后面的章节中讨论。

Seaborn库中有很多有用的类。特别是当我们需要在数据子集内分别可视化一个变量的分布或多个变量之间的关系时,FacetGrid类就派上了用场。FacetGrid可以绘制三维,即行、列和色调。这些库包及其功能将在后面的章节中描述。

创建可视化时,第一步是明确要回答的问题。换句话说,可视化将如何帮助?另一个挑战是选择正确的绘图方法。

条形图和饼图

我们什么时候选择条形图和饼图?它们是最古老的可视化方法,饼图最适合用来比较整体的各个部分。然而,条形图可以比较不同组之间的事物来显示模式。

条形图、直方图和饼图帮助我们比较不同的数据样本,对它们进行分类,并确定数据值在该样本中的分布。条形图有几种不同的样式,从单一的、多重的和堆叠的。

条形图

当你有很好地分成不同类别的数字数据时,条形图特别有效,因此你可以快速看到数据中的趋势。

条形图在跨类别比较数据时非常有用。一些值得注意的例子包括:

  • 不同尺寸牛仔裤的体积
  • 过去二十年世界人口变化
  • 按部门划分的支出百分比

除了这一点,还要考虑以下几点:

  • 为条形图添加颜色以获得更大的影响力:用条形图展示收入表现具有信息性,但添加颜色以揭示利润会增加视觉洞察力。然而,如果有太多的条,颜色可能会使图表看起来笨拙。
  • 在一个仪表盘上包含多个条形图:这有助于查看者快速比较相关信息,而不是翻阅一堆电子表格或幻灯片来回答问题。
  • 在一个轴的两侧放置条形:沿着一个连续的轴绘制正负数据点是发现趋势的有效方法。
  • 使用堆叠条形图或并排条形图:将相关数据显示在彼此的顶部或旁边,可以让您的分析更深入,同时解决多个问题。

这些图可以用不到 12 行 Python 代码来实现,更多的例子将在后面的章节中讨论。

对于条形图,每列代表一个由特定类别定义的组;对于直方图,每一列代表一个由定量变量定义的组。对于条形图, x 轴没有低端或高端值,因为 x 轴上的标签是分类的,而不是定量的。另一方面,在柱状图中,会有一系列的值。下图显示了 2000 年至 2009 年美国奥斯卡获奖者和提名者的统计数据:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_15.jpg

下面的 Python 代码使用matplotlib显示电影中一个小数据样本的条形图(这可能不一定是一个真实的例子,但给出了一个绘图和比较的想法):

[5]: import numpy as np
     import matplotlib.pyplot as plt

     N = 7
     winnersplot = (142.6, 125.3, 62.0, 81.0, 145.6, 319.4, 178.1)

     ind = np.arange(N)  # the x locations for the groups
     width = 0.35        # the width of the bars

     fig, ax = plt.subplots()
     winners = ax.bar(ind, winnersplot, width, color='#ffad00')

     nomineesplot = (109.4, 94.8, 60.7, 44.6, 116.9, 262.5, 102.0)
     nominees = ax.bar(ind+width, nomineesplot, width,
       color='#9b3c38')

     # add some text for labels, title and axes ticks
     ax.set_xticks(ind+width)
     ax.set_xticklabels( ('Best Picture', 'Director', 'Best Actor',
       'Best Actress','Editing', 'Visual Effects', 'Cinematography'))

     ax.legend( (winners[0], nominees[0]), ('Academy Award Winners',  
       'Academy Award Nominees') )

     def autolabel(rects):
       # attach some text labels
       for rect in rects:
         height = rect.get_height()
         hcap = "$"+str(height)+"M"
         ax.text(rect.get_x()+rect.get_width()/2., height, hcap,
           ha='center', va='bottom', rotation="vertical")

     autolabel(winners)
     autolabel(nominees)

     plt.show()

饼图

说到饼状图,真的要考虑回答“各部分组成有意义的整体了吗?”以及“你有足够的房产来用圆形视图表示它们吗?”。有一些批评者在饼状图上崩溃了,其中一个主要原因是,当有许多类别时,很难得到比例并比较这些类别来获得任何洞察力。(来源:https://www . quora . com/How-and-why-is-pie-charts-被数据可视化专家认为是邪恶的)。

饼图对于显示单个空间或整个地图的比例非常有用。一些值得注意的例子包括:

  • 调查的响应类别
  • 特定技术的前五大公司市场份额(在这种情况下,人们可以很快知道哪些公司在市场中占有主要份额)

除此之外,请考虑以下几点:

  • 将饼图楔形限制为八个:如果要表示的比例超过八个,考虑一个条形图。由于房地产有限,很难有意义地表现和解释这些作品。
  • 在地图上叠加饼图:饼图可以更容易地在地图上展开并突出地理趋势。(这里的楔形也应该是有限的。)

考虑以下简单饼状图的代码,比较几个学科的录取人数是如何分布的:

[6]: import matplotlib.pyplot as plt

     labels = 'Computer Science', 'Foreign Languages', 
       'Analytical Chemistry', 'Education', 'Humanities', 
       'Physics', 'Biology', 'Math and Statistics', 'Engineering'

     sizes = [21, 4, 7, 7, 8, 9, 10, 15, 19]
     colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral',
       'red', 'purple', '#f280de', 'orange', 'green']
     explode = (0,0,0,0,0,0,0,0,0.1)
     plt.pie(sizes, explode=explode, labels=labels, 
       autopct='%1.1f%%', colors=colors)
     plt.axis('equal')
     plt.show()

下面的饼图示例显示了一些选定的顶级研究领域的大学录取人数:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_17.jpg

方框图

箱线图也被称为“盒须图”。这是一种基于五个数字汇总显示数据分布的标准化方式:最小值、第一个四分位数、中值、第三个四分位数和最大值。下图显示了如何阅读箱线图:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_18.jpg

箱线图是以图形方式检查一组或多组数据的快速方法,它们一次只占用较少的空间来定义五个摘要。对于这种用法,我们可以想到的一个例子是:如果两个或两个以上的班级进行同样的考试,那么一个方框图可以告诉我们一个班级的大多数学生什么时候比另一个班级的大多数学生做得更好。另一个例子是,如果有更多的人吃汉堡,中位数会更高,或者顶部的胡须会比底部的长。在这种情况下,它可以很好地概括数据分布。

在我们试图理解何时使用方框图之前,这里有一个需要理解的定义。数据值集合中的异常值是与其他值相距异常距离的观察值。

箱线图在显示一组数据的分布时最有用。一些值得注意的例子如下:

  • 识别数据中的异常值
  • 确定数据是如何向两端倾斜的

除此之外,请考虑以下几点:

  • 隐藏框内的点:关注异常值
  • 跨分布比较:箱线图有利于快速比较数据集之间的分布

散点图和气泡图

散点图是一种显示两个变量的可视化方法。它们相交点的模式可以图形化地显示关系模式。散点图是在同一组个体上测量的两个变量之间关系的可视化。另一方面,气泡图显示三维数据。每个实体及其相关数据的三元组 (a,b,c) 被绘制成一个圆盘,通过 xy 位置表示这三个变量中的两个,第三个显示测量的显著性量。

散点图

数据通常显示为点的集合,并经常用于绘制各种相关性。例如,当一组数据值的增加也会增加另一组数据值时,就会发现正相关。前面显示的学生记录数据有各种散点图,显示了它们之间的相关性。

在下面的例子中,我们将学生的身高与他们母亲的身高进行比较,以确定是否存在正相关。数据可从http://www.knapdata.com/python/ucdavis.csv下载。

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
students = pd.read_csv("/Users/Macbook/python/data/ucdavis.csv")
g = sns.FacetGrid(students, palette="Set1", size=7)
g.map(plt.scatter, "momheight", "height", s=140, linewidth=.7, edgecolor="#ffad40", color="#ff8000")
g.set_axis_labels("Mothers Height", "Students Height")

我们使用seaborn包演示了这个例子,但是也可以只使用matplotlib来完成,这将在下一节中显示。前面代码的散点图如下所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_19.jpg

散点图对于研究两个不同变量之间的关系非常有用。一些值得注意的例子如下:

  • 男性与女性不同年龄患皮肤癌的可能性
  • 智商测试分数与平均成绩的相关性

除此之外,请考虑以下几点:

  • 添加趋势线或最佳拟合线(如果关系是线性的):添加趋势线可以显示数据值之间的相关性
  • 使用信息性标记类型:如果要透露的故事是关于可以通过相关形状和颜色进行视觉增强的数据,则应使用信息性标记类型

气泡图

以下示例显示了如何使用彩色地图作为第三个维度,该维度可以指示销售量或任何适当的推动利润的指标:

 [7]: import numpy as np
     import pandas as pd
     import seaborn as sns
     import matplotlib.pyplot as plt

     sns.set(style="whitegrid")
     mov = pd.read_csv("/Users/MacBook/python/data/2014_gross.csv")

     x=mov.ProductionCost
     y=mov.WorldGross
     z=mov.WorldGross

     cm = plt.cm.get_cmap('RdYlBu')
     fig, ax = plt.subplots(figsize=(12,10))

     sc = ax.scatter(x,y,s=z*3, c=z,cmap=cm, linewidth=0.2, alpha=0.5)
     ax.grid()
     fig.colorbar(sc)

     ax.set_xlabel('Production Cost', fontsize=14)
     ax.set_ylabel('Gross Profits', fontsize=14)

     plt.show()
..-.

以下散点图是使用颜色映射的示例的结果:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_25.jpg

气泡图对于比较三个数值数据维度中的数据之间的关系非常有用: x 轴数据、 y 轴数据以及由气泡大小表示的数据。气泡图类似于 XY 散点图,不同的是散点图上的每个点都有一个与之相关的附加数据值,该值由以 XY 点为中心的圆或“气泡”的大小来表示。此处显示了气泡图的另一个示例(没有 python 代码,以展示不同的风格):

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_22.jpg

在前面的显示中,气泡图显示了不同大洲的预期寿命人均国内生产总值

气泡图最有用的是显示沿两个轴的数据浓度,第三个数据元素是测量的显著性值。一些值得注意的例子如下:

  • 电影的制作成本和总利润,以及如示例中所示的按加热比例衡量的重要性

除此之外,请考虑以下几点:

  • 添加颜色和形状意义:通过改变大小和颜色,可以将数据点转化为清晰回答某些问题的可视化
  • 使其具有交互性:如果数据点太多,气泡图可能会变得混乱,所以将它们按时间轴或类别分组,并以交互方式可视化

KDE 图

核密度 估计 ( KDE )是一种非参数方法,用于估计概率密度函数及其在观测数据点上的平均值,以创建平滑近似。它们与直方图密切相关,但有时可以被称为核的概念赋予平滑性或连续性。

概率密度函数 ( PDF )的核心是 PDF 的形式,其中省略了不是域中任何变量的函数的任何因素。我们将只关注它的可视化方面;关于更多的理论,可以参考统计学书籍。

有几个不同的 Python 库可以用来完成不同深度和级别的 KDE 绘图,包括matplotlibScipyscikit-learnseaborn。以下是 KDE 绘图的两个例子。在后面的章节中,将会有更多的例子,只要有必要,展示 KDE 绘图的各种其他方式。

在下面的示例中,我们使用大小为 250 的随机数据集和seaborn包,用几行简单的线显示分布图:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_23.jpg

可以使用seaborn显示数据图的简单分布,这里使用使用numpy.random生成的随机样本进行演示:

from numpy.random import randn
import matplotlib as mpl
import seaborn as sns
import matplotlib.pyplot as plt

sns.set_palette("hls")
mpl.rc("figure", figsize=(10,6))
data = randn(250)
plt.title("KDE Demonstration using Seaborn and Matplotlib", fontsize=20)
sns.distplot(data, color='#ff8000')

在第二个例子中,我们使用 SciPy 和 NumPy 演示了概率密度函数。首先我们使用 SciPy 中的norm()来创建正态分布样本,然后使用 NumPy 中的hstack()来水平堆叠它们,并应用 SciPy 中的gaussian_kde()

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_01_24.jpg

前面的图是使用 SciPy 和 NumPy 的 KDE 图的结果,如下所示:

from scipy.stats.kde import gaussian_kde
from scipy.stats import norm
from numpy import linspace, hstack
from pylab import plot, show, hist

sample1 = norm.rvs(loc=-1.0, scale=1, size=320)
sample2 = norm.rvs(loc=2.0, scale=0.6, size=320)
sample = hstack([sample1, sample2])
probDensityFun = gaussian_kde(sample)
plt.title("KDE Demonstration using Scipy and Numpy", fontsize=20)
x = linspace(-5,5,200)
plot(x, probDensityFun(x), 'r')
hist(sample, normed=1, alpha=0.45, color='purple')
show()

其他可视化方法如线面图、网络图、树状图、热图、雷达图或蜘蛛图、小提琴图将在接下来的几章中讨论。

总结

到目前为止,所展示的例子只是为了让你知道在做演示之前应该如何思考和计划。最重要的阶段是数据熟悉和可视化的准备过程。一个人能否首先获得数据或塑造理想的故事,主要取决于尝试的结果。这就像是“先有鸡还是先有蛋”的情况——数据是第一位还是焦点?最初,可能不清楚人们可能需要什么数据,但在大多数情况下,经过几次迭代,只要数据中没有错误,事情就会变得清楚。

通过进行一些清理或缩小维度(如果需要)来转换数据质量,并填补空白(如果有)。除非数据是好的,否则人们在视觉上展示数据的努力将会白费。在实现了对数据的合理理解之后,确定什么样的可视化可能是合适的是有意义的。在某些情况下,最好以几种不同的方式显示它,以便清楚地看到故事。

二、数据分析和可视化

大多数可视化故事都是从某个问题开始的,这个问题是针对正在探索或收集数据的主题。这个问题包含了故事的前提,并把我们引向数据对故事绘图进行考察的点。这样的数据考察以一个问题开始,例如,【2014 年报告了多少埃博拉死亡病例?由一群人通过相互协作来实现。数据传播者的角色应该是创造一种信息体验,改变受众对其故事的看法。

故事的关键部分涉及将可视化置于有意义的上下文中的过程。上下文提供了回答以下问题的知识:

  • 有足够的数据吗?
  • 这种数据存在的时间范围内吗?
  • 全球哪些相关事件会影响这些数据?

重申一下,理解数据并确定试图回答的问题的背景是很重要的。有时,人们甚至在问题最终确定之前就开始挖掘数据,在这种情况下,一旦对数据有了更好的理解,你可能会对问题有一个更好或更清晰的版本。

这个过程从输入数据开始,假设人们有办法从某个来源获取、解析和收集所需的信息。在某些情况下,最好将收集的信息可视化以消除噪声,而在其他一些情况下,可以在应用可视化方法之前过滤和分析数据。在本章中,我们将学习数据探索的不同方式,以进一步将它们用于可视化方法。我们还将按照以下顺序讲述一些有趣的数据故事和相关概念:

  • 获取、解析和过滤数据以检测异常值和异常值、数据挖掘和提炼、可视化表示和交互
  • 用数据创造有趣的故事
  • 可视化的感知、呈现方法和最佳实践
  • 交互式可视化—探索事件侦听器和布局

为什么可视化需要规划?

可视化的整个过程涉及不同技能集和领域专长的人。数据辩论者勤奋地收集数据并进行分析。数学家和统计学家理解视觉设计原则,并使用这些原则交流他们的数据。设计师或艺术家(在某些情况下,是前端开发人员)拥有可视化所需的技能,而业务分析师则关注客户行为模式、异常值或突然出现的异常趋势。但是,它总是从获取或收集数据开始,并遵循以下步骤:

  • 从外部来源、网站或磁盘上的文件获取或收集数据
  • 解析和过滤数据使用编程方法解析、清理和减少数据
  • 分析细化去除噪声和不必要的维度,找到模式
  • 表示和交互以更易访问和理解的方式呈现数据

这个过程遵循的程度因不同的问题而异,在某些情况下,所做的分析比数据过滤更多。如前一章所述,在某些情况下,分析和可视化是迭代完成的。换句话说,这些步骤的分布并不总是可预测和一致的。

埃博拉的例子

为了说明上一节提到的步骤,以及它们如何导致一个可以理解的可视化,让我们考虑一下我们之前的问题,即【2014 年报告了多少埃博拉死亡病例?这个特殊的问题引出了非常具体的数据,通常由世界卫生组织(http://www.who.int/en/)或人道主义数据交换(https://hdx.rwlabs.org)维护。这一数据的原始来源是世界卫生组织 ( 世卫组织),但人道主义数据交换 ( HDX )是贡献者。然而,请注意,我们将在一个地方获得所有数据,以及本书的 Python 源代码示例。

这些数据包含有关埃博拉病毒在几内亚、利比里亚、马里、尼日利亚、塞内加尔、塞拉利昂、西班牙、联合王国和美利坚合众国传播的信息。

该信息的投稿人网址为https://data.hdx.rwlabs.org/dataset/ebola-cases-2014/

逗号分隔值 ( CSV )格式的数据文件内容包括指标、国家名称、日期以及死亡人数或感染人数,具体取决于指标所述。共有 36 个不同的指标,前 10 名如下(其他可在附录前进探索可视化查看):

  • 过去 7 天可能出现的埃博拉病例数
  • 过去 21 天可能的埃博拉死亡人数
  • 过去 21 天疑似埃博拉病例数
  • 过去 7 天疑似埃博拉病例数
  • 过去 21 天疑似埃博拉死亡人数
  • 过去 21 天确诊的埃博拉病例比例
  • 过去 7 天确诊的埃博拉病例比例
  • 过去 21 天确诊的埃博拉死亡比例
  • 过去 7 天疑似埃博拉病例的比例
  • 过去 21 天疑似埃博拉死亡的比例

此时,看完指标清单,我们最初的单一问题,即【2014 年报告了多少埃博拉死亡病例?可以改为多组问题。为了简单起见,我们将重点放在这个问题上,看看如何进一步分析数据,并提出可视化方法。首先,让我们看一下读取数据文件的方法。

在任何编程语言中,读取文件的方式都不止一种,其中一种选择就是使用 Python 的 pandas 库,该库性能高,使用数据结构和数据分析工具。另一种选择是使用 csv 库读取 csv 格式的数据文件。它们之间有什么区别?他们两个都能做这项工作。在熊猫的旧版本中,大数据的内存映射存在问题(也就是说,如果 CSV 格式的数据文件非常大),但现在已经进行了优化。让我们从下面的代码开始:

[1]:  with open('("/Users/kvenkatr/python/ebola.csv ', 'rt') as f: 
        filtereddata = [row for row in csv.reader(f) if row[3] != "0.0" and 
        row[3] != "0" and "deaths" in row[0]]

[2]:    len(filtereddata)
Out[2]: 1194

前面的过滤也可以使用熊猫来执行,如下所示:

import pandas as pd
eboladata = pd.read_csv("/Users/kvenkatr/python/ebola.csv")
filtered = eboladata[eboladata["value"]>0]
filtered = filtered[filtered["Indicator"].str.contains("deaths")]
len(filtered)

数据可从http://www.knapdata.com/python/ebola.csv下载。下一步是以读取文本 ( rt )格式打开数据文件。它读取每一行,并进一步过滤死亡人数为零的行,因为指示器字符串中有单词deaths。这是一个非常简单的过滤器,用于忽略没有报告病例或死亡的数据。仅打印过滤数据的前五行会显示以下内容:

[3]:  filtereddata[:5]
Out[3]: 
[['Cumulative number of confirmed Ebola deaths', 'Guinea','2014-08-29', '287.0'],
 ['Cumulative number of probable Ebola deaths','Guinea','2014-08-29',
  '141.0'],
 ['Cumulative number of suspected Ebola deaths','Guinea','2014-08-29',
  '2.0'],
 ['Cumulative number of confirmed, probable and suspected Ebola deaths',
  'Guinea','2014-08-29','430.0'],
 ['Cumulative number of confirmed Ebola deaths',
  'Liberia','2014-08-29','225.0']]

如果每个国家报告的埃博拉病例的所有数据都要分开,我们如何进一步过滤这些数据?我们可以在国家栏上对它们进行分类。该数据文件共有四列:indicatorcountrydatenumber value,如下图所示:

[4]:  import operator
      sorteddata = sort(filtereddata, key=operator.itemgetter(1))
[5]:  sorteddata[:5]
Out[5]: 
[['Cumulative number of confirmed Ebola deaths', 'Guinea','2014-08-29', '287.0'],
 ['Cumulative number of probable Ebola deaths','Guinea','2014-08-29',
  '141.0'],
 ['Cumulative number of suspected Ebola deaths','Guinea','2014-08-29',
  '2.0'],
 ['Cumulative number of confirmed, probable and suspected Ebola deaths',
  'Guinea','2014-08-29','430.0'],
 ['Number of confirmed Ebola deaths in the last 21 days', 'Guinea',
  '2014-08-29','8.0']]

在查看了目前为止的数据后,有两个指标似乎与我们开始这一数据考察的背景有关:

  • 累计确诊埃博拉死亡人数
  • 累计确诊、可能和疑似埃博拉死亡人数

通过多次应用可视化,我们还注意到,在几个国家中,几内亚、利比里亚和塞拉利昂的确诊死亡人数多于其他国家。我们现在来看看这三个国家的死亡报告是如何绘制的:

import matplotlib.pyplot as plt  
import csv 
import operator 
import datetime as dt  

with open('/Users/kvenkatr/python/ebola.csv', 'rt') as f: 
  filtereddata = [row for row in csv.reader(f) if row[3] != "0.0" and 
  row[3] != "0" and "deaths" in row[0]] 

sorteddata = sorted(filtereddata, key=operator.itemgetter(1))  
guineadata  = [row for row in sorteddata if row[1] == "Guinea" and 
  row[0] == "Cumulative number of confirmed Ebola deaths"] 
sierradata  = [row for row in sorteddata if row[1] == "Sierra Leone" and 
  row[0] == "Cumulative number of confirmed Ebola deaths"] 
liberiadata = [row for row in sorteddata if row[1] == "Liberia" and 
  row[0] == "Cumulative number of confirmed Ebola deaths"] 

g_x = [dt.datetime.strptime(row[2], '%Y-%m-%d').date() for 
  row in guineadata] 
g_y = [row[3] for row in guineadata] 

s_x = [dt.datetime.strptime(row[2], '%Y-%m-%d').date() for 
  row in sierradata] 
s_y = [row[3] for row in sierradata] 

l_x = [dt.datetime.strptime(row[2], '%Y-%m-%d').date() for
  row in liberiadata] 
l_y = [row[3] for row in liberiadata] 

plt.figure(figsize=(10,10))
plt.plot(g_x,g_y, color='red', linewidth=2, label="Guinea") 
plt.plot(s_x,s_y, color='orange', linewidth=2, label="Sierra Leone")
plt.plot(l_x,l_y, color='blue', linewidth=2, label="Liberia")
plt.xlabel('Date', fontsize=18)
plt.ylabel('Number of Ebola Deaths', fontsize=18)
plt.title("Confirmed Ebola Deaths", fontsize=20)
plt.legend(loc=2)
plt.show()

结果将会是如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_01.jpg

我们可以为另一个指标构建一个类似的图,即累计确诊、疑似和疑似埃博拉死亡人数。(这可能不是最好的方法,但我们可以纳入更多国家的数据,并绘制出类似的结果。)

import matplotlib.pyplot as plt  
import csv 
import operator 
import datetime as dt  

with open('/Users/kvenkatr/python/ebola.csv', 'rt') as f: 
  filtereddata = [row for row in csv.reader(f) if row[3] != "0.0" and 
  row[3] != "0" and "deaths" in row[0]] 

sorteddata = sorted(filtereddata, key=operator.itemgetter(1))  

guineadata  = [row for row in sorteddata if row[1] == "Guinea" and 
  row[0] == "Cumulative number of confirmed, probable and suspected Ebola deaths"] 
sierradata  = [row for row in sorteddata if row[1] == "Sierra Leone" and 
  row[0] == " Cumulative number of confirmed, probable and suspected Ebola deaths "] 
liberiadata = [row for row in sorteddata if row[1] == "Liberia" and 
  row[0] == " Cumulative number of confirmed, probable and suspected Ebola deaths "] 

g_x = [dt.datetime.strptime(row[2], '%Y-%m-%d').date() for 
  row in guineadata] 
g_y = [row[3] for row in guineadata] 

s_x = [dt.datetime.strptime(row[2], '%Y-%m-%d').date() for 
  row in sierradata] 
s_y = [row[3] for row in sierradata] 

l_x = [dt.datetime.strptime(row[2], '%Y-%m-%d').date() for
  row in liberiadata] 
l_y = [row[3] for row in liberiadata] 

plt.figure(figsize=(10,10))
plt.plot(g_x,g_y, color='red', linewidth=2, label="Guinea") 
plt.plot(s_x,s_y, color='orange', linewidth=2, label="Sierra Leone")
plt.plot(l_x,l_y, color='blue', linewidth=2, label="Liberia")
plt.xlabel('Date', fontsize=18)
plt.ylabel('Number of Ebola Deaths', fontsize=18)
plt.title("Probable and Suspected Ebola Deaths", fontsize=20)
plt.legend(loc=2)
plt.show()

绘图应该是这样的:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_02.jpg

一个体育的例子

为了说明另一个例子,以及一个特定的可视化方法如何比另一个更好地工作,让我们考虑一个不同的问题:*截至 2015 年 2 月,美国足坛四分卫的前五大触球记录是什么?*这一数据的原始来源是美国橄榄球联盟的莱恩·道森和美国劳联统计。(数据来源:http://www . pro-football-reference . com/players/D/dawsle00 . htm。)

该数据包含了前 22 名四分卫的信息:培顿·曼宁、布雷特·法弗、丹·马里诺、德鲁·布里斯、汤姆·布拉迪、弗兰克·塔肯顿、约翰·埃尔韦、沃伦·穆恩、约翰·尤尼塔斯、文尼泰斯塔维尔达、乔·蒙塔纳、戴夫·Krieg、埃利·曼宁、桑尼·尤根森、丹·福茨、菲利普·里弗斯、本·罗瑟里斯伯格、德鲁·布莱索、布默·埃西森、约翰·哈德尔、蒂特尔和托尼·罗莫:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_05.jpg

在我们想到可视化方法之前,需要做一点分析。这些四分卫在不同的时期打过球。例如,布雷特·法弗从 1991 年到 2010 年,丹·马里诺从 1983 年到 1999 年。挑战在于,如果我们使用条形图或气泡图,它们只会在一个维度上显示结果。

第一步是解析 CSV 文件,这里有几个选项。我们可以使用熊猫read_csv功能,也可以使用csv模块,该模块有一些方便的功能,例如DictReader:

import csv 
import matplotlib.pyplot as plt

# csv has Name, Year, Age, Cmp, Att, Yds, TD, Teams
with open('/Users/MacBook/java/qb_data.csv') as csvfile: 
   reader = csv.DictReader(csvfile) 
   for row in reader:
     name  = row['Name']
     tds = row['TD']

四分卫数据是从本节前面列出的来源下载的;过滤后的数据也可在http://www.knapdata.com/python/qb_data.csv获得。csv模块包括将行作为字典使用的类,以便可以命名字段。DictReaderDictWriter类将这些行翻译成字典,而不是列表。字典的关键字可以是传入的或从输入的第一行推断的(该行包含标题)。通过DictReader读取 CSV 文件的内容,其中列输入值被视为字符串:

#ways to call DictReader

# if fieldnames are Name, Year, Age, Cmp, Att, Yds, TD, Teams
fieldnames = ['Name', 'Year', 'Age', 'Cmp', 'Att', 'Yds', 'TD', 'Teams'] 

reader = csv.DictReader(csvfile, fieldNames=fieldnames)
# If csv file has first row as Name, Year, Cmp, Att, Yds, TD, Teams
#   we don't need to define fieldnames, the reader automatically recognizes
#   them. 

为了将一些值转换成数字,我们可能需要一个转换并返回数值的函数。我们还在prepare.py中增加了getcolors()``num()等功能,可以在以后的例子中使用:

# num(s) and getcolors() functions 
def num(s):
  try:
    return int(s)
  except ValueError:
    return 0  

def getcolors():
  colors = [(31, 119, 180), (255,0,0), (0,255,0), (148, 103, 189), (140, 86, 75), (218, 73, 174), (127, 127, 127), (140,140,26), (23, 190, 207), (65,200,100), (200, 65,100), (125,255,32), (32,32,198), (255,191,201), (172,191,201), (0,128,0), (244,130,150), (255, 127, 14), (128,128,0), (10,10,10), (44, 160, 44), (214, 39, 40), (206,206,216)]

  for i in range(len(colors)):
    r, g, b = colors[i]
    colors[i] = (r / 255\. , g / 255\. , b / 255.)
  return colors

直观地表示结果

根据输入数据中的字段名称,对于每个四分卫,他们的触地统计数据或传球码统计数据可以绘制在时间线上。现在我们知道要画什么了,下一步就是弄清楚怎么画。

简单的 X-Y 带场(年,触地)或(触地,年)的绘图应该是一个好的开始。然而,到目前为止,在这个输入数据文件中有 252 个四分卫,其中大多数是不相关的。因此,用不同的颜色展示它们是没有意义的。(为什么?我们有 252 种不同的颜色吗?)我们可以尝试绘制前 7 名或前 10 名的结果,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_06.jpg

下面的 Python 程序演示了如何使用matplotlib根据触地次数显示前 10 名四分卫,该程序产生的图是上图所示的:

import csv
import matplotlib.pyplot as plt

# The following functions can be in separate file 
#  (If it does, you need to import) 
def num(s):
  try:
    return int(s)
  except ValueError:
    return 0  

def getcolors():
  colors = [(31, 119, 180), (255,0,0), (0,255,0), (148, 103, 189), (140, 86, 75), (218, 73, 174), (127, 127, 127), (140,140,26), (23, 190, 207), (65,200,100), (200, 65,100), (125,255,32), (32,32,198), (255,191,201), (172,191,201), (0,128,0), (244,130,150), (255, 127, 14), (128,128,0), (10,10,10), (44, 160, 44), (214, 39, 40), (206,206,216)]

  for i in range(len(colors)):
    r, g, b = colors[i]
    colors[i] = (r / 255\. , g / 255\. , b / 255.)
  return colors

def getQbNames():
  qbnames = ['Peyton Manning']
  name=''
  i=0
  with open('/Users/MacBook/java/qb_data.csv') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
      if ( row['Name'] != name and qbnames[i] != row['Name']):
        qbnames.append(row['Name'])
        i = i+1
  return qbnames

def readQbdata():
  resultdata = []
  with open('/Users/MacBook/java/qb_data.csv') as csvfile:
    reader = csv.DictReader(csvfile)
    resultdata = [row for row in reader]
  return resultdata

fdata=[]
prevysum=0

#    -- functions End -- 

qbnames = getQbNames()
fdata = readQbdata()

i=0
rank=0
prevysum=0
lastyr=0
highrank=244
colorsdata = getcolors() 

fig = plt.figure(figsize=(15,13))
ax=fig.add_subplot(111,axisbg='white')

# limits for TD
plt.ylim(10, 744) 
plt.xlim(1940, 2021)

colindex=0
lastage=20

for qbn in qbnames:
  x=[]
  y=[]
  prevysum=0
  for row in fdata: 
    if ( row['Name'] == qbn and row['Year'] != 'Career'):
      yrval = num(row['Year'])
      lastage = num(row['Age'])
      prevysum += num(row['TD'])
      lastyr = yrval
      x += [yrval]
      y += [prevysum]

  if ( rank > highrank):
    plt.plot(x,y, color=colorsdata[colindex], label=qbn, linewidth=2.5)
    plt.legend(loc=0, prop={'size':10}) 
    colindex = (colindex+1)%22
    plt.text(lastyr-1, prevysum+2, qbn+"("+str(prevysum)+"):" +str(lastage), fontsize=9)

  else:
    plt.plot(x,y, color=colorsdata[22], linewidth=1.5) 
    rank = rank +1 
plt.xlabel('Year', fontsize=18)
plt.ylabel('Cumulative Touch Downs', fontsize=18)
plt.title("Cumulative Touch Downs by Quarter Backs", fontsize=20)
plt.show() 

当绘图( X,Y )切换到( Y,X )时,有足够的空间显示四分卫的名字。在前面的代码片段中,我们可能需要进行以下更改:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_07.jpg

如果我们翻转 xy 轴,那么就有更多的空间来显示四分卫的名字和总触地得分,如前面的图所示。要做到这一点,可能需要切换 xy ,让标签文字按照新的 xy 轴正确定位。

plt.xlim(10, 744)  
plt.ylim(1940, 2021)

# remaining code all un-changed except

y += [num(row['Year'])]
x += [prevysum]

# Don't forget to switch the x,y co-ordinates of text display

plt.text(prevysum+2, lastyr-1, qbn+"("+str(prevysum)+"):" str(lastage), fontsize=9)

乍一看,我们只能分辨出职业生涯达阵得分数领先的四分卫(截至 2014-2015 足球赛季)。基于这种可视化,您可以进一步尝试分析和理解我们还可以从这些数据中推断出什么。这个问题的答案基于以下问题的答案:

  • 哪个四分卫在他们的职业生涯中打得最久?
  • 今天有谁能超越培顿·曼宁的触地得分记录吗?

在我们从输入文件中读取的字段中,Age恰好是我们拥有的字段值之一。有许多方法可以试验Age的起始值,用于绘制AgeTouchdown的统计数据。要回答第一个问题,我们必须跟踪Age而不是Year。以下代码片段可以在单独的函数中使用(如果必须经常使用的话),也可以包含在主脚本中:

maxage = 30

with open('/Users/MacBook/java/qb_data.csv') as csvfile:
  reader = csv.DictReader(csvfile)
    for row in reader:
      if ( num(row['Age']) > maxage ):
        maxage = num(row['Age']) 

print maxage 

运行前面的代码块显示44是四分卫的最大年龄(在联盟中活跃时,有三个这样的四分卫:沃伦·穆恩、维尼·泰斯特维德和史蒂夫·德伯格。技术上,乔治·布兰达一直打到了 48 岁(这是作为球员的最大年龄),但他从四分卫开始,也是一名踢球的人(有些年了)。

为了回答另一个问题,我们根据四分卫年龄绘制了触地得分统计数据,如下所示:

import csv
import matplotlib.pyplot as plt

# The following functions can be in a separate file
#    -- functions Begin -- 
def num(s):
  try:
    return int(s)
  except ValueError:
    return 0  

def getcolors():
  colors = [(31, 119, 180), (255,0,0), (0,255,0), (148, 103, 189), (140, 86, 75), (218, 73, 174), (127, 127, 127), (140,140,26), (23, 190, 207), (65,200,100), (200, 65,100), (125,255,32), (32,32,198), (255,191,201), (172,191,201), (0,128,0), (244,130,150), (255, 127, 14), (128,128,0), (10,10,10), (44, 160, 44), (214, 39, 40), (206,206,216)]

  for i in range(len(colors)):
    r, g, b = colors[i]
    colors[i] = (r / 255\. , g / 255\. , b / 255.)
  return colors

def getQbNames():
  qbnames = ['Peyton Manning']
  name=''
  i=0
  with open('/Users/MacBook/java/qb_data.csv') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
      if ( row['Name'] != name and qbnames[i] != row['Name']):
        qbnames.append(row['Name'])
        i = i+1
  return qbnames

def readQbdata():
  resultdata = []
  with open('/Users/MacBook/java/qb_data.csv') as csvfile:
    reader = csv.DictReader(csvfile)
    resultdata = [row for row in reader]
  return resultdata

fdata=[]
prevysum=0

#    -- functions End -- 

qbnames = getQbNames()
fdata = readQbdata()

i=0
rank=0
prevysum=0
lastyr=0
highrank=244
colorsdata = getcolors() 

fig = plt.figure(figsize=(15,13))
ax=fig.add_subplot(111,axisbg='white')

# limits for TD
plt.ylim(10, 744)
#change xlimit to have age ranges 
plt.xlim(20, 50)

colindex=0
lastage=20

for qbn in qbnames:
  x=[]
  y=[]
  prevysum=0
  for row in fdata: 
    if ( row['Name'] == qbn and row['Year'] != 'Career'):
      yrval = num(row['Year'])
      lastage = num(row['Age'])
      prevysum += num(row['TD'])
      lastyr = yrval
      x += [lastage]
      y += [prevysum]

  if ( rank > highrank):
    if ( lastage == 44):
      plt.plot(x,y, color='red', label=qbn, linewidth=3.5)
    else:
      plt.plot(x,y, color=colorsdata[colindex], label=qbn, linewidth=2.5)
      plt.legend(loc=0, prop={'size':10}) 

    colindex = (colindex+1)%22
    plt.text(lastage-1, prevysum+2, qbn+"("+str(prevysum)+"):" +str(lastage), fontsize=9)

  else:
    if ( lastage == 44):
      plt.plot(x,y, color='red', label=qbn, linewidth=3.5)
      plt.text(lastage-1, prevysum+2, qbn+"("+str(prevysum)+"):" +str(lastage), fontsize=9)
    else:         
      plt.plot(x,y, color=colorsdata[22], linewidth=1.5) 
    rank = rank +1 

plt.xlabel('Age', fontsize=18)
plt.ylabel('Number of Touch Downs', fontsize=18)
plt.title("Touch Downs by Quarter Backs by Age", fontsize=20)
plt.show() 

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_08.jpg

当你看一下标绘结果,只有两个四分卫的成绩能和 35 岁的培顿·曼宁相提并论,那就是德鲁·布里斯和汤姆·布拉迪。然而,考虑到汤姆·布拉迪目前的年龄和他迄今为止的成就,似乎只有德鲁·布里斯更有可能超越培顿·曼宁的触地得分记录。

下图显示了这一结论,并给出了基于 35 岁的简单数据图。对比前四名四分卫的成绩——培顿·曼宁、汤姆·布拉迪、德鲁·布里斯和布雷特·法弗——我们可以看到,德鲁·布里斯在 35 岁时的成就堪比佩顿在同样年龄时的成就。虽然《纽约时报》以标题*为题的文章《为什么培顿·曼宁的记录很难被打破》*得出了不同的结论,但以下绘图,至少是倾向于德鲁·布里斯可能打破记录的可能性:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_09.jpg

用数据创造有趣的故事

数据可视化定期提升其用数据揭示故事的能力,在某些情况下,可视化地揭示不那么琐碎的故事。在最近的过去,记者们一直在将可视化更多地融入他们的叙述中,这通常有助于我们更好地理解他们的故事。在商业世界中,很少有人能掌握数据如何与一个既能在情感上又能在智力上吸引观众的有意义的故事联系起来。正如拉迪亚德·吉卜林所写的那样,如果历史是以故事的形式教授的,它将永远不会被忘记;类似的想法也适用于数据。因此,我们应该明白,如果以正确的方式呈现,数据会被更好地理解和记住。

为什么故事如此重要?

我们今天有许多可视化的工具和方法:条形图和饼图、表格、折线图、气泡图、散点图等等,不胜枚举。然而,使用这些工具,重点是数据探索,而不是辅助叙述。虽然有可视化的例子确实有助于讲故事,但它们很少。这主要是因为找到故事比计算数字要困难得多。还有 读者驱动的叙事作者驱动的叙事

作者驱动的叙事具有由作者选择并呈现给公众读者的数据和可视化。另一方面,读者驱动的叙事为读者提供了玩数据的工具和方法,这给了读者更多的灵活性和选择来分析和理解可视化。

读者驱动的叙事

2010 年,斯坦福大学的研究人员研究并回顾了讲故事的新兴重要性,并为叙事可视化提出了一些设计策略。根据他们的研究,纯作者驱动的方法在可视化中有严格的线性路径,依赖于消息传递,并且没有交互性,而读者驱动的方法没有规定的图像排序,没有消息传递,并且具有高度的交互性。作者驱动方法的一个例子是幻灯片演示。该研究列出的七种可视化叙事包括杂志风格、标注图表、分区海报、流程图、连环画、幻灯片和一部电影/视频/动画。

Gapminder

读者驱动的叙事与数据驱动的叙事相结合的一个经典例子是《Gapminder World》(http://gapminder.org/world)。它收集了 600 多个国际经济、环境、卫生、技术等数据指标。它提供了学生可以用来研究现实世界问题和发现模式、趋势和相关性的工具。这是由 Trendalyzer 软件开发的,该软件最初由瑞典的汉斯·罗斯林基金会开发,后来在 2007 年 3 月被谷歌收购。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_10.jpg

Gapminder 使用的信息可视化技术是一个交互式气泡图,默认设置为五个变量: XY 、气泡大小、颜色和一个由滑块控制的时间变量。这种滑动控制和对沿着 XY 轴的选择使其具有交互性。然而,创造一个故事,即使有这样的工具,也不一定容易。讲故事是一门手艺,可以成为一种有效的知识分享技巧,因为它比大多数其他交流方式更有效地传达了背景和情感内容。

最有魅力的说书人都明白理解观众的重要性。他们可能会给一个孩子和一个成年人讲同样的故事,但是发音会有所不同。同样,数据驱动或读者驱动的故事应该根据谁在听或研究它来调整。例如,对于高管来说,统计数据可能是关键,但商业智能经理最有可能对方法和技术感兴趣。

今天有很多 JavaScript 框架可以用来创建交互式可视化,最流行的是 D3.js,使用 Python,今天只有几种方法可以创建交互式可视化(不使用 Flash)。一种方法是生成 D3.js 可以用来绘图的 JSON 格式的数据,第二种选择是使用 Plotly(http://www . Plotly . ly)。我们将在这一章的最后一节更详细地讨论 Plotly。

国情咨文

推特根据奥巴马总统演讲期间的推文创建了一个可视化工具,可以根据位置和主题绘制推文。这种可视化很有趣,因为它在一个地方捕捉了很多细节。滚动演讲,看看推特的反应;发布在http://twitter.github.io/interactive/sotu2015/#p1

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_11.jpg

美国的死亡率

从 1968 年到 2010 年,美国的死亡率下降了大约 17%,这些年我们有详细的数据(来自 http://www.who.int/healthinfo/mortality_data/en/和 T2)。几乎所有这些进步都可以归因于男性生存前景的改善。看起来进步在 20 世纪 90 年代中期就停止了,但其中一个原因可能是从那以后人口老龄化了很多。人们可能会读到彭博对此的完整描述,但这里我们试图展示两个可视化:

  • 1968-2010 年期间男性、女性和合计死亡率
  • 死亡率为七个年龄组展示了一些有趣的结果

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_12.jpg

该示例的代码如下:

import csv
import matplotlib.pyplot as plt

fig = plt.figure(figsize=(15,13))
plt.ylim(740,1128)
plt.xlim(1965,2011)
# Data from http://www.who.int/healthinfo/mortality_data/en/
with open('/Users/MacBook/Downloads/mortality1.csv') as csvfile:
  mortdata = [row for row in csv.DictReader(csvfile)]

x=[]
males_y=[]
females_y=[]
every_y=[]
yrval=1968
for row in mortdata:
  x += [yrval]
  males_y += [row['Males']]
  females_y += [row['Females']]
  every_y += [row['Everyone']]
  yrval = yrval + 1

plt.plot(x, males_y, color='#1a61c3', label='Males', linewidth=1.8)
plt.plot(x, females_y, color='#bc108d', label='Females', linewidth=1.8)
plt.plot(x, every_y, color='#747e8a', label='Everyone', linewidth=1.8)
plt.legend(loc=0, prop={'size':10})
plt.show()

死亡率是按每 10 万人计算的。通过将人口分成不同的年龄组,预期寿命的提高是持续的,尤其是 25 岁以下年龄组的进步最大。25-44 岁年龄组以下的人口到底发生了什么(红色显示)?关于彭博的叙述将另一个事实联系起来,很好地阐明了原因,即在此期间,艾滋病造成的死亡人数对该年龄组产生了影响。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_13.jpg

艾滋病每年夺去 4 万多名美国人的生命,其中 75%的人年龄在 25-44 岁之间。因此,不寻常的结果是在那个时间窗口看到的。

import csv
import matplotlib.pyplot as plt

fig = plt.figure(figsize=(15,13))
plt.ylim(35,102)
plt.xlim(1965,2015)

colorsdata = ['#168cf8', '#ff0000', '#009f00', '#1d437c', '#eb912b', '#8663ec', '#38762b']
labeldata = ['Below 25', '25-44', '45-54', '55-64', '65-74', '75-84', 'Over 85']

# using reader() instead of DictReader() so that we could loop to 
# build y-values in list
with open('/Users/MacBook/Downloads/mortality2.csv') as csvfile:
  mortdata = [row for row in csv.reader(csvfile)]

x=[]
for row in mortdata:
  yrval = int(row[0])
  if ( yrval == 1969 ):
    y = [[row[1]],[row[2]],[row[3]],[row[4]],[row[5]],[row[6]],[row[7]]]
  else:
   for col in range(0,7):
     y[col] += [row[col+1]]
  x += [yrval]

for col in range(0,7):
  if ( col == 1 ):
    plt.plot(x, y[col], color=colorsdata[col], label=labeldata[col], linewidth=3.8)
  else:
    plt.plot(x, y[col], color=colorsdata[col], label=labeldata[col], linewidth=2)

plt.legend(loc=0, prop={'size':10})
plt.show()

csv.reader()csv.DictReader()的区别在于,当输入的 CSV 文件有字段名(或列名)时,DictReader()使用字段名作为关键字,使用该列中的实际值作为数据值。在前面的例子中,我们使用了reader(),因为当涉及到循环时( y[col] = [row[col+1]] )会很方便。此外,对于reader(),如果 CSV 文件中存在列名,则应忽略第一行。

我们还将这两个示例的过滤数据作为mortality1.csvmortality2.csvhttp://www.knapdata.com/python提供。

对于mortdata[:4],每种阅读方法的结果都是不同的。换句话说,当我们使用reader()mortdata[:4]的结果如下:

[['1969', '100', '99.92', '97.51', '97.47', '97.54', '97.65', '96.04'],  ['1970', '98.63', '97.78', '97.16', '97.32', '96.2', '96.51', '83.4'],  ['1971', '93.53', '95.26', '94.52', '94.89', '93.53', '93.73', '89.63'],  ['1972', '88.86', '92.45', '94.58', '95.14', '94.55', '94.1', '89.51']] 

使用DictReader(),假设 CSV 文件有字段名,四行显示如下:

[{'25-44': '99.92', '45-54': '97.51', '55-64': '97.47', '65-74': '97.54', '75-84': '97.65', 'Below 25': '100', 'Over 85': '96.04', 'Year': '1969'},
 {'25-44': '97.78', '45-54': '97.16', '55-64': '97.32', '65-74': '96.2', '75-84': '96.51', 'Below 25': '98.63', 'Over 85': '83.4', 'Year': '1970'},
 {'25-44': '95.26', '45-54': '94.52', '55-64': '94.89', '65-74': '93.53', '75-84': '93.73', 'Below 25': '93.53', 'Over 85': '89.63', 'Year': '1971'},
 {'25-44': '92.45', '45-54': '94.58', '55-64': '95.14', '65-74': '94.55', '75-84': '94.1', 'Below 25': '88.86', 'Over 85': '89.51', 'Year': '1972'}]

其他几个示例叙述

人们可以探索、想象、互动和玩耍的例子数不胜数。一些值得注意的问题如下:

  • 经济衰退如何重塑经济 255 图(纽约时报):这段叙述展示了在大衰退结束后的五年里,经济如何重新获得了失去的 900 万个工作岗位,突出了哪些行业比其他行业恢复得更快。(来源:http://tinyurl.com/nwdp3pp。)
  • 2013 年华盛顿奇才队的投篮明星(华盛顿邮报):这张互动图是几年前根据 2013 年华盛顿奇才队的表现而创作的,试图分析和看看签下保罗·皮尔思如何能够带来中距离投篮的大幅提升。(来源:http://www . Washington post . com/WP-SRV/special/sports/wizard-shooting-star/。)

作者驱动的叙事

纽约**时报制作了一些世界上最好的数据可视化、多媒体和互动故事。他们对这些项目的抱负一直是在非常有声望的水平上达到新闻标准,并为读者创造真正新的体验。其中的讲故事文化是这部作品背后的能量来源之一。

例如,有一个名为也门混乱地理*的数据和作者驱动叙事的组合。2015 年 3 月 26 日,沙特阿拉伯喷气式飞机袭击了也门的目标,以打击胡塞叛军组织。也门对沙特阿拉伯、伊朗和美国等关键角色扮演着重要角色。《纽约时报》的作者们直观地捕捉到,胡塞武装的影响力在过去几年有所增长。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_14.jpg

也门是基地组织在阿拉伯半岛最活跃的分支之一的所在地。自 2009 年以来,美国已经在也门进行了至少 100 次空袭。除了基地组织的占领之外,伊斯兰国在该地区也有活动,最近,他们声称对萨那两个什叶派清真寺的爆炸事件负责,这两起爆炸造成 135 多人死亡。以下可视化来自美国企业研究所关键威胁项目调查新闻局:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_15.jpg

另一个很好的例子是大卫·麦坎德斯对大西洋过去的可视化,它展示了过度捕捞之前的海洋是什么样子。很难想象过度捕捞对海洋造成的损害。效果是看不见的,隐藏在海洋中。下图显示了 1900 年和 2000 年北大西洋中被广泛食用的鱼类的生物量。人们普遍食用的鱼类包括金枪鱼、鳕鱼、黑线鳕、鳕鱼、大比目鱼、鲱鱼、鲭鱼、鳕鱼、鲑鱼、海鳟鱼、条纹鲈鱼、鲟鱼和大菱鲆,其中许多现在都很脆弱或濒临灭绝。

不列颠哥伦比亚大学的维利·克里斯滕森博士和他的同事使用生态系统模型、水下地形图、鱼获记录和统计分析来呈现本世纪不同时期大西洋鱼类的生物量。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_16.jpg

感知和呈现方法

在过去,数据的大小和种类并没有带来太大的挑战;因此,感知和分析数据很简单。今天,在无数的领域中有大量的数据,可视化可以为人类感知和交互数据的可视化提供有价值的帮助。人为因素对整个可视化过程有很大贡献,以便更好地理解数据并帮助决策任务。

可视化技术可以分为两个领域:

  • 科学 可视化:这涉及到具有内在物理实体的科学数据
  • 信息 可视化:这涉及到抽象数据(空间或非空间)

大多数可视化系统的设计都是为了让人类和计算机能够相互协作,各自执行以下任务:

  • 直观地表示数据以增强数据分析
  • 直观显示模型、数据解释、想法、假设和洞察力
  • 帮助用户通过为他们的假设找到支持或矛盾的证据来改进他们的模型
  • 帮助用户组织和分享他们的想法

对视觉感知的新见解来自于信息可视化之外的各个学科的工作,如人的因素和人机交互。数据可视化的最大优势之一是我们处理视觉信息的速度比语言信息快得多。20 世纪 20 年代,心理学家在德国研究知觉组织,第一批是格式塔理论家。

感知的格式塔原则

完形这个词的意思是“有组织的整体”,或者换句话说,当单独识别的部分对整体有不同的特征时。例如,为了描述一棵树,你可以说它有不同的部分,如树干、树叶、树枝、果实(在某些情况下)。然而,当我们看整棵树时,我们意识不到部分,而是意识到整个物体——在这种情况下,是树。

格式塔知觉的原理如下:

了解这些原则对于创建任何可视化方法都非常有用。

让我们用一个例子来进一步阐述。邻近是指如果形状看起来彼此相似,则将形状分组在一起的视觉方法。这样的群体通常被视为一个单一的单位。例如,下图显示了如何区分邻近关系:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_35.jpg

可视化的一些最佳实践

第一个重要的步骤是知道努力背后的目标是什么。如何知道可视化是否有目的?了解观众是谁以及这将如何帮助他们也非常重要。

一旦知道了这些问题的答案,并且很好地理解了可视化的目的,下一个挑战就是选择正确的方法来呈现它。最常用的可视化类型可以根据以下内容进一步分类:

  • 比较和排名
  • 相互关系
  • 分配
  • 特定位置或地理数据
  • 部分到整体的关系
  • 趋势随着时间的推移

对比排名

比较和排名可以有多种方式,但是传统的方式是使用条形图。条形图被认为是将数量值编码为同一基线上的长度。然而,这并不总是显示比较和排名的最佳方式。例如,要显示非洲国内生产总值排名前 12 的国家,以下演示是一种创造性的可视化方式(礼貌: Stats Legend,Andrew Gelman 和 Antony Unwin ):

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_22.jpg

相关性

一个简单的相关性分析是一个很好的开始来识别测量之间的关系,虽然相关性不能保证关系。为了确认这种关系确实存在,通常需要一种统计方法。下面是一个构建简单散点图来检测两个因素之间的相关性的示例,比如某大学学生中的gpatvgpaexercise:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_23.jpg

但是,我们可以使用其他方式来显示相关矩阵。例如,可以使用散点图、热图或一些特定的例子来显示 S&P 100 指数股票之间的影响网络。(以下两幅图取自http://www.sthda.com高通量分析统计工具。)为了进一步强调,一个相关矩阵包含矩阵形式的数据。数据通过使用缩放的颜色映射进行关联,如下例所示。更多详情,建议您参考网站:http://www.sthda.com

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_24.jpg

相关矩阵用于同时研究多个变量之间的相关性。结果是一个包含每个变量和其他变量之间的相关系数的表。热图起源于 2D 在数据矩阵中显示值。有许多不同的配色方案可以用来说明热图,每个方案都有感知上的优点和缺点。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_25.jpg

分布

分布分析显示了定量值在它们的范围内是如何分布的,因此在数据分析中非常有用。例如,比较一个班学生的期中、期末考试和课程总成绩的家庭作业的等级分布。在本例中,我们将讨论两种最常用的图表类型。一个是 直方图(如下图所示),另一个是方块 方块触须图。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_26.jpg

直方图的形状很大程度上取决于指定的面元大小和位置。盒须图非常适合显示多种分布。他们把所有的数据点——在这种情况下是每个学生的分数——打包到一个触须显示器中。现在,您可以轻松地识别所有类别中的低值、第 25 百分位值、中间值、第 75 百分位值和最大值,所有这些都是同时进行的。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_27.jpg

在 Python 中方便地绘制这些图的方法之一是使用 Plotly,这是一种在线分析和可视化工具。Plotly 为 Python、R、Julia 和 JavaScript 提供在线绘图、分析和统计工具以及科学绘图库。直方图和盒须图的例子,参考https://plot.ly/python/histograms-and-box-plots-tutorial

特定位置或地理数据

地图是显示特定位置数据的最佳方式。当地图与另一个详细说明地图显示内容的图表(如从大到小排序的条形图、显示趋势的折线图等)配对时,使用地图最为合适。例如,下图显示了各大洲地震的强度对比:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_28.jpg

部分对整体的关系

饼图是显示部分到整体关系的常用工具,但也有其他方法。分组条形图有利于将类别中的每个元素与其他元素进行比较,也有利于跨类别比较元素。然而,分组使得区分每组总数之间的差异变得更加困难。这就是堆叠柱形图的由来。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_29.jpg

堆叠柱形图非常适合显示总数,因为它们直观地将所有类别聚集在一个组中。不利的一面是,比较各个类别的规模变得更加困难。堆叠也表示部分到整体的关系。

一段时间内的趋势

分析数据最常用的可视化方法之一是显示一段时间内的趋势。在下面的例子中,绘制了 2009-2015 年对可穿戴设备初创公司的投资。说明可穿戴设备的投资几年来一直在上升;2014 年的交易活动如火如荼,有 61 笔交易完成,总价值 4.27 亿美元,而 2013 年(仅一年前)只有 43 笔交易价值 1.66 亿美元。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_30.jpg

有了这个观察,看看未来几年市场如何演变将会很有趣。

Python 中的可视化工具

分析和可视化数据需要几个软件工具:编写代码的文本编辑器(最好是语法高亮显示的)、运行和测试代码的 Python 和附加库,或许还有呈现结果的工具。软件工具分为两类:通用软件工具和特定软件组件。

开发工具

通用软件工具是一个集成开发环境 ( IDE ),它是一个应用,在一个包中拥有所有的生产力工具。从处理 Python 库的角度来看,这些 ide 通常非常方便。关于这些集成开发环境工具的更多细节将在下一章中讨论。在这一章中,我们将把我们的讨论限制在对来自 Enthought】的树冠和来自 Continuum Analytics蟒蛇的简单介绍。

具体软件组件有BokehIPythonmatplotlibNetworkXSciPyNumPyScikit-learnSeaborn等 Python 绘图库。这两个 ide 都有一个非常方便的方法来处理这些绘图库的添加、删除和更新。

来自恩思的树冠

entorn Canopy 有一个免费版本,是在 BSD 风格的许可下发布的,除了其他几个库之外,还附带了作为绘图工具的 GraphCanvasSciMathChaco 。它拥有高级文本编辑器、集成的 IPython 控制台、图形包管理器和在线文档链接。Canopy 分析环境简化了科学家、工程师和分析师的数据分析、可视化、算法设计和应用开发。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_03.jpg

来自连续体分析的蟒蛇

Anaconda IDE 基于 conda 应用。Conda 是一个用于查找和安装软件包的应用。conda 包是包含系统级库、Python 模块、可执行程序或其他组件的二进制 tarball。Conda 跟踪包和平台细节之间的依赖关系,使得从不同的包集合创建工作环境变得简单。

Anaconda 有 sypder-app ,一个科学的 Python 开发环境,也有一个 IPython 查看器。除此之外,IPython 还可以作为图形用户界面或基于网络的笔记本推出。最方便的是可以在主目录中安装 Python,而不需要触碰系统安装的 Python。到目前为止,并不是所有的包都准备好使用 Python 3;因此,最好将 Python 2 与这些 ide 一起使用。

IPython()http://ipython.scipy.org/)提供了一个增强的、交互式的 Python 外壳,并且强烈推荐主要是因为数据分析和可视化本质上是交互式的。大多数平台都支持 IPython。IPython 附带的一些附加功能如下:

  • 选项卡完成:这包括变量、函数、方法、属性和文件名的完成。标签完成是通过 GNU Readline 库(http://tiswww.case.edu/php/chet/readline/rltop.html)实现的,非常上瘾。在接触到 GNU Readline 之后,很难回到常规的命令行界面。
  • 命令历史功能:这将发布之前使用的命令的完整记录的命令历史。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_04.jpg

交互可视化

要使可视化被认为是交互式的,它必须满足两个标准:

  • 人类输入:对信息的视觉表示的某些方面的控制必须对人类可用
  • 响应时间:人类做出的改变必须及时融入可视化

当必须处理大量数据来创建可视化时,这变得非常困难,有时是不可能的,即使以当前的技术;因此,“交互式可视化”通常应用于在输入几秒钟内向用户提供反馈的系统。许多交互式可视化系统支持导航隐喻,类似于通过物理世界的导航。

互动的好处是,人们可以在更短的时间内探索更大的信息空间,这可以通过一个平台来理解。然而,这种交互的一个缺点是,它需要大量时间来彻底检查每一种可能性,以测试可视化系统。此外,设计系统以保证对用户行为的即时响应可能需要大量的算法关注。

任何可视化方法都需要良好的布局规划。一些布局方法会自动生成对称的图形;或者,一些绘图方法从发现数据的对称性开始。交互式可视化是使用事件侦听器实现的,对一些人来说,这是众所周知的常识,但无论如何,下面的部分描述了它的全部内容。

事件监听器

事件监听器是当鼠标被移动或点击时使用的过程。技术上,事件有很多种,但纯粹为了交互可视化,你只需要知道当用户用鼠标在可视化中导航时会发生什么。交互的延迟,也就是系统响应鼠标动作的时间,非常重要。

最显而易见的原则是,用户确实应该有某种动作已经完成的确认,而不是被悬着不知道动作是否还在进行。因此,诸如突出显示选定项目的反馈是确认所需操作已成功完成的好方法。视觉反馈通常应该发生在大约一秒钟的即时反应等待时间内。以下是谷歌图表中的一个 JavaScript 事件监听器示例:

chart = new google.visualization.PieChart(document.getElementById( 'chart_div'));
google.visualization.events.addListener(chart, 'select', selectHandler);
chart.draw(data, options);

function selectHandler() {
  var selectedItem = chart.getSelection()[0];
  var value = data.getValue(selectedItem.row, 0);
  alert('The user selected ' + value);
}

另一个原则是,如果一个动作花费的时间比用户自然预期的要长得多,那么应该向用户显示某种进度指示器。用 JavaScript 编写事件侦听器要容易得多,但是为了使用用 Python 编写的绘图方法创建交互式可视化,应该使用 Plotly。

还有另一个模块,图形工具(https://graph-tool . skill . de),可以用来以直接的方式执行动画。它使用 GTK+在交互窗口和屏幕外显示动画到文件。这个想法是为了容易地生成可视化,可以用于演示和嵌入网站。

布局

为了直观高效地显示数据,了解布局方法非常重要。美学是衡量布局算法优劣的标准之一。为了使布局结果更易读,如果可能的话,结构需要有层次或对称;一个关键因素是空间的利用。

一个好的布局是解开和理解任何图形的关键。一般来说,为了更好地理解,每种布局都特别适合不同类型的数据可视化。一些值得注意的布局方法如下:

  • 圆形布局
  • 放射状布局
  • 气球布局

圆形布局

表格是数据的天然容器。每当信息被呈现时,通过表格呈现的机会非常高。然而,在许多情况下,当这些信息很复杂(因此表格很大)时,表格表示很难直观地解析,表格数据中的模式仍然不透明。

换句话说,有用的容器并不总是呈现数据的有用方式。该表很好地呈现了单个数据,但是它们之间的相互关系以及它们组成的模式几乎不可见。圆形布局可以使用几种不同的组合(定性和定量)在单个可视化中显示,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_32.jpg

例如,如上图所示,在有限的空间内显示复杂的关系是很直观的。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_33.jpg

上图显示了以圆形布局显示的复杂层次关系的示例。

放射状布局

Sunburst 可视化是一种用于显示树状结构的径向空间填充可视化技术(如上图所示)。还有其他填充空间的可视化方法,使用其他可视化编码来描述层次结构。例如,树形图是一种空间填充可视化,它使用“包含”来显示“父子”关系。有几个微妙的变化可以改善这种可视化传达信息的方式。

由于每个轨道的长度随着半径的增加而增加,因此节点的空间往往更大。随着层级的增加,径向树会将更多的节点分布在更大的区域。

气球布局

气球布局有不同的变化,人们甚至可以将它们视为气泡。但是,如果我们使用不同颜色和大小的气球(或圆圈/气泡),在这个可视化中可以显示更多,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_02_34.jpg

总结

可视化方法的原则对于创建一个有效的故事是有用的。本章解释的叙述给出了美学的概念和方法的巨大变化。

数据可视化的目标是通过所选择的可视化显示方法,向用户清晰有效地传达信息。有效的可视化有助于分析和推理数据和证据。它使复杂的数据更易于访问、理解和使用。用户可能有特定的分析任务,如进行比较或理解因果关系,图形的设计原则遵循任务。

表通常用于用户查找变量的特定度量,而各种类型的图表用于显示一个或多个变量的数据模式或关系。

数据可视化既是一门艺术,也是一门科学,就像解决一个数学问题。没有一个正确的方法来解决它。同样,没有一种正确的方法来创建可视化方法。可视化工具有很多,我们知道一些支持 Python 的工具。在下一章中,将讨论关于这些工具的更多细节。*

三、Python 集成开发环境入门

Python 是一种广泛使用的编程语言,已经存在了 20 多年。在许多其他东西中,这种语言因其简单性和动态类型而非常受欢迎。*类型(基准)*动态确定数据对象的类型。它有一个语法,允许程序员写很少的代码行。Python 支持多种编程范例,包括函数式、面向对象和过程式。

Python 解释器可以在几乎所有正在使用的操作系统上使用。它的内置数据结构与动态绑定相结合,使得它作为一种高性能语言来快速连接现有的操作组件非常有吸引力。即使在分布式应用中,Python 也作为粘合剂与 Hive (NoSQL)一起使用,以非常快速和高效地完成一些事情。Python 功能强大,在软件开发社区中很受欢迎,它需要一个交互式环境来创建、编辑、测试、调试和运行程序。

一个 集成开发环境 ( IDE )是一个软件应用,它提供了一套全面而强大的工具来为运行 Windows、Linux 或 Mac OS 操作系统的目标系统构建应用。这些工具提供单一且一致的集成环境,旨在最大限度地提高工作效率。Python 编程的 IDE 有很多选择。细节将在本章的下一节讨论。此外,我们将讨论以下主题:

  • Python 中的集成开发环境工具
  • 安装指南—下载和安装工具的说明
  • conda 命令行界面 ( CLI )和 Spyder
  • IDE 工具中的数据可视化工具是特定于对可视化有用的库的
  • 交互式可视化包
  • 使用集成开发环境工具的一些绘图示例

Python 中的 IDE 工具

分析和可视化数据需要几个软件工具:一个编写代码的文本编辑器(最好是语法高亮显示),运行和测试代码的附加工具和库,也许还有另一套呈现结果的工具。集成开发环境有许多优点。一些值得注意的问题如下:

  • 语法高亮显示(立即显示错误或警告)
  • 在调试模式下单步执行代码
  • 交互式控制台
  • 与交互式图形笔记本(如 IPython)的集成

Python 3.x 对比 Python 2.7

Python 3.x 与 2.x 版本不向后兼容。这就是为什么 Python 2.7 仍在使用的原因。在本书中,我们将使用 Python 2.7,尽量不要将重点放在 Python 3.x 上,这个问题超出了本书的范围,建议您搜索如何编写适用于不同版本的代码的信息。一些 IDE 工具有使用这两个版本的具体说明。在某些情况下,代码的编写可能会有所不同。

交互工具的类型

在进一步讨论 Python IDEs 的之前,考虑显示交互式数据可视化的不同方式是很重要的。创建交互式数据可视化有许多选项,但在这里,我们将只考虑两种流行的工具来实现这一点:

  • 伊普提洪伊普提翁伊普提翁伊普提翁伊普提翁伊普提翁伊普提翁伊普提翁伊普提翁伊普提翁伊普提翁伊普提翁
  • 阴谋地

IPython

2001 年,Fernando Perez 开始致力于 IPython,这是一个增强的交互式 Python shell,具有一些改进,例如历史缓存、配置文件、对象信息和会话日志记录。最初专注于 Python 中的交互计算,后来包括 Julia、R、Ruby 等等。一些特性——比如自动添加括号和完成标签——非常省时,并且在可用性方面非常有效。在标准 Python 中,要完成选项卡,您必须导入几个模块,而 IPython 默认提供选项卡完成。

IPython 为 Python 脚本编写提供了以下丰富的工具集:

  • 方便的终端命令和基于 Qt 的工具
  • 纯基于网络的笔记本电脑的交互环境,具有与独立笔记本电脑相同的核心功能;它还支持代码、文本、数学表达式和内联图
  • 方便的交互式数据可视化;这种能力是许多 ide 集成支持 IPython 的原因
  • 易于使用的高性能多处理计算工具

对 IPython 最有帮助的四个命令及其简要描述:

|

命令

|

描述

|
| — | — |
| ? | 这指定了 IPython 特性的介绍和概述 |
| %quickref | 这表示快速参考 |
| --help-all | 这指定了 Python 的帮助 |
| %who/%whos | 这给出了关于标识符的信息 |

IPython 笔记本是一个基于网络的交互式计算环境。在这里,您可以将代码、数学和绘图合并到一个文档中。

IPython(http://ipython.scipy.org/)提供了一个增强的交互式 Python 外壳,强烈推荐,主要是因为数据分析和可视化本质上是交互式的。大多数平台都支持 IPython。IPython 附带的一些附加功能包括:

  • 选项卡完成:这包括变量、函数、方法、属性和文件名的完成。标签完成是使用 GNU Readline 库(http://tiswww.case.edu/php/chet/readline/rltop.html)实现的。在接触到 GNU Readline 之后,很难回到常规的命令行界面。
  • 命令历史功能:这将发布以前使用的命令的完整记录的命令历史。

在 IPython 上运行的一个示例如下图所示。要了解更多关于 IPython 和 IPython 笔记本的信息,请参考http://nbviewer.ipython.org

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_03_03.jpg

绘图

Plotly 是一个在线分析和数据可视化工具,提供在线绘图、分析和统计工具,以实现更好的协作。该工具使用 Python 构建,用户界面使用 JavaScript,可视化库使用 D3.js、HTML 和 CSS。Plotly 包括许多语言的科学图形库,如 Arduino、Julia、MATLAB、Perl、Python 和 r .有关 Plotly 的示例来源,请参考https://Plotly . ly/~ etpinard/84/fig-31a-Hans-roslings-bubble-chart-For-year-2007/

以下是显示全球人均国内生产总值的臭名昭著的泡沫图例子。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_03_04.jpg

Plotly 提供了一种方便的方式将绘图从matplotlib转换为 Plotly,如以下代码所示(假设您有一个 Plotly 帐户并使用您的凭据登录):

import plotly.plotly as py
import matplotlib.pyplot as plt
#auto sign-in with credentials or use py.sign_in()
mpl_fig_obj = plt.figure()
#code for creating matplotlib plot
py.plot_mpl(mpl_fig_obj)

Python IDE 的类型

以下是目前流行的一些 Python IDEs:

  • PyCharm :这指定了基于 Java Swing 的用户界面
  • PyDev :表示基于 SWT 的用户界面(在 Eclipse 上工作)
  • 互动编辑为 巨蟒 ( IEP )
  • 来自恩思的天篷:这个是基于 PyQt 的
  • 连续分析公司 Spyder 的分布图(T4):这也是基于 PyQt

皮卡姆

PyCharm 是为数不多的有很大特色的热门 ide 之一,社区版是免费的。PyCharm 4.0.6 社区版是当前版本,可在https://www.jetbrains.com/pycharm/download免费下载。他们有快捷方式参考卡可用于苹果电脑,Linux 和视窗系统。佩德罗·克罗格博士在http://pedrokroger.net/getting-started-pycharm-python-ide/写了一篇关于 PyCharm 的详细描述。您可以参考此链接了解更多详细信息。在许多有趣的特性中,代码向导和 NumPy 数组查看器显示在下面的屏幕截图中:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_03_05.jpg

极坐标投影可以快速完成,如前面的截图所示,随机样本数组的创建如下面的截图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_03_06.jpg

类似的随机样本在不同的 IDE(如 Spyder)中创建;下面是一个的例子:

rand_4 = np.random.random_sample((2,2,2,2))-1  
array([[[[-0.6565232 , -0.2920045 ],
[-0.45976502, -0.70469325]],
[[-0.80218558, -0.77538009],
[-0.34687551, -0.42498698]]],
[[[-0.60869175, -0.9553122 ], 
[-0.05888953, -0.70585856]], 
[[-0.69856656, -0.21664848],
[-0.29017137, -0.61972867]]]])

PyDev

PyDev 是 Eclipse IDE 的一个插件。换句话说,Eclipse 的插件足以利用普通集成开发环境可能具有的其他默认功能,而不是创建一个新的集成开发环境。PyDev 支持代码重构、图形调试、交互控制台、代码分析和代码折叠。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_03_07.jpg

您可以安装 PyDev 作为 Eclipse 的插件,或者安装 LiClipse,一个高级的 Eclipse 发行版。LiClipse 不仅增加了对 Python 的支持,还增加了对 CoffeeScript、JavaScript、Django 模板等语言的支持。

PyDev 预装在 LiClipse 中,但需要先安装 Java 7。完整安装步骤可参考http://pydev.org/manual_101_install.html

Python 交互编辑器(IEP)

IEP 是另一个 Python IDE,它拥有其他 IDE 中可用的类似工具,但看起来与您可能在微软 Windows 上使用的任何工具相似。

IEP 是一个跨平台的 Python IDE,旨在交互性和自省性,这使得它非常适合科学计算。它的实用设计旨在简单高效。

IEP 由两个主要的组件组成,编辑器和外壳,并使用一组可插拔工具以各种方式帮助程序员。一些示例工具是源结构、项目管理器、交互式帮助和工作区。一些关键特性如下:

  • 像任何现代 IDE 一样进行代码自省
  • 要么从命令行运行 Python 脚本,要么通过文件或 IPython 界面交互运行
  • Shells 作为后台进程运行
  • 多个外壳可以使用不同的 Python 版本(从 v2.4 到 3.x)

下面的截图显示了如何在同一个 IDE 中使用两个不同版本的 Python:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_03_10.jpg

有些人不认为 IEP 是一个集成开发环境工具,但它服务于开发 Python 程序、编辑它们和运行它们的目的。它同时支持多个 Python 外壳。因此,对于想要使用多个图形用户界面工具包进行编程的人来说,这是一个非常有效的工具,例如 PySide、PyQt4、GTK 和 TK 交互。

IEP 是用(纯)Python 3 编写的,并且使用了 Qt GUI 工具包,但是它可以用来在任何可用的 Python 版本上执行代码。你可以从http://www.iep-project.org/downloads.html下载 IEP。

来自恩思的树冠

entorn Canopy 有一个免费版本,是在 BSD 风格的许可下发布的,除了其他几个库之外,它还附带了 GraphCanvasSciMathChaco 作为绘图工具。像所有的 IDEs 一样,它有一个文本编辑器。它还有 IPython 控制台,非常有用,能够运行和可视化结果。此外,它还附带了一个图形包管理器。当天篷启动时,它会提供一个带有编辑器包管理器文档浏览器的选项供选择。也可以尝试使用他们的培训材料,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_03_01.jpg

除了其他开发代码之外,Canopy 还拥有 IPython 笔记本集成的便捷功能,您可以使用这些功能来创建数据可视化。像大多数 IDEs 一样,它有一个编辑器、一个文件浏览器和 IPython 控制台。此外,还有一个显示当前编辑状态的状态显示。雨篷集成开发环境的这些组件主要执行以下任务:

  • 文件浏览器:有了这个,你就可以从硬盘读取或者写入 Python 程序了
  • Python 代码编辑器:这指定了一个语法突出的代码编辑器,具有专门针对 Python 代码的附加功能
  • Python 窗格:这是一个集成的 IPython(交互式 Python)提示,可用于交互式运行 Python 程序,而不是从文件中运行
  • 编辑器状态栏:可以显示行号、列号、文件类型、文件路径

下面的截图显示了高亮显示的数字。这代表了之前描述的 IDEs 的组件。文件浏览器和 Python 窗格可以拖放到代码编辑器窗口或边框之外的不同位置。当一个窗格被拖动时,它可以停靠的位置以蓝色突出显示,如下图所示的:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_03_08.jpg

文档通过名为座舱盖文档浏览器的浏览器组织,可从帮助菜单访问。这包括一些常用 Python 包的文档链接。

文档浏览器的一个重要特性是,它提供了对文档中呈现的示例代码的简单访问。当用户右键单击示例代码框时,将显示上下文菜单。此外,您可以选择复制代码选项,将代码块的内容复制到 Canopy 的复制粘贴缓冲区,以便在编辑器中使用。

Canopy 为个人提供了几种不同的产品,免费版本被称为 Canopy Express ,大约有 100 个核心包。这个免费版本对于科学和分析计算的 Python 开发来说是一个有用的工具。选择目标操作系统为 Windows、Linux 或 Mac OS 之一后,可在https://store.enthought.com/downloads/下载。

Python 开发环境中的挑战之一是,管理许多不同库和工具的包可能是一项非常耗时且令人生畏的任务。这就是他们的文档浏览器的样子。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_03_09.jpg

Canopy 有一个包管理器,可以用来发现 Canopy 可用的 Python 包,并决定安装哪些附加包和删除哪些包。有一个方便的搜索界面来查找和安装任何可用的软件包,并恢复到以前的软件包状态。

Canopy 使用 Python 功能来确定可用的 Python 包。当 Canopy 启动时,它首先在虚拟环境中查找包并显示它们,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_03_11.jpg

集成开发环境的编号突出显示区域是:

  1. 导航面板:这个和任何 IDE 都差不多;导航有一个树列表类型的结构来选择包管理器的组件。
  2. 主查看区:一旦左侧的选择发生变化,右侧面板将显示选中的项目,以及相关的套餐列表(如前一张截图所示)、带有标题为更多信息按钮的具体套餐信息等等。
  3. 搜索栏:这类似于任何搜索功能,有助于快速搜索包的名称和描述。例如,打字机器将列表过滤为 11 个包(匹配的数量可能因操作系统而异)。
  4. 订阅状态和帮助:这里会显示订阅的链接和当前使用的账号名称。
  5. 状态栏:对于用户进行的每一次导航,状态栏都会根据导航的变化显示结果当前状态的详细信息。

来自连续体分析的蟒蛇

蟒蛇是社区使用的最受欢迎的 ide 之一。它附带了一个已经集成的编译好的长的软件包列表。该 IDE 基于名为 conda 的核心组件(稍后将详细解释),您可以使用condapip安装或更新 Python 包。

Anaconda 是 Python 强大包的免费集合,支持大规模数据管理、分析和可视化,用于商业智能、科学分析、工程、机器学习等。

Anaconda 有一个 Scientific PYthon 开发环境 ( Spyder ),它也有一个 IPython 查看器。此外,IPython 可以作为图形用户界面或基于网络的笔记本推出。最方便的方面是可以在一个主目录下安装 Python,不要碰系统安装的 Python。并非所有的包都已经准备好使用 Python 3;因此,最好将 Python 2 与这些 ide 一起使用。Anaconda IDE 有两个重要组件,基于conda包管理器。两个组件是condaspyder

当 Anaconda 启动时,会出现以下截图。这为用户提供了几个选项,包括 IPython 控制台、IPython 笔记本、Spyder IDE 和 glueviz:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_03_02.jpg

Spyder 概述

Spyder 是一个 Python 开发环境,包含以下组件:

  • Python 代码编辑器:这个自带单独的函数浏览器,类编辑器自带对 Pylint 代码分析的支持。今天,代码完成已经成为一种规范,在所有的 ide 上都很方便,所以它也支持这一点。
  • 交互控制台:Python 语言最适合交互工作;因此,控制台必须具备支持对编辑器中编写的代码进行即时评估的所有必要工具。
  • 探索变量:在任何交互执行过程中探索变量有助于提高整体生产力。编辑变量也是可能的,例如字典,有时还可以编辑数组。

代码编辑器和 IPython 控制台如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_03_12.jpg

conda 概述

Conda 是一个命令行工具,用于管理环境和 Python 的包,而不是使用pip。有多种方法可以查询和搜索包,必要时创建新的环境,并在现有的 conda 环境中安装和更新 Python 包。这个命令行工具还跟踪包和平台细节之间的依赖关系,帮助您从不同的包组合中创建工作环境。要检查运行的是 conda 的哪个版本,您可以输入以下代码(在我的环境中,它显示的是 3.10.1 版本):

Conda –v
3.10.1

一个 conda 环境是一个文件系统目录,包含一组特定的 conda 包。作为一个具体的例子,您可能希望有一个提供 NumPy 1.7 的环境和另一个为遗留测试提供 NumPy 1.6 的环境;conda 使这种混合和匹配变得容易。要开始使用环境,只需将PATH变量设置为指向其 bin 目录。

让我们看一个如何用 conda 安装一个名为 SciPy 的包的例子。假设您已经正确安装了 Anaconda,并且 conda 在运行路径中可用,您可能需要输入以下代码来安装 SciPy:

$ conda install scipy

Fetching package metadata: ....
Solving package specifications: .
Package plan for installation in environment /Users/MacBook/anaconda:

The following packages will be downloaded:

 package                    |            build
 ---------------------------|-----------------
 flask-0.10.1               |           py27_1         129 KB
 itsdangerous-0.23          |           py27_0          16 KB
 jinja2-2.7.1               |           py27_0         307 KB
 markupsafe-0.18            |           py27_0          19 KB
 werkzeug-0.9.3             |           py27_0         385 KB

The following packages will be linked:

 package                    |            build
 ---------------------------|-----------------
 flask-0.10.1               |           py27_1
 itsdangerous-0.23          |           py27_0
 jinja2-2.7.1               |           py27_0
 markupsafe-0.18            |           py27_0
 python-2.7.5               |                2
 readline-6.2               |                1
 sqlite-3.7.13              |                1
 tk-8.5.13                  |                1
 werkzeug-0.9.3             |           py27_0
 zlib-1.2.7                 |                1

Proceed ([y]/n)? 

您应该注意到,正在尝试安装的软件包上的任何依赖项都将被自动识别、下载和链接。如果需要安装或更新任何 Python 包,您必须使用以下代码:

conda install <package name>  or conda update <package name> 

下面是一个使用 conda(更新 matplotlib)从命令行更新包的例子:

conda update matplotlib

Fetching package metadata: ....
Solving package specifications: .
Package plan for installation in environment /Users/MacBook/anaconda:

The following packages will be downloaded:

 package                    |            build
 ---------------------------|-----------------
 freetype-2.5.2             |                0         691 KB
 conda-env-2.1.4            |           py27_0          15 KB
 numpy-1.9.2                |           py27_0         2.9 MB
 pyparsing-2.0.3            |           py27_0          63 KB
 pytz-2015.2                |           py27_0         175 KB
 setuptools-15.0            |           py27_0         436 KB
 conda-3.10.1               |           py27_0         164 KB
 python-dateutil-2.4.2      |           py27_0         219 KB
 matplotlib-1.4.3           |       np19py27_1        40.9 MB
 ------------------------------------------------------------
 Total:        45.5 MB

The following NEW packages will be INSTALLED:

 python-dateutil: 2.4.2-py27_0 

The following packages will be UPDATED:

 conda:           3.10.0-py27_0    --> 3.10.1-py27_0 
 conda-env:       2.1.3-py27_0     --> 2.1.4-py27_0 
 freetype:        2.4.10-1         --> 2.5.2-0 
 matplotlib:      1.4.2-np19py27_0 --> 1.4.3-np19py27_1
 numpy:           1.9.1-py27_0     --> 1.9.2-py27_0 
 pyparsing:       2.0.1-py27_0     --> 2.0.3-py27_0 
 pytz:            2014.9-py27_0    --> 2015.2-py27_0 
 setuptools:      14.3-py27_0      --> 15.0-py27_0 

Proceed ([y]/n)?

要检查使用 Anaconda 安装的软件包,请导航到命令行并输入以下命令,以快速显示默认环境中安装的所有软件包的列表:

conda list 

此外,您始终可以通过常用方式安装软件包,例如pip install,或者使用setup.py文件从源位置安装。虽然 conda 是首选的打包工具,但是 Anaconda 并没有什么特别的地方阻止使用标准的 Python 打包工具(比如pip)。

IPython 不是必需的,但强烈建议使用。IPython 应该在安装 Python、GNU Readline 和 PyReadline 之后安装。默认情况下,Anaconda 和 Canopy 会执行这些操作。本书中的所有示例都使用了 Python 包,这是有充分理由的。在下面的部分,我们已经更新了这个列表。

水蟒可视化图

从获取数据、操纵和处理数据,到可视化和交流研究成果,Python 和 Anaconda 支持科学数据工作流中的多种流程。Python 可以用于各种各样的应用(甚至超越科学计算);用户可以快速采用这种语言,不需要学习新的软件或编程语言。Python 的开源可用性增强了研究结果,并使用户能够与世界各地的科学家和工程师的大型社区联系。

以下是一些可用于 Anaconda 的常见打印库:

  • matplotlib :这是最流行的 Python 绘图库之一。再加上 NumPy 和 SciPy,这是科学 Python 社区的主要驱动力之一。IPython 具有 pylab 模式,该模式专门设计用于使用 matplotlib 执行交互式绘图。
  • Plotly :这是一个在浏览器上工作的协同绘图和分析平台。它支持使用 IPython 笔记本的交互式图形。图形是交互式的,可以通过修改代码和交互式查看结果来进行风格化。使用 matplotlib 生成的任何绘图代码都可以轻松导出到 Plotly 版本。
  • Veusz :这是一个用 Python 和 PyQt 编写的 GPL-科学绘图包。Veusz 也可以嵌入到其他 Python 程序中。
  • Mayavi :这是一个三维绘图包,完全可以从 Python 中脚本化,类似于简单的 pylab 和类似 MATLAB 的接口,用于绘制数组。
  • NetworkX :这是一个 Python 语言软件包,用于创建、操作和研究复杂网络的结构、动力学和功能。
  • pygooglechart :这是一个功能强大的包,可以让你创建可视化的方法,还可以和 Google Chart API 接口。

表面-3D 图

三维图由定义为 Z 的数据生成,作为 (X,Y) 的函数。这在数学上表示为 Z=f(X,Y) 。在我们这里的例子中,我们将绘制 Z=sin(sqrt(X2+Y2)) ,这本质上类似于二维抛物线。我们的绘图需要遵循以下步骤:

  1. First, generate the X and Y grid with the following code:

    import numpy as np
    
    X = np.arange(-4, 4, 0.25) 
    Y = np.arange(-4, 4, 0.25) 
    X, Y = np.meshgrid(X, Y)
    Generate the Z data:
    R = np.sqrt(X**2 + Y**2)
    Z = np.sin(R)
    

    使用mpl_toolkits包绘制简单的三维表面 sin(sqrt(X2+Y2)) 如下图所示;使用颜色条表示打击和绘图图:

    https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_03_13.jpg

  2. 然后,绘制曲面,如下图所示:

    from mpl_toolkits.mplot3d import Axes3d
    from matplotlib import cm
    from matplotlib.ticker import LinearLocator, FormatStrFormatter
    import matplotlib.pyplot as plt
    import numpy as np
    
    fig = plt.figure(figsize=(12,9))
    ax = fig.gca(projection='3d')
    X = np.arange(-4, 4, 0.25)
    Y = np.arange(-4, 4, 0.25)
    X, Y = np.meshgrid(X, Y)
    R = np.sqrt(X**2 + Y**2)
    Z = np.sin(R)
    surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=0, antialiased=False)
    
    ax.set_zlim(-1.01, 1.01)
    ax.zaxis.set_major_locator(LinearLocator(10))
    ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
    
    fig.colorbar(surf, shrink=0.6, aspect=6)
    
    plt.show()
    

为了让这个三维绘图工作,你必须确保安装了 matplotlib 和 NumPy 。Anaconda 中的默认包附带了这些安装。

正方形地图图

通过比较和上一章讨论的排名示例,使用 squarify 算法(带有 matplotlib)显示非洲 GDP 排名前 12 的国家,您可以获得一个看起来类似于树状图的图,如下代码所示:

# Squarified Treemap Layout : source file (squarify.py)
# Implements algorithm from Bruls, Huizing, van Wijk, "Squarified Treemaps"
# squarify was created by Uri Laserson 
# primarily intended to support d3.js 

def normalize_sizes(sizes, dx, dy):
  total_size = sum(sizes)
  total_area = dx * dy
  sizes = map(float, sizes)
  sizes = map(lambda size: size * total_area / total_size, sizes)
  return sizes

def pad_rectangle(rect):
  if rect['dx'] > 2:
    rect['x'] += 1
    rect['dx'] -= 2
  if rect['dy'] > 2:
    rect ['y'] += 1
    rect['dy'] -= 2

def layoutrow(sizes, x, y, dx, dy):
  covered_area = sum(sizes)
  width = covered_area / dy
  rects = []
  for size in sizes:  
    rects.append({'x': x, 'y': y, 'dx': width, 'dy': size / width})
    y += size / width
  return rects

def layoutcol(sizes, x, y, dx, dy):
  covered_area = sum(sizes)
  height = covered_area / dx
  rects = []
  for size in sizes:
    rects.append({'x': x, 'y': y, 'dx': size / height, 'dy': height})
    x += size / height
  return rects

def layout(sizes, x, y, dx, dy):
  return layoutrow(sizes, x, y, dx, dy) if dx >= dy else layoutcol(sizes, x, y, dx, dy)

def leftoverrow(sizes, x, y, dx, dy):
  covered_area = sum(sizes)
  width = covered_area / dy
  leftover_x = x + width
  leftover_y = y
  leftover_dx = dx - width
  leftover_dy = dy
  return (leftover_x, leftover_y, leftover_dx, leftover_dy)

def leftovercol(sizes, x, y, dx, dy):
  covered_area = sum(sizes)
  height = covered_area / dx
  leftover_x = x
  leftover_y = y + height
  leftover_dx = dx
  leftover_dy = dy - height
  return (leftover_x, leftover_y, leftover_dx, leftover_dy)

def leftover(sizes, x, y, dx, dy):
  return leftoverrow(sizes, x, y, dx, dy) if dx >= dy else leftovercol(sizes, x, y, dx, dy)

def worst_ratio(sizes, x, y, dx, dy):
  return max([max(rect['dx'] / rect['dy'], rect['dy'] / rect['dx']) for rect in layout(sizes, x, y, dx, dy)])

def squarify(sizes, x, y, dx, dy):
  sizes = map(float, sizes)
  if len(sizes) == 0:
    return []
  if len(sizes) == 1:
    return layout(sizes, x, y, dx, dy)
  # figure out where 'split' should be
  i = 1
  while i < len(sizes) and worst_ratio(sizes[:i], x, y, dx, dy) >= worst_ratio(sizes[:(i+1)], x, y, dx, dy):
    i += 1
  current = sizes[:i]
  remaining = sizes[i:]
  (leftover_x, leftover_y, leftover_dx, leftover_dy) = leftover(current, x, y, dx, dy)
  return layout(current, x, y, dx, dy) + \
squarify(remaining, leftover_x, leftover_y, leftover_dx, leftover_dy)

def padded_squarify(sizes, x, y, dx, dy):
  rects = squarify(sizes, x, y, dx, dy)
  for rect in rects:
    pad_rectangle(rect)
  return rects

前一个代码显示的 squarify 函数可以用来显示非洲 GDP 排名前 12 的国家,如下代码所示:

import matplotlib.pyplot as plt
import matplotlib.cm
import random
import squarify

x = 0.
y = 0.
width = 950.
height = 733.
norm_x=1000
norm_y=1000

fig = plt.figure(figsize=(15,13))
ax=fig.add_subplot(111,axisbg='white')

initvalues = [285.4,188.4,173,140.6,91.4,75.5,62.3,39.6,29.4,28.5, 26.2, 22.2]
values = initvalues
labels = ["South Africa", "Egypt", "Nigeria", "Algeria", "Morocco",
"Angola", "Libya", "Tunisia", "Kenya", "Ethiopia", "Ghana", "Cameron"]

colors = [(214,27,31),(229,109,0),(109,178,2),(50,155,18), 
(41,127,214),(27,70,163),(72,17,121),(209,0,89), 
(148,0,26),(223,44,13), (195,215,0)] 
# Scale the RGB values to the [0, 1] range, which is the format matplotlib accepts. 
for i in range(len(colors)): 
  r, g, b = colors[i] 
  colors[i] = (r / 255., g / 255., b / 255.) 

# values must be sorted descending (and positive, obviously)
values.sort(reverse=True)

# the sum of the values must equal the total area to be laid out
# i.e., sum(values) == width * height
values = squarify.normalize_sizes(values, width, height)

# padded rectangles will probably visualize better for certain cases
rects = squarify.padded_squarify(values, x, y, width, height)

cmap = matplotlib.cm.get_cmap()

color = [cmap(random.random()) for i in range(len(values))]
x = [rect['x'] for rect in rects]
y = [rect['y'] for rect in rects]
dx = [rect['dx'] for rect in rects]
dy = [rect['dy'] for rect in rects]

ax.bar(x, dy, width=dx, bottom=y, color=colors, label=labels)

va = 'center'
idx=1

for l, r, v in zip(labels, rects, initvalues):
  x, y, dx, dy = r['x'], r['y'], r['dx'], r['dy']
  ax.text(x + dx / 2, y + dy / 2+10, str(idx)+"--> "+l, va=va,
     ha='center', color='white', fontsize=14)
  ax.text(x + dx / 2, y + dy / 2-12, "($"+str(v)+"b)", va=va,
     ha='center', color='white', fontsize=12)
  idx = idx+1
ax.set_xlim(0, norm_x)
ax.set_ylim(0, norm_y)
plt.show()

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_03_14.jpg

交互式可视化包

几年前除了 IPython 没有太多的交互工具。为了理解如何让任何可视化变得交互式,将它与现有工具(如 D3.js)进行比较是有意义的。D3.js 非常强大的原因之一是基于 JavaScript 的绘图框架可以使绘图呈现在网络上。此外,它还附带了所有可以轻松配置的事件驱动功能。

有两个可视化库被称为 BokehVisPy ,它们在今天可用的少数几个中很受欢迎。还有另一个工具叫做瓦卡里。这主要用于数据分析,在如何创建基于浏览器的可视化方面与 IPython 相似。 Ashiba 项目是由 Clayton Davis 在 Continuum 开发的另一个工具,但是由于 Continuum 的重点转移到了 Bokeh 和 Wakari,在过去的几年里,关于 Ashiba 的工作做得很少。

Bokeh

Bokeh 是一个用 Python 开发的交互式可视化库,旨在通过网络浏览器工作。Bokeh 这个名字来自哪里?这是一个日语单词,用来描述模糊或图像中不聚焦的部分。目标是开发一个非常类似 D3.js 美学的库;Bokeh 这个名字的选择似乎很匹配。Bokeh 写入 HTML5 Canvas 库,因此保证在支持 HTML5 的浏览器上工作。这很有用,因为您可能想要将基于 JavaScript 的图与 Python 进行比较。

我们不会详细说明这个工具。你可以在http://bokeh.pydata.org阅读和探索更多相关内容。然而,重要的是要知道 Bokeh 库的依赖关系。安装 Bokeh 库前,要求安装jsonschema,如下:

conda install jsonschema

Fetching package metadata: ....
Solving package specifications: .
Package plan for installation in environment /Users/MacBook/anaconda:

The following packages will be downloaded:

 package                    |            build
 ---------------------------|-----------------
 jsonschema-2.4.0           |           py27_0          51 KB

The following NEW packages will be INSTALLED:

 jsonschema: 2.4.0-py27_0

Proceed ([y]/n)?

使用 Bokeh、pandas、SciPy、matplotlib 和 ggplot 的交互式可视化示例可在上找到。

粘性

VisPy 是一个用于 2D 或三维绘图的可视化库,具有交互性和高性能。您可以利用 OpenGL 知识快速创建可视化。它也有不一定需要深入了解 OpenGL 的方法。有关更多信息,您可以阅读位于【vispy.org】的文档。

为了安装 VisPy 库,可以尝试conda install vispy命令,但它很可能会响应 binstar 搜索–t conda vispy的建议。以下代码是列表中的代码之一:

conda install --channel https://conda.binstar.org/asmeurer vispy

使用此命令,您将获得以下响应:

Fetching package metadata: ......
Solving package specifications: .
Package plan for installation in environment /Users/MacBook/anaconda:

The following packages will be downloaded:

 package                    |            build
 ---------------------------|-----------------
 numpy-1.8.2                |           py27_0         2.9 MB
 vispy-0.3.0                |       np18py27_0         679 KB
 ------------------------------------------------------------
 Total:         3.6 MB

The following NEW packages will be INSTALLED:

 vispy: 0.3.0-np18py27_0

The following packages will be DOWNGRADED:

 numpy: 1.9.2-py27_0 --> 1.8.2-py27_0 

Proceed ([y]/n)?

VisPy 的图库收藏中有很多例子。可以在【http://vispy.org/gloo.html?highlight=gloo#module-vispy.gloo】查看使用vispy.gloo命令和 GLSL 阴影代码的点显示的一个特定示例。

总结

现在有一套适合 Python 开发人员的工具和包。Python 有一个很大的标准库。这通常被认为是 Python 最大的优势之一。它有创建图形用户界面的模块,连接到关系数据库,伪随机数发生器,具有任意精度小数的算法,操作正则表达式。此外,还有绘制 2D 和三维图形的高性能软件包、机器学习和统计算法等。

我们已经看到,集成开发环境工具(如 Canopy 和 Anaconda)从计算和可视化的角度以及其他许多领域利用了高效的开发工作。有许多有效的方法来使用这些工具产生可视化方法。在接下来的几章中,将展示这些工具和包的有趣示例。

四、数值计算和交互式绘图

高性能数值计算领域位于许多学科和技能的十字路口。为了在今天成功地使用高性能计算,它需要编程、数据科学和应用数学的知识和技能。除此之外,计算问题的有效实现需要对处理和存储设备有所了解。

近年来,计算在科学中的作用已经发展到不同的水平。编程语言(如 R 和 MATLAB)在学术研究和科学计算中很常见。如今,Python 在科学计算中扮演着重要角色,这是有充分理由的。Python 社区汇集了许多高效的工具和包,不仅被研究社区使用,而且被成功的商业组织使用,如雅虎、谷歌、脸书和亚马逊。

科学计算中广泛使用的软件包有两种。分别是数值 Python 包 ( NumPy )和科学 Python 包 ( SciPy )。NumPy 因其高效的数组,尤其是易于索引而广受欢迎。在以下各节中,我们将讨论以下主题:

  • NumPy、SciPy 和 MKL 函数
  • 数字索引和逻辑索引
  • 数据结构—堆栈、队列、元组、集合、尝试和字典
  • 使用 matplotlib 可视化绘图,等等
  • 用 NumPy 和 SciPy 进行优化和插值,并举例说明
  • 将 Cython 与 NumPy 相结合以及 Cython 的优势

NumPy、SciPy 和 MKL 函数

几乎所有的科学和数值计算都需要用向量和矩阵的形式来表示数据,NumPy 用数组来处理所有这些。

NumPy 和 SciPy 是 Python 的计算模块,在预编译的快速函数中提供方便的数学和数值方法。NumPy 包提供了基本的例程来操作大型数组和矩阵的数字数据。SciPy 包扩展了 NumPy,用应用数学技术收集有用的算法。在 NumPy 中, ndarray 是一个数组对象,它表示具有已知大小的多维齐次项目数组。

NumPy

NumPy 不仅使用数组对象,还使用可以方便用于计算的线性代数函数。它提供了阵列和相关阵列功能的快速实现。使用数组对象,可以执行包括矩阵乘法、向量和矩阵转置、求解方程组、执行向量乘法和归一化等操作。

NumPy 通用函数

通用功能( ufunc )是通过每个元素、支持类型铸造和其他几个标准特征在ndarrays上运行的功能。换句话说,ufunc是接受标量输入并产生标量输出的函数的矢量化包装器。许多内置函数都是在编译好的 C 代码中实现的,这使得它更快。

NumPy 通用函数比 Python 函数更快,因为循环是在编译代码中执行的。此外,因为数组是类型化的,所以在任何类型的计算发生之前就知道它们的类型。

这里显示了一个对每个元素进行操作的简单示例ufunc:

import numpy as np
x = np.random.random(5)
print x
print x + 1   # add 1 to each element of x

[ 0.62229809  0.18010463  0.28126201  0.30701477  0.39013144] 
[ 1.62229809  1.18010463  1.28126201  1.30701477  1.39013144]

其他例子还有np.addnp.subtract

NumPy 的ndarray类似于 Python 中的列表,但它在只存储同类对象时相当严格。换句话说,使用 Python 列表,可以混合元素类型,例如第一个元素作为数字,第二个元素作为列表,下一个元素作为另一个列表(或字典)。对于大尺寸阵列来说,在操作ndarray的元件方面的性能明显更快,这将在这里进行演示。这里的例子表明它更快,因为我们将测量运行时间。然而,对于对 C 语言中的 NumPy 实现感兴趣的读者来说,在网站上可以找到关于这个实现的文档。

import numpy as np

arr = np.arange(10000000)
listarr = arr.tolist()

def scalar_multiple(alist, scalar):
    for i, val in enumerate(alist):
        alist[i] = val * scalar
    return alist

# Using IPython's magic timeit command
timeit arr * 2.4
10 loops, best of 3: 31.7 ms per loop
# above result shows 31.7 ms (not seconds)

timeit scalar_multiple(listarr, 2.4)
1 loops, best of 3: 1.39 s per loop
# above result shows 1.39 seconds (not ms)

在前面的代码中,每个数组元素占用 4 个字节。因此,一百万个整数数组占用大约 44 MB 的内存,列表使用 711 MB 的内存。但是,数组对于小的集合大小来说速度较慢,但是对于大的集合大小来说,它们使用的内存空间较少,并且比列表快得多。

NumPy 附带了许多有用的函数,大致分为三角函数、算术函数、指数和对数函数以及各种函数。在众多的杂函数中,线性卷积的convolve()和线性插值的interp()比较流行。此外,对于大多数涉及等间距数据的实验工作来说,linspace()random.rand()函数是被广泛使用的几个函数之一。

塑造和重塑手法

改变现有数组的形状比用新形状从旧数据创建新数组更有效。在第一个示例中,重塑发生在内存中(数组不存储在变量中),而在下面的代码中,数组首先存储在变量 a 中,然后 a 被重塑:

import numpy as np

np.dandom.rand(2,4)
array([[ 0.96432148,  0.63192759,  0.12976726,  0.56131001], 
    [    0.27086909,  0.92865208,  0.27762891,  0.40429701]])

np.random.rand(8).reshape(2,4)
array([[ 0.39698544,  0.88843637,  0.66260474,  0.61106802], 
       [ 0.97622822,  0.47652548,  0.56163488,  0.43602828]]) 

在上例中,创建8值后,它们被重新整形为有效的选择维度,如以下代码所示:

#another example
a = np.array([[11,12,13,14,15,16],[17,18,19,20,21,22]])

print a
[[11, 12, 13, 14, 15, 16], [17, 18, 19, 20, 21, 22]]

# the following shows shape is used to know the dimensions
a.shape
(2,6)

#Now change the shape of the array
a.shape=(3,4)
print a
[[11 12 13]  [14 15 16]  [17 18 19]  [20 21 22]]

xrange代替range,因为循环更快,避免了整数列表的存储;它只是一个接一个地产生它们。形状和重塑的对立面是ravel(),如下图所示:

#ravel example
a = np.array([[11,12,13,14,15,16],[17,18,19,20,21,22]])

a.ravel()
array([11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22])

插值的一个例子

以下是使用interp()进行插值的示例:

n=30 

# create n values of x from 0 to 2*pi 
x = np.linspace(0,2*np.pi,n) 

y = np.zeros(n) 

#for range of x values, evaluate y values
for i in xrange(n):    
   y[i] = np.sin(x[i])

下图显示的图像是简单正弦曲线插值的结果:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_01.jpg

以下代码显示了使用和不使用插值绘制曲线:

import numpy as np
import matplotlib.pyplot as plt

# create n values of x from 0 to 2*pi 
x = np.linspace(0, 8*np.pi, 100)

y = np.sin(x/2)

#interpolate new y-values 
yinterp = np.interp(x, x, y)

#plot x,y values using circle marker (line style)
plt.plot(x, y, 'o')  

#plot interpolated curve using dash x marker
plt.plot(xvals, yinterp, '-x')  

plt.show()

向量化函数

通过 NumPy 和 SciPy 中的vectorize()向量化函数非常有效。矢量化能够通过逐元素应用相同的规则,将以标量为参数的函数转换为以数组为参数的函数。我们将在这里用两个例子来证明这一点。

第一个示例使用一个接受三个标量参数的函数来生成一个接受三个数组参数的矢量化函数,如以下代码所示:

import numpy as np

def addition(x, y, z):
    return x + y + z

def addpoly():
    i = np.random.randint(25)
    poly1 = np.arange(i, i+10)
    i = np.random.randint(25) 
    poly2 = np.arange(i, i+10)
    poly3 = np.arange(10, 18)
    print poly1
    print poly2
    print poly3
    print '-' * 32
    vecf = np.vectorize(addition)
    print vecf(poly1,poly2,poly3)

addpoly()

[ 4  5  6  7  8  9 10 11 12 13]
[13 14 15 16 17 18 19 20 21 22]
[10 11 12 13 14 15 16 17 18 19]
--------------------------------
[27 30 33 36 39 42 45 48 51 54]

注意arrange是内置 Python range函数的数组值版本。

第二个示例使用一个接受标量参数的函数来生成一个接受数组参数的矢量化函数,如以下代码所示:

import numpy as np

def posquare(x):
  if x >= 0: return x**2
  else: return -x

i = np.random.randint(25)
poly1 = np.arange(i,i+10)

print poly1
vecfunc = vectorize(posquare, otypes=[float]) 
vecfunc(poly1)

[14 15 16 17 18 19 20 21 22 23]
array([ 196., 225., 256., 289., 324., 361., 400., 441., 484., 529.])

还有另一个例子,借助于示例代码很有意思。此示例显示了用常数增加数组元素的三种方法,并测量运行时间以确定哪种方法更快:

import numpy as np
from time import time

def incrembyone(x):
    return x + 1

dataarray=np.linspace(1,5,1000000)

t1=time()
lendata = len(dataarray)
print "Len = "+str(lendata)
print dataarray[1:7]
for i in range(lendata):
    dataarray[i]+=1
print " time for loop (No vectorization)->" + str(time() - t1)

t2=time()

vecincr = np.vectorize(incrembyone) #1 
vecincr(dataarray) #2          
print " time for vectorized version-1:" + str(time() - t2)
t3 = time()

# This way to increment array elements with one line
# is pretty powerful, accomplishes same thing as #1 and #2
dataarray+=1  # how does this achieve the results
print dataarray[1:7]
print " time for vectorized version-2:" + str(time() - t3)

Len = 1000000
 [ 1.000004 1.000008 1.000012 1.000016 1.00002 1.000024]  
time for loop (No vectorization)->0.473765850067  
time for vectorized version-1:0.221153974533 # half the time

[ 3.000004 3.000008 3.000012 3.000016 3.00002 3.000024]  
time for vectorized version-2:0.00192213058472 # in fraction time

除了矢量化技术,还有另一种简单的编码实践可以让程序更高效。如果循环中使用了前缀符号,最好创建一个本地别名,并在循环中使用该别名。这里显示了一个这样的例子:

fastsin = math.sin

x = range(1000000)
for i in x:
    x[i] = fastsin(x[i])

NumPy 线性代数综述

以下是 NumPy 在线性代数中提供的一些著名函数的列表:

|

名字

|

描述

|
| — | — |
| dot(a,b) | 这是两个数组的点积 |
| linalg.norm(x) | 这是矩阵或向量范数 |
| linalg.cond(x) | 这指定了条件编号 |
| linalg.solve(A,b) | 这解决了线性系统Ax=b |
| linalg.inv(A) | 这表示A的倒数 |
| linalg.pinv(A) | 这指定了A的伪逆 |
| linalg.eig(A) | 这些是平方的特征值/向量A |
| linalg.eigvals(A) | 这些是一般A的特征值 |
| linalg.svd(A) | 这是一个奇异值分解 |

黑桃

NumPy 已经有很多方便的函数可以用于计算。那么,我们为什么需要 SciPy?SciPy 是用于数学、科学和工程的 NumPy 的扩展,它有许多软件包可用于线性代数、积分、插值、快速傅立叶变换、大型矩阵操作、统计计算等。下表显示了这些包的简要描述:

|

分装

|

功能简述

|
| — | — |
| scipy.cluster | 这指定了用于聚类的函数,包括矢量量化和 k 均值。 |
| scipy.fftpack | 这表示快速傅立叶变换的功能。 |
| scipy.integrate | 这指定了使用梯形、辛普森、龙贝格和其他方法进行数值积分的函数。它还规定了积分常微分方程的方法。人们可以用函数quaddblquadtplquad对函数对象执行单、双和三次积分。 |
| scipy.interpolate | 表示具有离散数值数据的插值对象以及线性和样条插值的函数和类。 |
| scipy.linalg | 这是 NumPy 中包装linalg的包装。NumPy 的所有功能都是scipy.linalg的一部分,还有其他几个功能。 |
| scipy.optimize | 这表示最大化和最小化函数,包括奈德-米德单纯形法、鲍威尔法、共轭梯度 BFGS 法、最小二乘法、约束优化器、模拟退火法、牛顿法、二等分法、布赖登-安德森法和线搜索法。 |
| scipy.sparse | 这指定了可以处理大型稀疏矩阵的函数。 |
| scipy.special | 这对于计算物理有特殊的作用,如椭圆、贝塞尔、伽马、β、超几何、抛物线、圆柱、马蒂厄和球面波。 |

除了前面列出的子包,SciPy 还有一个scipy.io包,该包具有加载名为spio.loadmat()的矩阵、保存名为spio.savemat()的矩阵以及通过scio.imread()读取图像的功能。当需要用 Python 开发计算程序时,最好检查 SciPy 文档,看看它是否包含已经完成预期任务的函数。

我们来看一个使用scipy.polyId()的例子:

import scipy as sp

# function that multiplies two polynomials
def multiplyPoly():  
    #cubic1 has coefficients 3, 4, 5 and 5 
    cubic1 = sp.poly1d([3, 4, 5, 5])  

    #cubic2 has coefficients 4, 1, -3 and 3
    cubic2 = sp.poly1d([4, 1, -3, 3]) 

    print cubic1   
    print cubic2 

    print '-' * 36

    #print results of polynomial multiplication
    print cubic1 * cubic2

multiplyPoly()  # produces the following result

   3     2
3 x + 4 x + 5 x + 5
   3     2
4 x + 1 x - 3 x + 3
------------------------------------
    6      5      4      3     2
12 x + 19 x + 15 x + 22 x + 2 x + 15  

结果与传统的逐项乘法相匹配,如下所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_03.jpg

因此,多项式表示可以用于积分、微分和其他计算物理。这些功能以及 NumPy、SciPy 和其他包扩展中的更多功能清楚地表明,Python 是 MATLAB 的另一个替代品,因此在一些学术环境中使用。

SciPy 提供了许多不同类型的插值。以下示例使用interpolate.splev,其使用 B 样条及其导数和interpolate.splprep用于二维曲线(一般为 N 维)的 B 样条表示:

import numpy as np 
import matplotlib.pyplot as plt
import scipy as sp

t = np.arange(0, 2.5, .1)
x = np.sin(2*np.pi*t)
y = np.cos(2*np.pi*t)

tcktuples,uarray = sp.interpolate.splprep([x,y], s=0)
unew = np.arange(0, 1.01, 0.01)

splinevalues = sp.interpolate.splev(unew, tcktuples)

plt.figure(figsize=(10,10))
plt.plot(x, y, 'x', splinevalues[0], splinevalues[1], 
np.sin(2*np.pi*unew), np.cos(2*np.pi*unew), x, y, 'b')

plt.legend(['Linear', 'Cubic Spline', 'True'])
plt.axis([-1.25, 1.25, -1.25, 1.25])
plt.title('Parametric Spline Interpolation Curve')

plt.show()

下图是使用 SciPy 和 NumPy 进行样条插值的结果:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_02.jpg

让我们看一下数值积分中的一个例子,并使用一些 SciPy 函数(如 Simpson 和 Romberg)求解线性方程,并将这些函数与 NumPy 梯形函数进行比较。我们知道,当f(x)= 9–x2这样的函数从-3积分到3时,我们期望 36 个单位,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_08.jpg

上图显示了 9-x2 函数(沿 Y 轴对称)。数学上,从 -33 的积分是从 03 的积分的两倍。我们如何使用 SciPy 进行数值积分?下面的代码显示了一种使用 NumPy 中的梯形方法执行该操作的方法:

import numpy as np
from scipy.integrate import simps, romberg

a = -3.0; b = 3.0;
N = 10  

x = np.linspace(a, b, N)
y = 9-x*x
yromb = lambda x: (9-x*x)

t = np.trapz(y, x)
s = simps(y, x)
r = romberg(yromb, a, b)

#actual integral value
aiv = (9*b-(b*b*b)/3.0) - (9*a-(a*a*a)/3.0)

print 'trapezoidal = {0} ({1:%} error)'.format(t, (t - aiv)/aiv)
print 'simpsons = {0} ({1:%} error)'.format(s, (s - aiv)/aiv)
print 'romberg  = {0} ({1:%} error)'.format(r, (r - aiv)/aiv)
print 'actual value = {0}'.format(aiv)

trapezoidal = 35.5555555556 (-1.234568% error)
simpsons = 35.950617284 (-0.137174% error)
romberg  = 36.0 (0.000000% error)
actual value = 36.0

线性方程的一个例子

让我们尝试用三个变量 xyz 求解一组线性方程,如下所示:

  • x+2y–z = 2
  • 2x–3y+2z = 2
  • 3x+y–z = 2

NumPy 提供了一种求解线性方程的方便方法np.linalg.solve()。然而,输入应该是矢量形式的。下面的程序展示了如何求解线性方程。

import numpy as np

# Matrix A has coefficients of x,y and z
A = np.array([[1, 2, -1],
              [2, -3, 2],
              [3, 1, -1]])
#constant vector 
b = np.array([2, 2, 2])

#Solve these equations by calling linalg.solve
v = np.linalg.solve(A, b)

# v is the vector that has solutions
print "The solution vector is "
print v
# Reconstruct Av to see if it produces identical values 
print np.dot(A,v) == b

The solution vector is
[ 1\.  2\.  3.]
[ True  True  True]

注意np.dot(A,v)是矩阵乘法(不是A*v)。解向量v = [1,2,3]是正确的预期结果。

矢量化的数值导数

现在作为本节的最后一个例子,我们将看看 NumPy 提供的矢量化数字导数。应用微分的商法则,我们确实知道导数是https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_31.jpg。但是,通过应用 Python 中的矢量化方法来计算没有循环的导数,我们将看到以下代码:

import numpy as np 
import matplotlib.pyplot as plt

x = np.linspace(-np.pi/2, np.pi/2, 44)
y = 1/(1+np.cos(x)*np.cos(x))
dy_actual = np.sin(2*x)/(1+np.cos(x)*np.cos(x))**2

fig = plt.figure(figsize=(10,10))
ax=fig.add_subplot(111,axisbg='white')

# we need to specify the size of dy ahead because diff returns 
dy = np.zeros(y.shape, np.float) #we know it will be this size
dy[0:-1] = np.diff(y) / np.diff(x)
dy[-1] = (y[-1] - y[-2]) / (x[-1] - x[-2])

plt.plot(x,y, linewidth=3, color='b', label='actual function')
plt.plot(x,dy_actual,label='actual derivative', linewidth=2, color='r')
plt.plot(x,dy,label='forward diff', linewidth=2, color='g')
plt.legend(loc='upper center')
plt.show()

在下面的例子中,我们可以看到你如何在同一个图中画出实际函数、它的导数和向前差。将实际导数插入dy_actual,使用从 NumPy 计算的diff()计算正向差。

以下图表是该程序的结果:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_10.jpg

MKL 函数

英特尔的 MKL 函数提供向量和矩阵的高性能例程。此外,它们还包括快速傅立叶变换函数和矢量统计函数。这些功能已经过增强和优化,可在英特尔处理器上高效工作。对于 Anaconda 用户,Continuum 已经将这些 FFT 函数打包到 Python 库的二进制版本中,用于 MKL 优化。然而,作为 Anaconda Accelerate 包的一部分,MKL 优化作为一个附加组件提供。此处的图表显示了没有 MKL 时的慢度差异:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_04.jpg

上图取自https://store.continuum.io/cshop/mkl-optimizations/

对于更大的阵列输入,MKL 在性能上有显著提升,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_05.jpg

上图取自https://software . Intel . com/en-us/articles/numpsycpiy-with-Intel-mkl

Python 的性能

Python 程序员为了性能考虑,经常尝试用 C 语言重写自己最里面的循环,从 Python 中调用编译好的 C 函数。有许多项目旨在使这种优化变得更容易,例如 Cython。然而,最好是让他们现有的 Python 代码更快,而不依赖于另一种编程语言。

几乎没有其他选项可以提高 Python 中计算密集型程序的性能:

  • 使用 numapro:这是来自 Continuum Analytics 的 Python 编译器,可以编译 Python 代码,以便在支持 CUDA 的 GPU 或多核 CPU 上执行。该编译代码运行本机编译代码,比解释代码快几倍。Numbapro 通过在运行时启用编译来工作(这是及时准时编译)。有了 Numbapro,可以编写标准的 Python 函数,并在支持 CUDA 的 GPU 上运行它们。Numbapro 是为面向数组的计算任务而设计的,比如广泛使用的 NumPy 库。Numbapro 是 Numba 的增强版本,是 Anaconda Accelerate 的一部分,Anaconda Accelerate 是 Continuum Analytics 的商业许可产品。
  • 使用 Scipy.weave :这是一个模块,允许您插入 C 代码的片段,并将 NumPy 数组无缝传输到 C 层。它也有一些高效的宏。
  • 使用多核方法:Python 2.6 或更高版本的多处理包提供了一种相对简单的机制来创建子进程。现在连台式电脑都有多核处理器;让所有处理器工作是有意义的。这比使用线程要简单得多。
  • 使用称为池的进程池:这是多处理包中的另一个类。使用 pool,您可以定义要在池中创建的工作进程的数量,然后传递一个包含每个进程参数的 iterable 对象。
  • 在分布式计算包(如 Disco) 中使用 Python:这是一个轻量级、开源的分布式计算框架,基于 MapReduce 范式(http://discoproject.org)。其他类似的包有 Hadoop Streaming、mrjob、dumbo、Hadoop 和 pydoop。

标量选择

标量选择是从数组中选择元素的最简单的方法,对于一维数组使用[rowindex],对于二维数组使用[rowindex, columnindex]等等来实现。下面是显示数组元素引用的简单代码:

import numpy as np
x = np.array([[2.0,4,5,6], [1,3,5,9]])

x[1,2]
5.0

纯标量选择总是返回单个元素,而不是数组。所选元素的数据类型与所选内容中使用的数组的数据类型匹配。标量选择也可用于为数组元素赋值,如以下代码所示:

x[1,2] = 8

x
array([[2, 4, 5, 6],[1, 3, 8, 9]])

切片

数组可以像列表和元组一样被切片。数组切片与列表切片相同,只是语法更简单。使用[ : , :, ... :]语法对数组进行切片,其中数组的维数决定切片的大小,除了省略切片的这些维数,所有元素都被选中。比如b是三维阵列,b[0:2]b[0:2,:,:]一样。切片有速记符号。一些常见的有:

  • **:和:**同 0:n:1 ,其中 n 为阵长
  • m:和 m:n:m:n:1 相同,其中 n 为阵长
  • :n:0:n:1
  • **:d:**同 0:n:d ,其中 n 为阵长

所有这些切片方法都引用了数组的用法。这也适用于列表。对一维数组进行切片与对简单列表进行切片是一样的(因为可以看到一维数组相当于一个列表),并且所有切片操作的返回类型都与被切片的数组相匹配。以下是显示阵列切片的简单机制:

x = array([5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20])

# interpret like this – default start but end index is 2
y = x[:2]
array([5, 6])

# interpretation – default start and end, but steps of 2
y = x[::2]
array([5,7,9,11,13,15,17,19])

如果具有一种数据类型的元素被插入到具有不同数据类型的数组中,NumPy 会尝试自动转换数据类型。例如,如果数组具有整数数据类型,那么在数组中放置一个浮点数会导致该浮点数被截断,并将其存储为整数。这可危险了;因此,在这种情况下,数组应该被初始化为包含 floats,除非有充分的理由考虑决定使用不同的数据类型。此示例显示,即使一个元素是 float,而其余的是 integer,为了使其正常工作,也假定它是 float 类型:

a = [1.0, 2,3,6,7]
b = array(a)

b.dtype
dtype('float64')

用平板切片

矩阵中的数据以行为主的顺序存储,这意味着元素首先通过沿行计数,然后沿列计数进行索引。例如,在下面的矩阵中,有三行三列;元素的读取顺序为 4、5、6、7、8、9、1、2、3 (每行、每列):

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_06.jpg

线性切片按照元素读取的顺序为数组的每个元素分配一个索引。在二维数组或列表中,线性切片的工作方式是首先在行中计数,然后在列中计数。为了使用线性切片,必须使用flat函数,如下代码所示:

a=array([[4,5,6],[7,8,9],[1,2,3]])
b = a.flat[:]

print b
[4, 5, 6, 7, 8, 9, 1, 2, 3]

数组索引

来自 NumPy 数组的元素可以使用四种方法进行选择:标量选择、切片、数值索引和逻辑(或布尔)索引。标量选择和切片是访问数组中元素的基本方法,这里已经讨论过了。数字索引和逻辑索引密切相关,允许更灵活的选择。数字索引使用位置列表或数组来选择元素,而逻辑索引使用包含布尔值的数组来选择元素。

数值索引

数值索引是切片记数法的替代方法。数值索引中的思想是使用坐标来选择元素。这类似于切片。使用数字索引创建的数组创建数据的副本,而切片只是数据的视图,而不是副本。为了性能,应该使用切片。切片类似于一维数组,但切片的形状由切片输入决定。

一维数组中的数值索引使用数值索引值作为数组中的位置(从 0 开始的索引),并返回与数值索引具有相同维度的数组。

请注意,数字索引可以是列表或 NumPy 数组,并且必须包含整数数据,如以下代码所示:

a = 10 * arange(4.0)
array([0.,10.,20.,30.])

a[[1]]  # arrays index is list with first element 
array([ 10.])

a[[0,3,2]] # arrays index are 0-th, 3-rd and 2-nd
array([  0.,  30.,  20.])

sel = array([3,1,4,2,3,3])  # array with repetition
a[sel]
array([ 30\.  10\.   0\.  20\.  30\.  30.])

sel = array([4,1],[3,2]])
a[sel]
array([[ 30.,10.], [ 0.,20.]])

这些示例表明,数值索引决定元素位置,数值索引数组的形状决定输出的形状。

类似于切片,数值索引可以使用flat函数进行组合,以使用数组的行主顺序从数组中选择元素。使用平面进行数值索引的行为与在底层数组的平面版本上使用数值索引的行为相同。这里显示了几个示例:

a = 10 * arange(8.0)
array([  0.,  10.,  20.,  30.,  40., 50., 60., 70.])

a.flat[[3,4,1]]
array([ 30., 40., 10.])

a.flat[[[3,4,7],[1,5,3]]]
array([[ 30., 40., 70.], [ 10., 50., 30.]])

逻辑索引

逻辑索引不同于切片和数值索引;它而是使用逻辑索引来选择元素、行或列。逻辑索引就像电灯开关,不是真就是假。纯逻辑索引使用与用于选择的数组大小相同的逻辑索引数组,并且总是返回一维数组,如以下代码所示:

x = arange(-4,5)

x < 0 
array([True, True, True, True, False, False, False, False, False], dtype=bool)

x[x>0]
array([1, 2, 3, 4])

x[abs(x) >= 2]  
array([-4, -3, -2,  2,  3,  4])

#Even for 2-dimension it still does the same
x = reshape(arange(-8, 8), (4,4))
x
array([[-8, -7, -6, -5], [-4, -3, -2, -1], [ 0,  1,  2,  3], [ 4,  5,  6,  7]])

x[x<0]
array([-8, -7, -6, -5, -4, -3, -2, -1])

下面是另一个演示逻辑索引的例子:

from math import isnan
a = [[3, 4, float('NaN')], [5, 9, 8], [3, 3, 2], [9, -1, float('NaN')]]

list2 = [3, 4, 5, 6]
list1_valid = [elem for elem in list1 if not any([isnan(element) for element in elem])]

list1_valid
[[3, 7, 8], [1, 1, 1]] 

list2_valid = [list2[index] for index, elem in enumerate(list1) if not any([isnan(element) for element in elem])]

list2_valid
 [4, 5]

其他数据结构

Python 具有诸如堆栈、列表、集合、序列、元组、列表、堆、数组、字典和 deque 等数据结构。我们已经在试图理解数组时讨论了列表。元组通常比列表更节省内存,因为它们是不可变的。

书库

list 方法作为栈使用非常方便,已知是一种抽象数据类型,其原理是操作后进先出。已知的操作包括使用append()在堆栈顶部添加项目,使用pop()从堆栈顶部提取项目,以及使用remove(item-value)移除项目,如以下代码所示:

stack = [5, 6, 8]
stack.append(6)
stack.append(8)

stack
[5, 6, 8, 6, 8]

stack.remove(8)
stack
[5, 6, 6, 8]

stack.pop()
8

stack.remove(8)
Traceback (most recent call last): 
File "<ipython-input-339-61d6322e3bb8>", line 1, in <module>     stack.remove(8)
  ValueError: list.remove(x): x not in list

pop()功能效率最高(恒定时间),因为所有其他元素都保留在它们的位置。但是,参数化版本pop(k)删除了列表中 k < n 索引处的元素,将所有后续元素转移到以填补删除后的空白。该操作的效率是线性的,因为移动量取决于索引 k 的选择,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_07.jpg

元组

元组是一系列看起来类似于列表的不可变对象。元组是异构的数据结构,这意味着它们的元素有不同的含义,而列表是一个同质的元素序列。元组有结构,列表有顺序。元组的一些示例是星期几、课程名称和评分标准,如以下代码所示:

#days of the week
weekdays = ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")

#course names
courses = ("Chemistry", "Physics", "Mathematics", "Digital Logic", "Circuit Theory")

#grades
grades = ("A+", "A", "B+", "B", "C+", "C", "I")

元组有不可变的对象。这意味着您不能更改或从元组中移除它们。但是,元组可以完全删除,例如,“del grades”将删除此元组。此后,如果尝试使用该元组,将会出现错误。以下是内置的元组函数:

  • cmp(tup1, tup2):这个函数可以用来比较二元组的元素
  • len(tuple):这个函数可以用来获取元组的总长度
  • max(tuple):这个函数可以用来确定元组中的最大值
  • min(tuple):这个函数可以用来确定元组中的最小值
  • tuple(lista):该功能可用于将lista转换为tuple

Python 有一个max()函数,其行为与数值的预期一致。然而,如果我们传递一个字符串列表,max()返回最长的项目。

weekdays = ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
print max(weekdays) 
Wednesday  

类似地min()对于字符串也有相同的行为。

print min(weekdays) 
Friday

当我们需要找到一个数组或列表中有多少元素时,len()是一个很方便的方法。

len(weekdays)
7

集合与列表相似,但在两个方面有所不同。首先,与列表(按位置或索引排序)相比,它们是一个无序的集合。其次,它们没有副本(如果你知道集合的数学定义)。用于集合的符号显示在以下命令中:

setoftrees = { 'Basswood', 'Red Pine', 'Chestnut', 'Gray Birch', 'Black Cherry'} 

newtree = 'Tulip Tree' 
if newtree not in setoftrees:  setoftrees.add(newtree)

现在有了这个命令,你可以看到setoftrees上是什么:

setoftrees  # typing this shows list of elements shown below
{'Basswood', 'Black Cherry', 'Chestnut', 'Gray Birch', 'Red Pine', 'Tulip Tree'}

然后,使用适当的拼写构建charsinmathcharsinchem,如以下代码所示

#example of set of operation on letters
charsinmath = set('mathematics')
charsinchem = set('chem')

现在,让我们试着看看这些集合中的值:

Charsinmath # typing this shows letters in charsinmath
{'a', 'c', 'e', 'h', 'i', 'm', 's', 't'}

charsinchem # typing this shows letters in charsinchem
{'c', 'e', 'h', 'm'}

为了找到设置的差异,我们需要显示charsinmath – charsinchem 如下:

# take away letters from charsinchem from charsinmath
charsinmath - charsinchem
{'a', 'i', 's', 't'}

队列

就像堆栈一样,使用列表作为队列是可能的。但是的区别是可以在列表的末尾或者列表的开头添加或者删除元素。虽然在列表的末尾添加和删除是有效的,但是从头开始做同样的事情是无效的,因为在这种情况下,元素必须被转移。

幸运的是,Python 的集合包中有deque,可以使用append()pop()appendleft()popleft()高效地实现从两端添加和移除元素,如以下代码所示:

from collections import deque

queue = deque(["Daniel", "Sid", "Mathew",  "Michael"]) 
queue.append("Dirk")      # Dirk arrives 
queue.append("Monte")   # Monte arrives queue

queue
deque(['Daniel', 'Sid', 'Mathew', 'Michael', 'Dirk', 'Monte'])

queue.popleft()  
'Daniel'  

queue.pop() 
'Monte'

queue.appendleft('William')
queue
deque(['William', 'Sid', 'Mathew', 'Michael', 'Dirk'])

queue.append('Lastone')
queue
deque(['William', 'Sid', 'Mathew', 'Michael', 'Dirk', 'Lastone'])

词典

字典是由键/值对组成的无序数据值的集合,它具有基于键作为索引访问值的独特优势。问题是,如果键是字符串,那么索引是如何工作的?密钥必须是可散列的:对密钥应用散列函数来提取存储值的位置。换句话说,散列函数接受一个键值并返回一个整数。字典然后使用这些整数(或哈希值)来存储和检索值。这里显示了一些示例:

#example 1: Top 10 GDP of Africa
gdp_dict = { 'South Africa': 285.4, 'Egypt': 188.4, 'Nigeria': 173, 'Algeria': 140.6, 'Morocco': 91.4, 'Angola': 75.5, 'Libya': 62.3, 'Tunisia': 39.6, 'Kenya': 29.4, 'Ethiopia': 28.5, 'Ghana': 26.2, 'Cameron': 22.2}

gdp_dict['Angola']
75.5

#example 2: English to Spanish for numbers one to ten
english2spanish = { 'one' : 'uno', 'two' : 'dos', 'three': 'tres', 
'four': 'cuatro', 'five': 'cinvo', 'six': 'seis', 'seven': 'seite',  'eight': 'ocho', 'nine': 'nueve', 'ten': 'diez'}

english2spanish['four'] 
'cuatro'

密钥应该是不可变的,以具有可预测的哈希值;否则,哈希值更改将导致不同的位置。此外,不可预测的事情可能会发生。默认字典不会按照插入的顺序保存值;因此,通过在插入后迭代,键/值对的顺序是任意的。

Python 的 collections 包有一个等价的OrderedDict()函数,它保持插入顺序中的对的顺序。默认字典和有序字典的另一个区别是,在前者中,如果它们有一组相同的键/值对(不一定是相同的顺序),等式总是返回true,而在后者中,只有当它们有一组相同的键/值对并且它们处于相同的顺序时,等式才返回true。下面的例子说明了这一点:

# using default dictionary
dict = {}

dict['cat-ds1'] = 'Introduction to Data Structures'
dict['cat-ds2'] = 'Advanced Data Structures'
dict['cat-la1'] = 'Python Programming'
dict['cat-la2'] = 'Advanced Python Programming'
dict['cat-pda'] = 'Python for Data Analysis'
dict['cat-ps1'] = 'Data Science in Python'
dict['cat-ps2'] = 'Doing Data Science'

for key, val in dict.items():  print key,val

cat-ps1 Data Science in Python 
cat-ps2 Doing Data Science 
cat-pda Python for Data Analysis 
cat-la2 Advanced Python Programming 
cat-la1 Python Programming 
cat-ds1 Introduction to Data Structures 
cat-ds2 Advanced Data Structures

#using OrderedDict (inserting data the same way as before)
odict = OrderedDict()

odict['cat-ds1'] = 'Introduction to Data Structures'
odict['cat-ds2'] = 'Advanced Data Structures'
odict['cat-la1'] = 'Python Programming'
odict['cat-la2'] = 'Advanced Python Programming'
odict['cat-pda'] = 'Python for Data Analysis'
odict['cat-ps1'] = 'Data Science in Python'
odict['cat-ps2'] = 'Doing Data Science'

for key, val in odict.items():  print key,val

cat-ds1 Introduction to Data Structures 
cat-ds2 Advanced Data Structures 
cat-la1 Python Programming 
cat-la2 Advanced Python Programming 
cat-pda Python for Data Analysis 
cat-ps1 Data Science in Python 
cat-ps2 Doing Data Science

如果您必须实现类似这样的东西,那么在计算上最好使用 ISBN 作为关键字,而不是像在库中那样使用目录号。但是,可能有旧书没有 ISBN 因此,必须使用等效的唯一键/值来保持与其他具有 ISBN 号的新书的一致性。哈希值通常是一个数字,使用数字键,哈希函数可能比字母数字键容易得多。

矩阵表示的字典

通常有很多的例子,可以在有键/值关联的时候应用字典。例如,说明缩写和名称;其中一个可以是键,另一个可以是值,但是将缩写作为键会更有效。其他的例子有单词和单词计数或者城市名称和人口。字典真正有效的一个有趣的计算领域是稀疏矩阵的表示。

稀疏矩阵

我们来考察一下矩阵的空间利用率;对于使用列表表示的100×100矩阵,每个元素占用 4 个字节;因此,矩阵需要 40,000 字节,大约是 40 KB 的空间。然而,在这 40,000 个字节中,如果只有 100 个有非零值,其余的都为零,那么空间就被浪费了。现在,为了讨论简单起见,让我们考虑一个较小的矩阵,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_11.jpg

这个矩阵有大约 20%的非零值;因此,找到一种替代方法来表示矩阵的非零元素将是一个良好的开端。 1 有七个值, 23 各有五个值, 467 各有一个值。这可以表示如下:

A = {1: [(2,2),(6,6), (0,7),(1,8),(7,8),(3,9),(8,9)],
  2: [(5,2),(8,2),(6,3),(0,4),(0,9)],
  3: [(5,0),(8,0),(9,1),(1,3),(5,8)],
  4:[(1,1)], 6:[(2,0)], 7:[(2,5)]} 

然而,这种表示使得更难访问 A(i,j) th 值。有一种更好的方法可以用字典来表示这个稀疏矩阵,如下面的代码所示:

def getElement(row, col):
    if (row,col) in A.keys():
       r = A[row,col]
    else:
       r = 0
    return r

A={(0,4): 2, (0,7): 1, (1,1): 4, (1,3):3, (1,8): 1, (2,0): 6, (0,9): 2, (2,2):1, (2,5): 7, (3,9): 1, (5,0): 3, (5,2): 2, (5,8): 3, (6,3): 2, (6,6):1, (7,8): 1, (8,0): 3, (8,2): 2, (8,9): 1, (9,1): 3}

print getElement(1,3)
3

print getElement(1,2)
0

要访问矩阵 A(1,3) 处的元素,我们可以使用A【(1,3)】,但是如果该键不存在,它将抛出异常。为了使用键获取非零值,如果键不存在则返回0,我们可以使用名为getElement()的函数,如前面的代码所示。

可视化稀疏

借助方块图,我们可以直观地看到矩阵有多稀疏。下图显示了sparseDisplay()功能。这将为每个试图查看显示的矩阵条目使用方形框。黑色表示稀疏,而绿色表示非零元素:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_12.jpg

下面的代码演示了如何显示稀疏性:

import numpy as np
import matplotlib.pyplot as plt

"""
  SquareBox diagrams are useful for visualizing values of a 2D array,
  Where black color representing sparse areas.  
"""
def sparseDisplay(nonzero, squaresize, ax=None):
    ax = ax if ax is not None else plt.gca()

    ax.patch.set_facecolor('black')
    ax.set_aspect('equal', 'box')
    for row in range(0,squaresize):
      for col in range(0,squaresize):
        if (row,col) in nonzero.keys():
           el = nonzero[(row,col)]
           if el == 0:  color='black' 
           else:  color = '#008000'
           rect = plt.Rectangle([col,row], 1, 1, 
                   facecolor=color, edgecolor=color)
           ax.add_patch(rect)

    ax.autoscale_view()
    ax.invert_yaxis()

if __name__ == '__main__': 
    nonzero={(0,4): 2, (0,7): 1, (1,1): 4, (1,3): 3, (1,8): 1, 
(2,0): 6, (0,9): 2, (2,2): 1, (2,5): 7, (3,9): 1, (5,0): 3, 
(5,2): 2, (5,8): 3, (6,3): 2, (6,6): 1, (7,8): 1, (8,0): 3, (8,2): 2, (8,9): 1, (9,1): 3}

    plt.figure(figsize=(4,4))
    sparseDisplay(nonzero, 10)
    plt.show()

这只是显示稀疏矩阵的一个快速示例。假设您有一个只有几个非零值的 30 x 30 矩阵,那么显示看起来会有点类似于下图。就空间利用率而言,这种情况下节省了 97%。换句话说,矩阵越大,占用的空间越小,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_13.jpg

找到了用字典存储稀疏矩阵的方法后,你可能要记住不需要重新发明轮子。而且,考虑存储稀疏矩阵的可能性来理解字典的力量是有意义的。然而,真正推荐的是看看稀疏矩阵的 SciPy 和 pandas 包。在本书中,可能会有更多的机会在一些例子中使用这些方法。

记忆词典

记忆是计算科学中的一种优化技术,可以存储中间结果,否则会很昂贵。不是每个问题都需要记忆,但是当有一种通过调用函数来计算相同值的模式时,使用这种方法通常是有用的。可以使用这种方法的一个例子是在斐波那契函数的计算中,使用字典来存储已经计算的值,所以下次,您可以只搜索该值,而不是再次重新计算它,如以下代码所示:

fibvalues = {0: 0, 1: 1, 2:1, 3:2, 4:3, 5:5}

def fibonacci(n):
    if n not in fibvalues: 
        sumvalue = fibonacci(n-1) + fibonacci(n-2)
        fibvalues[n] = sumvalue  
    return fibvalues[n]

fibonacci(40)
102334155

print sorted(fibvalues.values())
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155]

#regular fibonacci without using dictionary
def fib(n):
   if n <= 1 : return 1
   sumval = fib(n-1)+fib(n-2)
   return sumval

fibvalues的字典对于防止重新计算斐波那契的值非常有用,但是fibcalled在这里仅用于说明通过使用字典,对于特定的 n 值,不能有一次以上的对fibonacci()的调用。通过比较fib()(不使用字典存储计算值)和fibonacci()的运行时间比率,我们可以看到绘制时,它看起来类似于下面的截图:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_14.jpg

from time import time

for nval in range(16,27):
  fibvalues = {0: 0, 1: 1, 2:1, 3:2, 4:3, 5:5}
  t3 = time()
  fibonacci(nval)
  diftime1 = time()-t3
  t2 = time()
  fib(nval)
  diftime2 = time()-t2
  print "The ratio of time-2/time-1 :"+str(diftime2/diftime1)

尝试

Trie (发音为 Trie 或 trai)是具有不同名称的数据结构(数字树基数树前缀树)。尝试对于搜索、插入和删除功能非常有效。这种数据结构非常适合存储。比如代数assocalltrie十个存储在 trie 中,看起来会和下图类似

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_15.jpg

在上图中,为了清楚起见,字符以大写形式显示,而在实际存储中,字符以单词形式存储。在 trie 的实现中,存储字数是有意义的。搜索功能非常有效,特别是当模式不匹配时,结果会更快。换句话说,如果搜索的,则在未找到字母 r 的级别确定失败。

其中一个流行的功能是最长前缀匹配。换句话说,如果我们要在字典中找到与特定搜索字符串匹配最长前缀的所有单词: base (例如)。结果可能是基础基础基线基础,如果在单词字典中找到的话,甚至更多单词。

Python 有很多不同的实现:suffix_treepytiretriedatrie等等。J. F .塞巴斯蒂安做了一个很好的比较研究,可以在https://github.com/zed/trie-benchmark查阅。

大多数搜索引擎都有一个名为倒排索引的 trie 实现。这是空间优化非常重要的核心部分。此外,搜索这种结构对于找到搜索字符串和文档之间的相关性非常有效。trie 的另一个有趣的应用是 IP 路由,其中包含大范围值的能力特别合适。也节省了空间。

Python 中一个简单的实现(不一定是最有效的)在下面的代码中显示为:

_end = '_end_'

# to search if a word is in trie
def in_trie(trie, word):
     current_dict = trie
     for letter in word:
         if letter in current_dict:
             current_dict = current_dict[letter]
         else:
             return False
     else:
         if _end in current_dict:
             return True
         else:
             return False

#create trie stored with words
def create_trie(*words):
    root = dict()
    for word in words:
        current_dict = root
        for letter in word:
            current_dict = current_dict.setdefault(letter, {})
        current_dict = current_dict.setdefault(_end, _end)
    return root

def insert_word(trie, word):
    if in_trie(trie, word): return

    current_dict = trie
    for letter in word:
            current_dict = current_dict.setdefault(letter, {})
    current_dict = current_dict.setdefault(_end, _end)

def remove_word(trie, word):
    current_dict = trie
    for letter in word:
        current_dict = current_dict.get(letter, None)
        if current_dict is None:
            # the trie doesn't contain this word.
            break
    else:
        del current_dict[_end]

dict = create_trie('foo', 'bar', 'baz', 'barz', 'bar')
print dict
print in_trie(dict, 'bar')
print in_trie(dict, 'bars')
insert_word(dict, 'bars')
print dict
print in_trie(dict, 'bars')

使用 matplotlib 的可视化

matplotlib是不是除了现在还有其他几个流行的绘图包之外的又一个流行的绘图包。matplotlib的能力现在正在被 Python 社区实现。这个包的创建者和项目负责人约翰·亨特将其总结为马特洛特利试图让简单的事情变得容易,让困难的事情变得可能。您只需很少的努力就可以生成非常高质量的出版物就绪图。在这一节中,我们将挑选几个有趣的例子来说明matplotlib的力量。

字云

单词云赋予在任何给定文本中出现频率更高的单词更大的重要性。它们也被称为标签云或加权词。您可以使用不同的字体、布局和配色方案来调整单词云。从出现的次数来看,一个词的力量的重要性在视觉上映射到其出现的大小。换句话说,在可视化中出现最多的单词是在文本中出现最多的单词。

除了它们出现的明显地图之外,单词云在社交媒体和营销方面还有几个有用的应用。一些应用如下:

  • 企业可以了解他们的客户以及他们如何看待他们的产品。一些组织使用了一种非常有创意的方法,让他们的粉丝或追随者发布关于他们对自己品牌的看法的词语,将所有这些词语放入一个词云,以更好地了解他们产品品牌的最常见印象。
  • 通过识别一个在网上很受欢迎的品牌来寻找了解竞争对手的方法。从他们的内容中创建一个词云,以更好地理解哪些词和主题吸引了产品目标市场。

为了创建单词云,您可以编写 Python 代码或使用已经存在的东西。来自 NYU 数据科学中心的安德烈亚斯·穆勒用 Python 创建了一个非常简单易用的单词云。它可以按照下一节给出的说明进行安装。

安装字云

为了更快的安装,你可以只使用pipsudo访问,如下代码所示:

sudo pip install git+git://github.com/amueller/word_cloud.git

或者,您可以通过 Linux 上的wget或 Mac OS 上的curl获得该包,代码如下:

wget https://github.com/amueller/word_cloud/archive/master.zip
unzip master.zip
rm master.zip 
cd word_cloud-master 
sudo pip install -r requirements.txt

对于 Anaconda IDE,您必须通过以下三个步骤使用conda安装它:

#step-1 command
conda install wordcloud

Fetching package metadata: ....
Error: No packages found in current osx-64 channels matching: wordcloud

You can search for this package on Binstar with
# This only means one has to search the source location
binstar search -t conda wordcloud

Run 'binstar show <USER/PACKAGE>' to get more details:
Packages:
 Name | Access       | Package Types   | 
 ------------------------- | ------------ | --------------- |
 derickl/wordcloud | public       | conda           |
Found 1 packages

# step-2 command
binstar show derickl/wordcloud

Using binstar api site https://api.binstar.org
Name:    wordcloud
Summary:
Access:  public
Package Types:  conda
Versions:
 + 1.0

To install this package with conda run:
conda install --channel https://conda.binstar.org/derickl wordcloud

# step-3 command
conda install --channel https://conda.binstar.org/derickl wordcloud

Fetching package metadata: ......
Solving package specifications: .
Package plan for installation in environment /Users/MacBook/anaconda:

The following packages will be downloaded:

 package                    |            build
 ---------------------------|-----------------
 cython-0.22                |           py27_0         2.2 MB
 django-1.8                 |           py27_0         3.2 MB
 pillow-2.8.1               |           py27_1         454 KB
 image-1.3.4                |           py27_0          24 KB
 setuptools-15.1            |           py27_1         435 KB
 wordcloud-1.0              |       np19py27_1          58 KB
 conda-3.11.0               |           py27_0         167 KB
 ------------------------------------------------------------
 Total:         6.5 MB

The following NEW packages will be INSTALLED:
 django:     1.8-py27_0
 image:      1.3.4-py27_0
 pillow:     2.8.1-py27_1
 wordcloud:  1.0-np19py27_1

The following packages will be UPDATED:
 conda:      3.10.1-py27_0 --> 3.11.0-py27_0
 cython:     0.21-py27_0   --> 0.22-py27_0
 setuptools: 15.0-py27_0   --> 15.1-py27_1

The following packages will be DOWNGRADED:

libtiff:    4.0.3-0       --> 4.0.2-1

Proceed ([y]/n)? y

输入单词云

在本节中,将有两个来源,您可以从中提取单词来构建单词云。第一个示例显示了如何从一些已知网站的 web 提要中提取文本,以及如何从其描述中提取单词。第二个例子展示了如何借助搜索关键词从推文中提取文本。这两个例子将需要feedparser包和tweepy包,通过遵循类似的步骤(如前面其他包所述),您可以轻松安装它们。

我们的方法是从这两个例子中收集单词,并将它们用作通用单词云程序的输入。

网络订阅源

如今,在大多数的“T5”新闻和科技服务网站中,都有分组有序的“T4”RSS 或 atom 订阅源。虽然我们的目标是将上下文限制在技术上,但是我们可以确定一些提要列表,如下面的代码所示。为了能够解析这些提要,feedparserparser()方法派上了用场。Word cloud 有自己的stopwords列表,但除此之外,我们还可以一边用一边收集数据,如下图所示(stopwords这里不全,但可以从网上任何已知资源收集更多):

import feedparser
from os import path
import re

d = path.dirname(__file__)
mystopwords = [  'test', 'quot', 'nbsp']

feedlist = ['http://www.techcrunch.com/rssfeeds/',
'http://www.computerweekly.com/rss',
'http://feeds.twit.tv/tnt.xml',
'https://www.apple.com/pr/feeds/pr.rss',
'https://news.google.com/?output=rss'
'http://www.forbes.com/technology/feed/'                  'http://rss.nytimes.com/services/xml/rss/nyt/Technology.xml',         'http://www.nytimes.com/roomfordebate/topics/technology.rss',
'http://feeds.webservice.techradar.com/us/rss/reviews'            'http://feeds.webservice.techradar.com/us/rss/news/software',
'http://feeds.webservice.techradar.com/us/rss',
'http://www.cnet.com/rss/',
'http://feeds.feedburner.com/ibm-big-data-hub?format=xml',
'http://feeds.feedburner.com/ResearchDiscussions-DataScienceCentral?format=xml',        'http://feeds.feedburner.com/BdnDailyPressReleasesDiscussions-BigDataNews?format=xml',
'http://http://feeds.feedburner.com/ibm-big-data-hub-galleries?format=xml',          'http://http://feeds.feedburner.com/PlanetBigData?format=xml',
'http://rss.cnn.com/rss/cnn_tech.rss',
'http://news.yahoo.com/rss/tech',
'http://slashdot.org/slashdot.rdf',
'http://bbc.com/news/technology/']          

def extractPlainText(ht):
    plaintxt=''
    s=0
    for char in ht:
        if char == '<': s = 1
        elif char == '>': 
            s = 0
            plaintxt += ' '
        elif s == 0: plaintxt += char
    return plaintxt

def separatewords(text):
    splitter = re.compile('\\W*')
    return [s.lower() for s in splitter.split(text) if len(s) > 3]

def combineWordsFromFeed(filename):
    with open(filename, 'w') as wfile:
      for feed in feedlist:
        print "Parsing " + feed
        fp = feedparser.parse(feed)
        for e in fp.entries:
          txt = e.title.encode('utf8') + 
               extractPlainText(e.description.encode('utf8'))
          words = separatewords(txt)

          for word in words:
            if word.isdigit() == False and word not in mystopwords:
               wfile.write(word)
               wfile.write(" ")
          wfile.write("\n")
    wfile.close()
    return

combineWordsFromFeed("wordcloudInput_FromFeeds.txt")

推特正文

为了访问推特应用编程接口,你需要访问令牌和消费者凭证,包括四个参数:access_tokenaccess_token_secretconsumer_keyconsumer_secret。为了获得这些密钥,您必须使用推特账户。获取这些密钥的步骤可以在推特网站上找到。涉及的步骤有:

  1. 登录推特账户。
  2. 导航到developer.twitter.com并使用管理我的应用来完成并获取前面提到的参数。

假设这些参数都准备好了,有了tweepy包,就可以通过 Python 访问推文了。下面的代码显示了一个简单的自定义流侦听器。在这里,当推文被流式传输时,有一个监听器监听状态并将状态写入文件。这可以在以后用来创建单词云。

该流使用过滤器来缩小关注于Python 程序数据可视化大数据机器学习统计的推特文本。tweepy流提供提取的推文。这可以永远运行,因为有无限的数据。我们如何设置它停止?访问速度可能比您预期的要慢,为了创建单词云,您可以想象提取一定数量的推文可能就足够了。因此,我们设置了一个限制,并将其称为MAX_TWEETS50,如以下代码所示:

import tweepy
import json
import sys
import codecs

counter = 0
MAX_TWEETS = 500

#Variables that contains the user credentials to access Twitter API 
access_token = "Access Token"
access_token_secret = "Access Secret"
consumer_key = "Consumer Key"
consumer_secret = "Consumer Secret"

fp = codecs.open("filtered_tweets.txt", "w", "utf-8")

class CustomStreamListener(tweepy.StreamListener):

     def on_status(self, status):
        global counter
        fp.write(status.text)
        print "Tweet-count:" +str(counter)
        counter += 1
        if counter >= MAX_TWEETS: sys.exit()

    def on_error(self, status):
        print status

if __name__ == '__main__':

    auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
    auth.set_access_token(access_token, access_token_secret)
    streaming_api = tweepy.streaming.Stream(auth,
               CustomStreamListener(), timeout=60)

    streaming_api.filter(track=['python program', 'statistics', 
             'data visualization', 'big data', 'machine learning'])

使用任何一包单词,你可以写少于 20 行的 Python 代码来生成单词云。一个字云生成一个图像,使用matplotlib.pyplot,可以使用imshow()显示字云图像。以下单词云可用于任何单词输入文件:

from wordcloud import WordCloud, STOPWORDS
import matplotlib.pyplot as plt
from os import path

d = path.dirname("__file__")
text = open(path.join(d, 'filtered_tweets.txt')).read()

wordcloud = WordCloud(
    font_path='/Users/MacBook/kirthi/RemachineScript.ttf',
    stopwords=STOPWORDS,
    background_color='#222222',
    width=1000,
    height=800).generate(text)

# Open a plot of the generated image.
plt.figure(figsize=(13,13))
plt.imshow(wordcloud)
plt.axis("off")
plt.show()

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_16.jpg

所需字体文件可从多个网站下载(该字体的一个特定资源可在http://www.dafont.com/remachine-script.font获得)。无论字体文件位于何处,您都必须使用设置为font_path的精确路径。对于使用提要中的数据,只有一行发生了变化,如以下代码所示:

text = open(path.join(d, 'wordcloudInput_fromFeeds.txt')).read()

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_17.jpg

使用类似的从推文中提取文本创建词云的思路,你可以在手机厂商的上下文中提取带有关键词的文本,比如 iPhone三星 Galaxy亚马逊 FireLG 擎天柱诺基亚 Lumia 等等,来决定消费者的情绪。在这种情况下,您可能需要一组额外的信息,即与单词相关联的积极和消极情绪值。

在有限的上下文中,有几种方法可以让你对推文进行情感分析。首先,一种非常天真的方法是将权重与对应于积极情绪的单词(如 w p )和消极情绪(如 w n 联系起来,应用以下符号 p(+) 作为积极情绪的概率,应用 p(-) 表示消极情绪:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_18.jpg

第二种方法是使用自然语言处理工具,并将训练好的分类器应用于以获得更好的结果。 TextBlob 是一个也有情感分析的文本处理包(http://textblob.readthedocs.org/en/dev)。

TextBlob 构建一个文本分类系统,并创建一个 JSON 格式的训练集。之后,使用这个训练和朴素贝叶斯分类器,它执行情感分析。我们将在后面的章节中尝试使用这个工具来演示我们的工作示例。

绘制股价图

美国最大的两家证券交易所是成立于 1792 年的纽约证券交易所和成立于 1971 年的纳斯达克。今天,大多数股票交易都是以电子方式进行的。甚至股票本身几乎都是以电子形式持有,而不是作为实物凭证。除了纳斯达克和纽交所,还有许多其他网站也提供实时股价数据。

获取数据

获取数据的网站之一是 Yahoo,它通过 API 提供数据,比如获取亚马逊的股价(低、高、开、关、量),网址是http://chart API . finance . Yahoo . com/instrument/1.0/amzn/chart data;type = quote 范围=3y/csv 。根据您选择的绘图方法,需要进行一些数据转换。例如,从该资源获得的数据包括没有任何格式的日期,如下面的代码所示:

uri:/instrument/1.0/amzn/chartdata;type=quote;range=3y/csv
ticker:amzn
Company-Name:Amazon.com, Inc.
Exchange-Name:NMS
unit:DAY
timestamp:
first-trade:19970516
last-trade:20150430
currency:USD
previous_close_price:231.9000
Date:20120501,20150430
labels:20120501,20120702,20121001,20130102,20130401,20130701,20131001,20140102,20140401,20140701,20141001,20150102,20150401
values:Date,close,high,low,open,volume
close:208.2200,445.1000
high:211.2300,452.6500
low:206.3700,439.0000
open:207.4000,443.8600
volume:984400,23856100
20120501,230.0400,232.9700,228.4000,229.4000,6754900
20120502,230.2500,231.4400,227.4000,227.8200,4593400
20120503,229.4500,232.5300,228.0300,229.7400,4055500
...
...
20150429,429.3700,434.2400,426.0300,426.7500,3613300
20150430,421.7800,431.7500,419.2400,427.1100,3609700

我们将讨论创建绘图的三种方法。每一种都有自己的优点和局限性。

在第一种方法中,使用matplotlib.cbook包和pylab包,您可以用以下代码行创建一个图:

from pylab import plotfile show, gca 
import matplotlib.cbook as cbook  
fname = cbook.get_sample_data('/Users/MacBook/stocks/amzn.csv', asfileobj=False) 
plotfile(fname, ('date', 'high', 'low', 'close'), subplots=False) 
show()

这将创建一个类似于下面截图中所示的图:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_19.jpg

在尝试使用这种方法绘图之前,还需要进行一次额外的编程工作。日期值必须格式化以将 20150430 表示为%d-%b-%Y。采用这种方法,图也可以一分为二,一个显示股价,另一个显示成交量,如下代码所示:

from pylab import plotfile show, gca 
import matplotlib.cbook as cbook  
fname = cbook.get_sample_data('/Users/MacBook/stocks/amzn.csv', asfileobj=False) 
plotfile(fname, (0,1,5), plotfuncs={f:'bar'}) 
show()

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_20.jpg

第二种方法是使用matplotlib.mlabmatplotlib.finance的子包。这有方便的方法从http://ichart.finance.yahoo.com/table.csv?s=GOOG&a = 04&b = 12&c = 2014&d = 06&e = 20&f = 2015&g = d获取股票数据,为了展示一个样本,这里有一个代码片段:

ticker='GOOG'

import matplotlib.finance as finance
import matplotlib.mlab as mlab
import datetime

startdate = datetime.date(2014,4,12)
today = enddate = datetime.date.today()

fh = finance.fetch_historical_yahoo(ticker, startdate, enddate)   
r = mlab.csv2rec(fh); fh.close()
r.sort()
print r[:2]

[ (datetime.date(2014, 4, 14), 538.25, 544.09998, 529.56, 532.52002, 2568000, 532.52002)  (datetime.date(2014, 4, 15), 536.82001, 538.45001, 518.46002, 536.44, 3844500, 536.44)]

当您试图绘制股价比较图时,显示成交量信息是没有意义的,因为对于每个股票代码,成交量是不同的。此外,它变得太混乱,无法查看股票图表。

matplotlib已经有绘制股价图的工作示例,足够精细,包括相对强弱指标 ( RSI )和移动平均线收敛/发散 ( MACD ),可在http://matplotlib . org/examples/pylab _ examples/finance _ work 2 . html获得。关于 RSI 和 MACD 的详情,你可以在网上找到很多资源,但是在http://easyforextrading.co/how-to-trade/indicators/有一个有趣的解释。

为了尝试使用现有代码,对其进行修改,并使其适用于多个图表,创建了一个名为plotTicker()的函数。这有助于在同一坐标轴内绘制每个滚动条,如以下代码所示:

import datetime
import numpy as np

import matplotlib.finance as finance
import matplotlib.dates as mdates
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt

startdate = datetime.date(2014,4,12)
today = enddate = datetime.date.today()

plt.rc('axes', grid=True)
plt.rc('grid', color='0.75', linestyle='-', linewidth=0.5)
rect = [0.4, 0.5, 0.8, 0.5]

fig = plt.figure(facecolor='white', figsize=(12,11))

axescolor = '#f6f6f6' # the axes background color

ax = fig.add_axes(rect, axisbg=axescolor)
ax.set_ylim(10,800)

def plotTicker(ticker, startdate, enddate, fillcolor):
  """
     matplotlib.finance has fetch_historical_yahoo() which fetches 
     stock price data the url where it gets the data from is 
     http://ichart.yahoo.com/table.csv stores in a numpy record 
     array with fields: 
      date, open, high, low, close, volume, adj_close
  """

  fh = finance.fetch_historical_yahoo(ticker, startdate, enddate) 
  r = mlab.csv2rec(fh); 
  fh.close()
  r.sort()

  ### plot the relative strength indicator
  ### adjusted close removes the impacts of splits and dividends
  prices = r.adj_close

  ### plot the price and volume data

  ax.plot(r.date, prices, color=fillcolor, lw=2, label=ticker)
  ax.legend(loc='top right', shadow=True, fancybox=True)

  # set the labels rotation and alignment 
  for label in ax.get_xticklabels():
    # To display date label slanting at 30 degrees
    label.set_rotation(30)
    label.set_horizontalalignment('right')

  ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d')

#plot the tickers now
plotTicker('BIDU', startdate, enddate, 'red')
plotTicker('GOOG', startdate, enddate, '#1066ee')
plotTicker('AMZN', startdate, enddate, '#506612')

plt.show()

当你用这个来比较比都、谷歌、亚马逊的股价时,图会看起来类似于下面的截图:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_22.jpg

使用以下代码比较推特、脸书和领英的股价:

plotTicker('TWTR', startdate, enddate, '#c72020')
plotTicker('LNKD', startdate, enddate, '#103474')
plotTicker('FB', startdate, enddate, '#506612')

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_23.jpg

现在,您也可以添加体积图。对于带音量的单个跑马灯图,请使用以下代码:

import datetime

import matplotlib.finance as finance
import matplotlib.dates as mdates
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt

startdate = datetime.date(2013,3,1)
today = enddate = datetime.date.today()

rect = [0.1, 0.3, 0.8, 0.4]   

fig = plt.figure(facecolor='white', figsize=(10,9))  
ax = fig.add_axes(rect, axisbg='#f6f6f6')

def plotSingleTickerWithVolume(ticker, startdate, enddate):

    global ax

    fh = finance.fetch_historical_yahoo(ticker, startdate, enddate)

    # a numpy record array with fields: 
    #     date, open, high, low, close, volume, adj_close
    r = mlab.csv2rec(fh); 
    fh.close()
    r.sort()

    plt.rc('axes', grid=True)
    plt.rc('grid', color='0.78', linestyle='-', linewidth=0.5)

    axt = ax.twinx()
    prices = r.adj_close

    fcolor = 'darkgoldenrod'

    ax.plot(r.date, prices, color=r'#1066ee', lw=2, label=ticker)
    ax.fill_between(r.date, prices, 0, prices, facecolor='#BBD7E5')
    ax.set_ylim(0.5*prices.max())

    ax.legend(loc='upper right', shadow=True, fancybox=True)

    volume = (r.close*r.volume)/1e6  # dollar volume in millions
    vmax = volume.max()

    axt.fill_between(r.date, volume, 0, label='Volume', 
                 facecolor=fcolor, edgecolor=fcolor)

    axt.set_ylim(0, 5*vmax)
    axt.set_yticks([])

    for axis in ax, axt:  
        for label in axis.get_xticklabels():
            label.set_rotation(30)
            label.set_horizontalalignment('right')

        axis.fmt_xdata = mdates.DateFormatter('%Y-%m-%d')

plotSingleTickerWithVolume ('MSFT', startdate, enddate)
plt.show()

随着单个滚动条的绘制以及音量和前面代码中的变化,该图将类似于下面的屏幕截图:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_25.jpg

您也可以选择使用第三种方法:使用blockspring套装。要安装blockspring,必须使用以下pip命令:

pip install blockspring

Blockspring 的方法是生成 HTML 代码。它以 JavaScript 格式自动生成绘图数据。当它与 D3.js 集成时,它提供了一个非常好的交互式绘图。令人惊讶的是,只有两行代码:

import blockspring 
import json  

print blockspring.runParsed("stock-price-comparison", 
   { "tickers": "FB, LNKD, TWTR", 
   "start_date": "2014-01-01", "end_date": "2015-01-01" }).params

根据操作系统,当运行该代码时,它会在默认区域生成 HTML 代码。

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_21.jpg

体育运动中的可视化实例

让我们在这里考虑一个不同的例子来说明可视化数据的各种不同方法。我们不会选择计算问题,而是将自己局限于一组简单的数据,并展示可以进行多少不同的分析,最终导致可视化,以帮助澄清这些分析。

北美体育有好几个大联盟运动,我们就来比较一下其中的四个:全国足球联赛(NFL)棒球大联盟(MLB)全国篮球协会(NBA)全国曲棍球联赛。NFL 的球队总价值为 91.3 亿美元,总收入为 95.8 亿美元。我们将使用以下团队价值观和锦标赛数据来选择这项运动(此处仅显示部分数据):

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_26.jpg

团队价值是比较不同团队的一个重要因素,但锦标赛也有价值。沿着 x 轴的年完成数、沿着 y 轴的冠军数以及代表每年平均冠军数的气泡大小的这个数据的简单图会给我们类似于下图的东西:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_27.jpg

但是,除非您可以通过显示标签或细节使其具有交互性,否则前面的图可能不会很有用。matplotlib 可以进行上述绘图,如以下代码所示:

import matplotlib.pyplot as plt
fig = plt.figure(figsize=(15,10), facecolor='w')

def plotCircle(x,y,radius,color, alphaval):
  circle = plt.Circle((x, y), radius=radius, fc=color,\
   alpha=alphaval)
  fig.gca().add_patch(circle)
  nofcircle = plt.Circle((x, y), radius=radius, ec=color, \
   fill=False)
  fig.gca().add_patch(nofcircle)

x = [55,83,90,13,55,82,96,55,69,19,55,95,62,96,82,30,22,39, \
  54,50,69,56,58,55,55,47,55,20,86,78,56]
y = [5,3,4,0,1,0,1,3,5,2,2,0,2,4,6,0,0,1,0,0,0,0,1,1,0,0,3,0, \
  0,1,0]
r = [23,17,15,13,13,12,12,11,11,10,10,10,10,10,9,9,9,8,8,8,8, \
    8,8,8,7,7,7,7,6,6,6]
for i in range(0,len(x)):
  plotCircle(x[i],y[i],r[i],'b', 0.1)

plt.axis('scaled')
plt.show()

你甚至可以用这个数值数据转换成 JavaScript 可以理解的格式(JSON 格式),这样在与 SVG 地图集成时,就有可能在地图上显示估值,如下图截图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_28.jpg

如果显示相关的标签,前面带有气泡的地图会更好。然而,由于地图的某些区域空间不足,在地图上添加交互式实现并通过导航显示信息会更有意义。

可以参考http://tinyurl.com/oyxk72r的原始数据源。

http://www.knapdata.com/python/nfl_franch.html有一个备用电源。

除了普通的气泡图和地图上的气泡图,还有其他几种可视化方法可以应用。当显示 32 个团队的统计数据时,一种看起来混乱的视觉格式是饼状图或条形图。

它不仅看起来杂乱,标签也几乎不可读。显示这个饼图的全部意义在于说明在这种数据中,人们必须寻找可视化的替代方法,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_29.jpg

如果我们在团队价值的一定范围内组合一组团队,那么通过减少它们,我们可能能够以更有组织的方式展示它们,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-zh/raw/master/docs/master-py-data-vis/img/B02085_04_30.jpg

上图是通过将团队分成小组来显示团队价值的另一种方法,例如,用 2300,000,000 美元表示 23 亿美元,这意味着 23 亿美元。这样,数据标签是可读的。

总结

在过去的几十年里,计算已经成为许多领域中非常重要的一部分。事实上,许多学校的计算机科学课程,如斯坦福、加州大学伯克利分校、麻省理工学院、普林斯顿、哈佛、加州理工学院等,都因为这种变化而进行了修订,以适应跨学科课程。在大多数科学学科中,计算工作是实验和理论的重要补充。此外,绝大多数实验和理论论文都涉及一些数值计算、模拟或计算机建模。

Python 已经走了很长的路,今天 Python 社区已经发展到有资源和工具来帮助编写最少的代码来非常高效地完成计算中可能需要的几乎所有事情。我们只能在本章中挑选几个工作示例,但是在接下来的章节中,我们将查看更多示例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值