
利用 Python 进行数据分析
前言
本书第 1 版于 2012 年出版,那时 Python 中像 pandas 这样的开源数据分析库刚出现不久,但发展十分迅速。当我在 2016 年和 2017 年创作第 2 版时,不仅要将 Python 更新到 3.6 版本(第 1 版使用的是 Python 2.7),还要更新过去 5 年间 pandas 的诸多变更。2022 年,Python 语言变化很少(目前是 Python 3.10,2022 年年底会推出 3.11),但 pandas 的演进一直在持续。
第 3 版的目标是让知识点紧跟 Python、NumPy、pandas 的发展,以及其他项目的最新版本,较少涉及过去几年新推出的 Python 项目。因为本书已经成为许多大学课程和职场专业人士的重要参考资料,所以我会尽力避免书中内容在短期内过时的情况。
本书的新特点是读者可以访问本书的在线版本。我会持续更新在线版本,如果读者碰到书中运行有误的地方,不妨及时查询线上内容的修订。
在本书的 GitHub 页面,你可以找到包含各章节所有代码实例的 Jupyter notebook。如果读者不方便访问 GitHub,还可以访问 Gitee 上的镜像地址。
第1章 准备工作
本书讲解利用 Python 进行数据操作、处理、清洗、规整等的基本要点和具体细节,目标是介绍 Python 编程语言及其用于数据的库生态和工具,掌握这些知识可以让你成为一名称职的数据分析师。虽然本书书名中包含“数据分析”,但内容重点是 Python 编程、库和工具,而不是数据分析方法论。本书主要介绍数据分析需要用到的 Python 编程知识。
本书第 1 版在 2012 年出版后,人们开始使用“数据科学”一词笼统地描述从简单的描述性统计到更为复杂的统计分析及机器学习的所有工作。自 2012 年起,Python 开源数据分析(或数据科学)生态得到了极大发展。目前有许多其他书籍专门讲解这些更高级的方法。希望本书可以让读者做好充分的准备,以便以后学习更细分领域的知识。
什么样的数据
当书中提到“数据”时,主要指的是结构化数据,例如:
- 表格型或电子表格型数据,其中各列可能是不同的类型(字符串、数值、日期等)。比如保存在关系型数据库中或以制表符/逗号为分隔符的文本文件中的数据。
- 多维数组(矩阵)。
- 通过关键列(对于 SQL 用户而言,就是主键和外键)相互联系的多个表。
- 平均或不平均间隔的时间序列。
这里没有列举所有格式的数据。大部分数据集都能被转化为更加适合分析和建模的结构化形式,虽然有时这并不是很明显。如果不行的话,也可以将数据集的特征提取为某种结构化形式。例如,一组新闻文章可以被处理为一个词频表,而这个词频表就可以用于情感分析。
大部分电子表格软件(比如 Microsoft Excel,可能是世界上使用最广泛的数据分析工具)的用户不会对此类数据感到陌生。
第2章 Python语法基础、IPython和Jupyter notebook
当我在 2011 年和 2012 年写作本书的第 1 版时,学习 Python 数据分析的可用资源很少。我们现在使用的库,比如 pandas、scikit- learn 和 statsmodels,那时相对来说并不成熟。来到 2022 年,数据科学、数据分析和机器学习的资源已经很多,原先仅面向通用科学计算的工作也拓展到了计算机科学家、物理学家和其他研究领域的工作人员。此外,也出现了大量学习 Python 编程和成为卓越软件工程师的优秀书籍。
因为本书是专注于 Python 数据处理的,从数据处理的角度,我认为很有必要独立成章地概述 Python 内置的数据结构和库的重要功能特性。因此,本章和第 3 章将介绍一些基本知识,这些内容足以确保读者学习本书的后续章节。
本书大部分内容关注的是基于表格数据的分析和处理数据集的数据准备工具,数据集并不大,可以在个人计算机上运行。为了使用这些工具,必须首先将混乱的数据规整为整洁的表格(或结构化)形式。幸好,Python 是一门理想的语言,可以快速整理数据。对 Python 的内置数据类型使用得越熟练,越容易准备新数据集以进行分析。
最好在 IPython 和 Jupyter 中亲自尝试本书中使用的工具。当你学会了如何启动 IPython 和 Jupyter,我建议你跟随示例代码进行练习。与任何键盘控制的操作环境一样,熟练掌握常用命令也是学习曲线的一部分。
本章没有介绍 Python 的某些概念,例如类和面向对象编程,你可能会发现它们在 Python 数据分析中很有用。
为了加强 Python 知识,我建议你学习官方 Python 教程,或者优秀的 Python 编程书籍。以下是一些推荐书籍:
- Python Cookbook,Third Edition,David Beazley 和 Brian K.Jones 著(O'Reilly 出版)
- Fluent Python,Luciano Ramalho 著(O'Reilly 出版)
- Effective Python,Second Edition,Brett Slatkin 著(Addison- Wesley 出版)
第3章 Python的数据结构、函数和文件
本章讨论贯穿全书的 Python 内置功能。虽然扩展库(比如 pandas 和 NumPy)带来了处理大数据集的高级计算功能,但它们的设计初衷是和 Python 内置数据处理工具协同使用。
我们从 Python 主要的数据结构开始:元组、列表、字典和集合。然后讨论创建可复用的 Python 函数。最后学习 Python 文件对象的机制,以及如何与本地硬盘交互。
第4章 NumPy 基础:数组和向量化计算
NumPy 是 Numerical Python 的简称,它是 Python 数值计算中最重要的基础包之一。大多数提供科学计算的包都用 NumPy 数组对象作为数据交换的通用标准接口。这里介绍的 NumPy 知识也适用于 pandas。
NumPy 的部分内容和功能如下:
- ndarray,一个高效多维数组,提供快速的基于数组的算术运算和灵活的广播功能。
- 用于对整个数组数据进行快速运算的数学函数,无须编写循环。
- 用于读写磁盘数据的工具,以及用于操作内存映射文件的工具。
- 线性代数、随机数生成以及傅里叶变换功能。
- 一个 C 语言 API,用于将 NumPy 连接到用 C、C++ 或 Fortran 编写的库。
由于 NumPy 提供了一套功能强大、文档翔实的 C 语言 API,因此很容易将数据传递给由底层语言编写的外部库,外部库也能以 NumPy 数组的形式将数据返回给 Python。这个功能使 Python 成为封装遗留的 C、 C ++ 和 Fortran 代码库的首选语言,并使封装库拥有一个动态和可访问的接口。
NumPy 本身并没有提供建模和科学计算功能,但理解 NumPy 数组以及面向数组的计算将有助于你更加高效地使用 pandas 等工具。NumPy 是一个很大的话题,我会在附录 A 中介绍更多 NumPy 的高级功能,比如广播。本书其余章节不会用到这些高级功能,但随着你深入研究 Python 的科学计算,就要用到了。
对于大部分数据分析应用而言,我最关注的功能主要集中在:
- 用于数据整理和清洗、子集构造和过滤、转换等基于数组的快速运算。
- 常用的数组算法,如排序、唯一化、集合运算等。
- 高效的描述性统计和数据连接/摘要运算。
- 用于合并/连接异构数据集的数据对齐和关系型数据操作。
- 将条件逻辑表述为数组表达式,而不是带有 if-elif-else 分支的循环。
- 数据的分组运算(连接、转换、函数应用等)。
虽然 NumPy 提供了通用的数值数据处理的计算基础,但大多数读者可能还是想将 pandas 作为统计和分析工作的基础,尤其是处理表格数据时。pandas 还提供了一些 NumPy 所没有的特定领域的功能,如时间序列处理。
Python 的面向数组的计算可以追溯到 1995 年,JimHugunin 创建了 Numeric 库。接下来的 10 年,许多科学编程社区纷纷开始使用 Python 从事数组编程,但是进入 21 世纪,库的生态变得碎片化了。2005 年,TravisOliphant 从 Numeric 和 Numarray 项目打造出了 NumPy 项目,进而所有社区都集合到了这个框架下。
NumPy 对于数值计算特别重要的原因之一,是它被设计为可以高效处理大型数组的数据。这是因为:
- NumPy 是在一个连续的内存块中存储数据,独立于其他 Python 内置对象。NumPy 的 C 语言编写的算法库可以操作内存,而不必进行类型检查或其他前期工作。比起 Python 的内置序列,NumPy 数组使用的内存更少。
- NumPy 可以在整个数组上执行复杂的运算,而不需要 Python 的 for 循环,for 循环对于大型序列速度较慢。NumPy 之所以比常规的 Python 代码快,是因为 NumPy 的基于 C 语言的算法无须对 Python 代码进行解释,节省了开销。
为了直观地观察性能差距,我们来看一个包含一百万个整数的数组和一个等价的 Python 列表:
import numpy as np
my_arr = np.arange(1_000_000)
my_list = list(range(1_000_000))
各个序列分别乘以 2:
In [10]: %timeit my_arr 2 = my_arr * 2715 us +- 13.2 us per loop (mean +- std. dev. of 7 runs, 1000 loops each)
In [11]: %timeit my_list 2 = [x * 2 for x in my_list]48.8 ms +- 298 us per loop (mean +- std. dev. of 7 runs, 10 loops each)
基于 NumPy 的算法要比纯 Python 算法快 10~100 倍(甚至更快),并且使用的内存更少。
第5章 pandas入门
pandas 是贯穿本书后续内容的主要工具。它包含多种数据结构和数据操作工具,可以使数据清洗和分析工作更快、更简单。pandas 经常和其他工具一同使用,如数值计算工具 NumPy 和 SciPy,分析库 statsmodels 和 scikit-learn,以及数据可视化库 matplotlib。pandas 从 NumPy 汲取了大量基于数组计算的语言风格,特别是基于数组的函数,以及不使用 for 循环进行数据处理。
虽然 pandas 采用了大量的 NumPy 编码风格,但二者最大的不同是,pandas 是专门为处理表格和异构数据设计的,而 NumPy 更适合处理同构类型的数值数组数据。
自从 2010 年成为开源项目,pandas 逐渐成长为一个非常庞大的库,并应用于许多领域的真实案例。开发者社区已经有 2500 位独立的贡献者,他们在解决日常数据问题的同时为这个项目提供贡献。活跃的 pandas 开发者和用户社区是 pandas 取得成功的重要一环。
许多人可能不清楚,自从 2013 年,我就远离了日复一日的 pandas 开发工作。pandas 自那以后就一直是完全由社区管理的项目。谨代表所有人对核心开发者和所有贡献者的辛勤工作表示由衷的感谢!
在本书后续章节中,我将使用下面的约定导入 NumPy 和 pandas:
import numpy as np
import pandas as pd
# 因此,只要你在代码中看到 pd,就知道引用的是 pandas。因为 Series 和 DataFrame 用的次数非常多,所以将其导入本地命名空间中会更加方便:
from pandas import Series, DataFrame
第6章 数据加载、存储与文件格式
读取数据并使数据可访问(称为数据加载)是使用本书所介绍的大部分工具的第一步。还有另外一个术语“解析”,用于描述加载文本数据并将其解释为表格和不同的数据类型。我会着重介绍 pandas 的数据输入与输出,虽然别的库中也有不少用于读写不同格式数据的工具。
数据输入输出通常可以划分为几大类:读取文本文件和其他更有效的磁盘存储格式,加载数据库中的数据,以及与网络资源(比如 WebAPI)交互。
第7章 数据清洗和准备
在数据分析和建模的过程中,相当多的时间要用在数据准备上:加载、清理、转换以及重塑。这些工作会占到分析师时间的 80% 甚至更多。有时,存储在文件和数据库中的数据的格式不适合某个特定的任务。许多研究者都选择使用通用编程语言(如 Python、Perl、R 或 Java)或 UNIX 文本处理工具(如 sed 或 awk)对数据格式进行专门处理。幸运的是,pandas 和 Python 内置的标准库提供了一组高级、灵活、快速的工具集,可以让你轻松地将数据规整为想要的格式。
如果你发现某种数据处理方式不在本书的范围之内,也不在 pandas 库中,请随时在 Python 邮件列表或 pandas 的 GitHub 网站上提出。实际上,pandas 的许多设计和实现都是由真实应用的需求所驱动的。
在本章中,我会讨论处理缺失数据、重复数据、字符串操作和其他分析数据转换的工具。下一章,我会关注用多种方法合并、重塑数据集。
第8章 数据规整:连接、联合和重塑
在许多应用中,数据可能分散在多个文件或数据库中,或者排列的形式不利于分析。本章关注的是连接、联合、重塑数据的方法。
首先,我会介绍 pandas 的层次化索引,它广泛用于以上操作。然后,我将深入介绍一些特殊的数据操作。在第 13 章,读者可以看到这些工具的具体运用。
第9章 绘图和可视化
信息可视化(也称作绘图)是数据分析中最重要的工作之一。可视化可能是探索过程的一部分,例如,帮助我们找出异常值、必要的数据转换、得出有关建模的想法等。对于其他人,完成可交互的数据可视化网页也许是工作的最终目标。Python 有许多库可用于制作静态或动态的数据可视化,但我在这里重点关注 matplotlib 和基于它的库。
matplotlib 是一个用于制作出版级质量图表的桌面绘图包。该项目由 John Hunter 于 2002 年启动,其目的是为 Python 构建一个 MATLAB 式的绘图接口。随后,matplotlib 和 IPython 社区进行合作,对从 IPython 终端(包括现在的 Jupyter notebook)进行交互式绘图做了简化工作。matplotlib 支持各种操作系统上的多种 GUI 后端,而且还能将图片导出为各种常见的向量图和光栅图,包括 PDF、SVG、JPG、PNG、BMP、GIF 等。除了少数几张图,本书中的大部分图形都是用 matplotlib 生成的。
随着时间的推移,matplotlib 行生出了多个数据可视化的工具集,它们使用 matplotlib 作为底层绘图库。其中之一是 seaborn,本章后面会学习它。
学习本章代码案例的最简单方法,是在 Jupyter notebook 中自己动手制作交互式绘图。为了设置环境,在 Jupyter notebook 中执行下面的语句:
%matplotlib inline
自从本书第 1 版于 2012 年出版,许多数据可视化库脱颖而出,其中一些(比如 Bokeh 和 Altair)使用了新式网页技术,可以创建出与 Jupyter notebook 完美融合的交互式可视化。本书没有使用多种可视化工具,而是使用 matplotlib 传授基本操作,另一个特别的原因是 pandas 和 matplotlib 兼容性很好。从本章学到的原理举一反三,就可以学习其他的可视化库。
第10章 数据聚合与分组操作
对数据集进行分类并对各组数据调用聚合或转换函数,通常是数据分析工作中的重要环节。在将数据集加载、合并、预处理之后,通常就是计算分组统计信息或生成透视表,以用于报告或数据可视化。pandas 提供了一个灵活高效的 gruopby 接口,它使你能以一种自然的方式对数据集进行切片、切块和汇总等操作。
关系型数据库和 SQL(Structured Query Language,结构化查询语言)能够如此流行的原因之一,就是其能够方便地对数据进行连接、过滤、转换和聚合。但是,像 SQL 这样的查询语言所能执行的分组运算的种类很有限。在本章中你将会看到,得益于 Python 和 pandas 强大的表达能力,通过自定义的 Python 函数操控数据的各个分组,我们可以执行复杂的分组运算。在本章中,你将学到:
- 使用单键或多键(形式可以是函数、数组或 DataFrame 列名)分割 pandas 对象。
- 计算分组汇总统计,比如计数、平均值或标准差,或用户定义的函数。
- 应用组内转换或其他操作,如正态化、线性回归、排名或选取子集等。
- 计算透视表和交叉表。
- 执行分位数分析以及其他统计分组分析。
对时间序列数据的聚合(groupby 的特殊用法之一),在本书中称作重采样,将在第 11 章中单独对其进行讲解。
与其他章节一样,首先导入 NumPy 和 pandas:
import numpy as np
import pandas as pd
第11章 时间序列
时间序列时间序列数据是一种重要的结构化数据形式,应用于多个领域,包括金融学、经济学、生态学、神经科学、物理学等。在多个时间点重复记录的值就形成了时间序列。很多时间序列是固定频率的,也就是说,数据点是根据某种规则定期出现的,比如每 15 秒、每 5 分钟或每月一次。时间序列也可以是不定期的,没有固定的时间单位或单位之间的偏移量。如何标记和引用时间序列数据取决于具体的应用,主要有以下几种:
时间戳:特定的时刻。
固定的周期:如 2017 年 1 月整月或 2020 年全年。
时间区间:由起始时间戳和结束时间戳表示。周期可以看作时间区间的特例。
试验时间或运行时间:每个时间戳都是相对于特定起始时间的度量(例如,饼干放入烤箱后每秒烘烤的直径),从 0 开始。
本章主要讲解前三种时间序列。许多技术都可用于处理试验时间序列,其索引可能是整数或浮点数,表示距试验起始时刻已经过去的时间。最简单的时间序列是按时间戳索引的。
pandas 也支持基于时间差的索引,它可以有效表示试验时间或运行时间。本书不涉及时间差索引,请参考 pandas的文档学习更多内容。
pandas 提供了许多内置的时间序列处理工具和算法。因此,你可以高效地处理大型时间序列,轻松地进行切片/切块、聚合,以及对不定期或固定频率的时间序列进行重采样等。其中一些工具特别适合金融和经济领域,当然你也可以用它们来分析服务器日志数据。
本章其余部分,我们都以如下方式导入 NumPy 和 pandas:
In [12]: import numpy as np
In [13]: import pandas as pd
第12章 Python建模库介绍
在本书中,我专注于介绍使用 Python 进行数据分析的编程基础。由于数据分析师和数据科学家总是在数据规整和准备上花费大量时间,因此本书的重点就是让你掌握这些方法。
开发模型选用什么库取决于应用本身。许多统计问题可以用简单方法解决,比如普通的最小二乘回归,其他问题可能需要更为复杂的机器学习方法。幸运的是,Python 已经成为运用这些分析方法的语言之一,因此学完本书之后,你还可以探索许多工具。
本章,我会回顾一些 pandas 的特点,在你聚焦于 pandas 数据规整和模型拟合以及评分时,它们可能会派上用场。我会简短介绍两个流行的建模工具包:statsmodels 和 scikit-learn。
第13章 数据分析案例
本章,我们来看一些真实世界的数据集。对于每个数据集,我们会用之前介绍的方法,从原始数据中提取有意义的内容。展示的方法也适用于其他数据集。本章包含各式各样的示例数据集,可以用本书学习过的工具进行练习。
示例数据集可在本书的GitHub仓库找到。若读者无法访问GitHub,还可访问Gitee上的镜像。
附录A 高阶 NumPy
在附录 A 中,我会深入讲解 NumPy 库的数组计算,包括关于 ndarray 类型以及更高级的数组操作和算法的更多内部细节。
该部分包括多个主题,读者不必按顺序阅读。在附录 A 中,我使用 numpy. random 模块中默认的随机数生成器为许多示例生成了随机数据,如下所示:
rng = np. random. default 市教育局 (seed=12345)
附录B 更多关于IPython的内容
在第 2 章中,我们学习了 IPython shell 和 Jupyter notebook 的基础知识。现在,我们将探索 IPython 可以在控制台或 Jupyter 中使用的更深层次的功能。
作者介绍
Wes McKinney 是一位在纳什维尔工作的软件开发者兼企业家。2007 年在麻省理工学院获得数学学士学位后,他在康涅狄格州格林尼治的 AQR 资本管理公司从事量化金融工作。由于对烦琐的数据分析工具感到沮丧,他学习了 Python 并开始构建后来成为 pandas 的项目。目前,他是 Python 数据社区的活跃成员,同时也是在数据分析、金融和统计计算等领域推广使用 Python 的倡导者。
Wes 后来成为 DataPad 的联合创始人兼 CEO,该公司的技术资产和团队于 2014 年被 Cloudera 公司收购。他自此投身到大数据技术中,加入了 Apache 软件基金会的 Apache Arrow 和 Apache Parquet 项目的项目管理委员会。2018 年,他创建了 Ursa Labs,这是一家聚焦于 Apache Arrow 开发的非营利组织,与 RStudio 和 Two Sigma Investments 达成了合作。2021 年,他与其他人联合创建了技术初创公司 Voltron Data,并担任首席技术官。
封面介绍
本书封面的动物是一只金尾树鼩(也叫笔尾树鼩,英文是 Ptilocercwslowii)。金尾树鼩在生物学分类上是笔尾树鼩科笔尾树鼩属的唯一物种,其他的树鼩都是树鼩科。树鼩的特征是长尾巴和柔软的红棕色皮毛。金尾树鼩得名于它类似于羽毛笔形状的尾巴。金尾树鼩是杂食动物,主要以昆虫、水果、种子和小型脊椎动物为食。
金尾树鼩主要分布在印度尼西亚、马来西亚和泰国,因喜欢饮酒而闻名。人们发现马来西亚金尾树鼩会花费数小时食用天然发酵的凸果棕榈花蜜,大致相当于
尽管名字里有树鼩,但金尾树鼩不是真正的树鼩,而与灵长类动物的亲缘关系更为密切。它们已成为灵长类动物的替代品,参与近视、心理压力和肝炎等医学实验。
封面图片来自 Cassell'sNaturalHistory。