Python 数据分析第三版(一)
原文:
annas-archive.org/md5/74a7b24994c40ad3a90c290c07b529df译者:飞龙
序言
数据分析使你能够通过发现新的模式和趋势,从大数据和小数据中创造价值,而 Python 是分析各种数据的最受欢迎工具之一。本书将带你快速入门 Python 数据分析,探索数据分析中的不同阶段和方法论,并学习如何使用 Python 生态系统中的现代库来创建高效的数据管道。
本书从使用 Python 进行基本统计和数据分析入手,你将通过简单易懂的示例进行复杂的数据分析与建模、数据处理、数据清理和数据可视化。接着,你将学习如何使用 ARMA 模型进行时间序列分析和信号处理。随着深入学习,你还将掌握如何使用机器学习算法(如回归、分类、主成分分析(PCA)和聚类)进行智能处理和数据分析。在最后几章中,你将通过实际案例分析文本数据和图像数据,分别使用自然语言处理(NLP)和图像分析技术。最后,本书还将展示如何使用 Dask 进行并行计算。
在阅读完本书后,你将掌握准备数据以进行分析并创建有意义的数据可视化的技能,从而能够根据数据预测值。
第一章:本书适用对象
本书适合数据分析师、商业分析师、统计学家以及希望学习如何使用 Python 进行数据分析的数据科学家。学生和学术人员也可以通过本书的实践方法学习和教授 Python 数据分析。具有基础数学知识和一定的 Python 使用经验将帮助你更好地入门。
本书内容概述
第一章,开始使用 Python 库,解释了数据分析过程以及 Python 库和 Anaconda 的成功安装。此外,我们还将讨论 Jupyter Notebook 及其高级功能。
第二章,NumPy 与 Pandas,介绍了 NumPy 和 Pandas。本章提供了 NumPy 数组、Pandas DataFrame 及其相关函数的基本概述。
第三章,统计学,简要概述了描述性统计和推断性统计。
第四章,线性代数,简要概述了线性代数及其相关的 NumPy 和 SciPy 函数。
第五章,数据可视化,向我们介绍了 matplotlib、seaborn、Pandas 绘图和 bokeh 可视化库。
第六章,检索、处理和存储数据,解释了如何读取和写入各种数据格式,如 CSV、Excel、JSON、HTML 和 Parquet。我们还将讨论如何从关系型和 NoSQL 数据库中获取数据。
第七章,清理杂乱数据,讲解了如何预处理原始数据并进行特征工程。
第八章,信号处理与时间序列,包含使用销售、啤酒生产和太阳黑子周期数据集进行时间序列和信号处理的示例。在这一章中,我们将主要使用 NumPy、SciPy 和 statsmodels。
第九章,监督学习——回归分析,详细讲解了线性回归和逻辑回归,并使用 scikit-learn 库提供了适当的示例。
第十章,监督学习——分类技术,讲解了多种分类技术,如朴素贝叶斯、决策树、K 最近邻和支持向量机(SVM)。此外,我们还将讨论模型性能评估措施。
第十一章,无监督学习——PCA 和聚类,详细讨论了降维和聚类技术。此外,我们还将评估聚类的性能。
第十二章,分析文本数据,简要概述了文本预处理、特征工程、情感分析和文本相似性。此章节主要使用 NLTK、SpaCy 和 scikit-learn 库。
第十三章,分析图像数据,提供了使用 OpenCV 进行图像处理操作的简要概述。同时,我们还将讨论人脸检测。
第十四章,使用 Dask 进行并行计算,解释了如何使用 Dask 进行数据预处理和机器学习建模的并行处理。
为了最大限度地利用本书
本书中提供的代码示例的执行需要在 Mac OS X、Linux 或 Microsoft Windows 上安装 Python 3.5 或更高版本。在本书中,我们将频繁使用 SciPy、NumPy、Pandas、scikit-learn、statsmodels、matplotlib 和 seaborn。第一章《Python 库入门》提供了安装说明和高级技巧,帮助你顺利进行工作。此外,特定和附加库的安装过程在相关章节中有所说明。Bokeh 的安装过程在第五章《数据可视化》中进行了讲解。类似地,NLTK 和 SpaCy 的安装说明在第十二章《分析文本数据》中进行了介绍。
我们还可以使用 pip 命令安装任何你想要探索的库或包。我们需要以管理员权限运行以下命令:
$ pip install <library name>
我们也可以通过在 pip 命令前加上 !(感叹号)在 Jupyter Notebook 中安装它:
!pip install <library name>
要卸载通过 pip 安装的 Python 库或包,请使用以下命令:
$ pip uninstall <library name>
如果您正在使用本书的数字版,我们建议您自己输入代码,或者通过 GitHub 仓库(链接将在下一部分提供)访问代码。这样可以帮助您避免因复制粘贴代码而产生的潜在错误。
下载示例代码文件
您可以从 GitHub 下载本书的示例代码文件,网址为 github.com/PacktPublishing/Python-Data-Analysis-Third-Edition。如果代码有更新,它将在现有的 GitHub 仓库中进行更新。
我们还提供来自我们丰富书籍和视频目录的其他代码包,您可以在 github.com/PacktPublishing/ 找到它们。快去看看吧!
下载彩色图像
我们还提供了一个包含本书中截图/图表彩色图像的 PDF 文件,您可以在这里下载:static.packt-cdn.com/downloads/9781789955248_ColorImages.pdf。
使用的约定
本书中,您会看到多种文本样式和约定。在这里,我们展示了一些这些样式的示例。文中的代码词汇、数据库表名、文件夹名称、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 账号如以下所示:“pandas 项目坚持的另一个约定是 import pandas as pd 导入语句。”
一段代码如下所示:
# Creating an array
import numpy as np
a = np.array([2,4,6,8,10])
print(a)
任何命令行输入或输出如下所示:
$ mkdir
$ cd css
粗体:表示新术语、重要词汇或在屏幕上看到的词语。例如,菜单或对话框中的词语会以这样的形式出现在文本中。举个例子:“从管理面板中选择系统信息。”
警告或重要说明如下所示。
小贴士和技巧如下所示。
联系我们
我们始终欢迎读者的反馈。
一般反馈:如果您对本书的任何内容有疑问,请在邮件主题中提及书名,并通过电子邮件联系我们 customercare@packtpub.com。
勘误表:尽管我们已尽一切努力确保内容的准确性,但难免会有错误。如果您在本书中发现错误,我们将不胜感激您能向我们报告。请访问 www.packtpub.com/support/err…,选择您的书籍,点击“勘误表提交表单”链接,并填写相关细节。
盗版:如果您在网上发现任何形式的非法复制作品,我们将不胜感激您能提供位置地址或网站名称。请通过 copyright@packt.com 与我们联系,并附上相关链接。
如果您有兴趣成为作者:如果您在某个领域拥有专业知识,并且有兴趣撰写或参与编写一本书,请访问authors.packtpub.com。
评论
请留下评论。阅读并使用本书后,为什么不在您购买该书的网站上留下评论呢?潜在的读者可以查看并参考您的公正意见来做出购买决策,我们在 Packt 也可以了解您对我们产品的看法,而我们的作者也能看到您对他们书籍的反馈。谢谢!
如需了解有关 Packt 的更多信息,请访问packt.com。
第一部分:数据分析基础
本节的主要目标是为学习者建立基础的数据分析技能。这些技能包括使用 Jupyter Notebook,以及基本的 Python 库,如 NumPy、Pandas、Scipy 和 statsmodels。同时,本节重点讲解统计学和线性代数的主观知识,以提升数学能力。
本节包括以下章节:
-
第一章,Python 库入门
-
第二章,NumPy 和 pandas
-
第三章,统计学
-
第四章,线性代数
第一章:开始使用 Python 库
如你所知,Python 已成为最受欢迎的标准编程语言之一,是数据科学相关操作的完整工具包。Python 提供了大量的库,如 NumPy、Pandas、SciPy、Scikit-Learn、Matplotlib、Seaborn 和 Plotly。这些库为数据分析提供了一个完整的生态系统,广泛应用于数据分析师、数据科学家和业务分析师的工作中。Python 还具有灵活性、易学性、快速开发、大型活跃社区的特点,并能处理复杂的数值、科学和研究应用。所有这些特点使其成为数据分析的首选语言。
本章将重点介绍各种数据分析过程,如 KDD、SEMMA 和 CRISP-DM。之后,我们将提供数据分析与数据科学的比较,并探讨数据分析师和数据科学家的角色及不同的技能要求。最后,我们将转向安装各种 Python 库、IPython、Jupyter Lab 和 Jupyter Notebook,并查看 Jupyter Notebooks 的一些高级功能。
在本章导言中,我们将涵盖以下内容:
-
理解数据分析
-
数据分析的标准过程
-
KDD 过程
-
SEMMA
-
CRISP-DM
-
比较数据分析与数据科学
-
数据分析师和数据科学家的技能要求
-
安装 Python 3
-
本书使用的软件
-
使用 IPython 作为 Shell
-
使用 Jupyter Lab
-
使用 Jupyter Notebooks
-
Jupyter Notebooks 的高级功能
开始吧!
理解数据分析
21 世纪是信息的时代。我们正处于信息时代,这意味着我们日常生活的几乎每个方面都在生成数据。不仅如此,商业运营、政府运营和社交媒体的发布也在生成大量数据。这些数据随着业务、政府、科学、工程、健康、社会、气候和环境活动的不断生成而日积月累。在这些决策领域中,我们需要一个系统化、通用、高效且灵活的分析和科学处理系统,以便能够从生成的数据中获得有价值的见解。
在今天的智能世界里,数据分析为商业和政府运营提供了有效的决策过程。数据分析是检查、预处理、探索、描述和可视化给定数据集的活动。数据分析过程的主要目标是发现决策所需的信息。数据分析提供了多种方法、工具和技术,所有这些都可以应用于商业、社会科学和基础科学等不同领域。
让我们来看看 Python 生态系统中的一些核心基础数据分析库:
-
NumPy:这是“数字化 Python”的缩写。它是 Python 中最强大的科学计算库,能够高效处理多维数组、矩阵,并进行数学计算。
-
SciPy:这是一个强大的科学计算库,用于执行科学、数学和工程操作。
-
Pandas:这是一个数据探索和处理库,提供如 DataFrame 等表格数据结构,并提供多种数据分析和处理方法。
-
Scikit-learn:代表“机器学习科学工具包”。这是一个机器学习库,提供多种监督和无监督算法,如回归、分类、降维、聚类分析和异常检测。
-
Matplotlib:这是核心的数据可视化库,是 Python 中所有其他可视化库的基础库。它提供 2D 和 3D 图表、图形、图示和数据探索图表,运行在 NumPy 和 SciPy 之上。
-
Seaborn:基于 Matplotlib,提供易于绘制的高级互动图表和更有组织的可视化。
-
Plotly:Plotly 是一个数据可视化库,提供高质量的互动图表,如散点图、折线图、条形图、直方图、箱线图、热力图和子图。
安装所需库和软件的说明将在本书中按需提供。同时,我们将讨论各种数据分析过程,如标准过程、KDD、SEMMA 和 CRISP-DM。
数据分析的标准过程
数据分析是指对数据进行调查,从中发现有意义的洞察并得出结论。该过程的主要目标是收集、过滤、清理、转换、探索、描述、可视化并传达从数据中获得的洞察,以发现决策所需的信息。一般来说,数据分析过程包括以下几个阶段:
-
数据收集:从多个来源收集并整理数据。
-
数据预处理:过滤、清理并将数据转换为所需的格式。
-
数据分析与发现洞察:探索、描述和可视化数据,发现洞察并得出结论。
-
洞察解读:理解洞察,并找出每个变量对系统的影响。
-
讲故事:以故事的形式传达你的结果,使普通人也能理解。
我们可以通过以下过程图来总结数据分析过程的这些步骤:
本节中,我们已经涵盖了标准的数据分析过程,重点是寻找可解释的洞察并将其转化为用户故事。在接下来的章节中,我们将讨论 KDD 过程。
KDD 过程
KDD的全称是数据中的知识发现或数据库中的知识发现。许多人将 KDD 视为数据挖掘的同义词。数据挖掘被称为发现有趣模式的知识发现过程。KDD 的主要目标是从大型数据库、数据仓库以及其他 Web 和信息存储库中提取或发现隐藏的有趣模式。KDD 过程包括七个主要阶段:
-
数据清洗:在此第一阶段,数据进行预处理。在这里,噪声被去除,缺失值得到处理,异常值被检测。
-
数据集成:在此阶段,来自不同来源的数据通过数据迁移和 ETL 工具进行整合。
-
数据选择:在此阶段,相关的分析任务数据被重新收集。
-
数据转换:在此阶段,数据被转换为适合分析的所需形式。
-
数据挖掘:在此阶段,使用数据挖掘技术发现有用的未知模式。
-
模式评估:在此阶段,提取的模式将被评估。
-
知识呈现:在模式评估之后,提取的知识需要进行可视化并呈现给业务人员,以便做出决策。
完整的 KDD 过程如下图所示:
KDD 是一个迭代过程,旨在提升数据质量、集成和转换,以获取更优的系统。现在,让我们讨论 SEMMA 过程。
SEMMA
SEMMA的全称是样本、探索、修改、建模和评估。这个顺序的数据挖掘过程是由 SAS 公司开发的。SEMMA 过程包括五个主要阶段:
-
样本:在此阶段,我们识别不同的数据库并将它们合并。之后,我们选择足够的用于建模过程的数据样本。
-
探索:在此阶段,我们理解数据,发现变量之间的关系,进行数据可视化,并获得初步的解释。
-
修改:在此阶段,数据为建模准备好。该阶段涉及处理缺失值、检测异常值、转换特征和创建新的附加特征。
-
建模:在此阶段,主要关注选择和应用不同的建模技术,例如线性回归、逻辑回归、反向传播网络、KNN、支持向量机、决策树和随机森林。
-
评估:在最后阶段,开发的预测模型通过性能评估指标进行评估。
下图展示了这一过程:
上图展示了 SEMMA 过程中的各个步骤。SEMMA 强调模型构建和评估。现在,让我们讨论 CRISP-DM 过程。
CRISP-DM
CRISP-DM的全称是跨行业数据挖掘过程。CRISP-DM 是一个经过明确定义、结构良好、被验证的机器学习、数据挖掘和商业智能项目过程。它是一种强大、灵活、循环、有用且实用的方法,用于解决商业问题。该过程从多个数据库中发现隐藏的有价值的信息或模式。CRISP-DM 过程包含六个主要阶段:
-
商业理解:在第一阶段,主要目标是理解商业场景和需求,为设计分析目标和初步行动计划做准备。
-
数据理解:在这个阶段,主要目标是理解数据及其收集过程,进行数据质量检查,并获得初步的见解。
-
数据准备:在这个阶段,主要目标是准备适合分析的数据。这包括处理缺失值、检测并处理异常值、数据归一化以及特征工程。对于数据科学家/分析师而言,这一阶段是最耗时的。
-
建模:这是整个过程中最激动人心的阶段,因为这是设计预测模型的环节。首先,分析师需要决定建模技术,并根据数据开发模型。
-
评估:一旦模型开发完成,就该评估和测试模型在验证数据和测试数据上的表现,使用诸如 MSE、RMSE、R-Square(回归)以及准确率、精确率、召回率和 F1 值等模型评估指标。
-
部署:在最后阶段,前一步选择的模型将被部署到生产环境中。这需要数据科学家、软件开发人员、DevOps 专家和商业专业人士的团队协作。
以下图表展示了 CRISP-DM 过程的完整周期:
标准过程侧重于通过故事的形式发现洞察并进行解释,而 KDD 则侧重于基于数据的模式发现并进行可视化。SEMMA 主要关注模型构建任务,而 CRISP-DM 则专注于商业理解和部署。现在我们了解了与数据分析相关的一些过程,让我们比较一下数据分析和数据科学,了解它们之间的关系以及彼此的区别。
比较数据分析与数据科学
数据分析是探索数据的过程,目的是发现帮助我们做出业务决策的模式。它是数据科学的一个子领域。数据分析方法和工具被业务分析师、数据科学家和研究人员广泛应用于多个业务领域。其主要目标是提高生产力和利润。数据分析从不同来源提取和查询数据,进行探索性数据分析,数据可视化,准备报告,并呈现给业务决策者。
另一方面,数据科学是一个跨学科领域,采用科学方法从结构化和非结构化数据中提取洞察力。数据科学是所有相关领域的集合,包括数据分析、数据挖掘、机器学习和其他相关领域。数据科学不仅限于探索性数据分析,还用于开发模型和预测算法,如股票价格、天气、疾病、欺诈预测,以及推荐系统,如电影、书籍和音乐推荐。
数据分析师和数据科学家的角色
数据分析师收集、过滤、处理数据,并应用所需的统计概念,从数据中捕捉模式、趋势和洞察力,并准备报告以支持决策。数据分析师的主要目标是帮助公司通过发现的模式和趋势解决业务问题。数据分析师还评估数据质量,并处理与数据采集相关的问题。数据分析师应精通编写 SQL 查询、发现模式、使用可视化工具,以及使用报告工具,如 Microsoft Power BI、IBM Cognos、Tableau、QlikView、Oracle BI 等。
数据科学家比数据分析师更具技术性和数学性。数据科学家偏向于研究和学术,而数据分析师则更加偏向于应用。数据科学家通常需要预测未来事件,而数据分析师则从数据中提取重要洞察。数据科学家提出自己的问题,而数据分析师回答给定的问题。最后,数据科学家关注将要发生什么,而数据分析师关注迄今为止已经发生了什么。我们可以通过以下表格总结这两个角色:
| 特点 | 数据科学家 | 数据分析师 |
|---|---|---|
| 背景 | 基于数据预测未来事件和场景 | 从数据中发现有意义的洞察 |
| 角色 | 提出有利于业务的问题 | 解决业务问题以作出决策 |
| 数据类型 | 处理结构化和非结构化数据 | 只处理结构化数据 |
| 编程 | 高级编程 | 基础编程 |
| 技能集 | 统计学、机器学习算法、自然语言处理和深度学习知识 | 统计学、SQL 和数据可视化知识 |
| 工具 | R、Python、SAS、Hadoop、Spark、TensorFlow 和 Keras | Excel、SQL、R、Tableau 和 QlikView |
现在我们已经了解了数据分析师和数据科学家的定义,以及它们之间的区别,让我们来看看成为其中一员所需要的各种技能。
数据分析师与数据科学家的技能集
数据分析师是通过数据发现洞察并创造价值的人。这有助于决策者了解业务表现如何。数据分析师必须掌握以下技能:
-
探索性数据分析(EDA):EDA 是数据分析师的一个重要技能。它有助于检查数据以发现模式、检验假设并确保假设的正确性。
-
关系型数据库:至少了解一种关系型数据库工具,如 MySQL 或 Postgre,是必须的。SQL 是处理关系型数据库时必备的技能。
-
可视化和商业智能工具:一图胜千言。视觉效果对人类有更大的影响,且视觉是表达洞察的清晰简便的方式。像 Tableau、QlikView、MS Power BI 和 IBM Cognos 这样的可视化和商业智能工具可以帮助分析师进行可视化并准备报告。
-
电子表格:了解 MS Excel、WPS、Libra 或 Google Sheets 是必不可少的,它们用于以表格形式存储和管理数据。
-
讲故事与展示技巧:讲故事的艺术是另一个必备技能。数据分析师应该擅长将数据事实与一个想法或事件联系起来,并将其转化为一个故事。
另一方面,数据科学家的主要工作是通过数据解决问题。为了做到这一点,他们需要了解客户的需求、领域、问题空间,并确保获得他们真正需要的东西。数据科学家的任务因公司而异。有些公司使用数据分析师,并仅将“数据科学家”这一职称用来提升职位的光环。还有一些公司将数据分析师的任务与数据工程师的工作结合起来,并赋予数据科学家这一职称;还有一些则将他们分配到以机器学习为主的数据可视化任务中。
数据科学家的任务因公司而异。有些公司将数据科学家视为知名的数据分析师,并将其职责与数据工程师结合起来。其他公司则让他们执行机器上的密集型数据可视化任务。
数据科学家必须是多面手,能够担任多个角色,包括数据分析师、统计学家、数学家、程序员、机器学习或自然语言处理工程师。大多数人并不在所有这些领域都有足够的技能或是专家。而且,要具备足够的技能需要大量的努力和耐心。这就是为什么数据科学无法在 3 到 6 个月内学成的原因。学习数据科学是一个过程。数据科学家应该拥有多种技能,诸如以下这些:
-
数学与统计学:大多数机器学习算法都基于数学和统计学。数学知识帮助数据科学家开发定制的解决方案。
-
数据库:掌握 SQL 知识,能让数据科学家与数据库交互,收集数据以进行预测和推荐。
-
机器学习:了解监督学习技术,如回归分析、分类技术,以及无监督学习技术,如聚类分析、异常值检测和降维。
-
编程技能:编程知识帮助数据科学家自动化其推荐的解决方案。建议掌握 Python 和 R。
-
故事讲述与演讲技巧:通过 PowerPoint 演示文稿以故事讲述的形式传达结果。
-
大数据技术:了解 Hadoop 和 Spark 等大数据平台,有助于数据科学家为大型企业开发大数据解决方案。
-
深度学习工具:深度学习工具,如 Tensorflow 和 Keras,在自然语言处理(NLP)和图像分析中得到应用。
除了这些技能外,数据科学专业人员还需要掌握网络抓取工具/包,用于从不同来源提取数据,以及用于设计原型解决方案的 Web 应用框架,如 Flask 或 Django。这些都是数据科学专业人员所需的技能。
现在我们已经介绍了数据分析和数据科学的基础知识,接下来让我们深入了解数据分析所需的基本设置。在下一节中,我们将学习如何安装 Python。
安装 Python 3
安装 Python 3 的安装程序文件可以从官方网站(www.python.org/downloads/)轻松下载,支持 Windows、Linux 和 Mac 32 位或 64 位系统。只需双击该安装程序即可进行安装。该安装程序还包含一个名为 "IDLE" 的 IDE,可用于开发。在接下来的几个部分中,我们将深入探讨每个操作系统的安装方法。
Windows 上的 Python 安装与设置
本书基于最新的 Python 3 版本。书中的所有代码都是用 Python 3 编写的,因此在开始编码之前,我们需要先安装 Python 3。Python 是一种开源、分发和免费使用的语言,并且具有商业使用许可。Python 有许多实现,包括商业实现和分发版本。在本书中,我们将专注于标准的 Python 实现,它保证与 NumPy 兼容。
您可以从 Python 官方网站下载 Python 3.9.x:www.python.org/downloads/。在这里,您可以找到适用于 Windows、Linux、Mac OS X 和其他操作系统平台的安装文件。您还可以在 docs.python.org/3.7/using/index.html 找到有关如何安装和使用 Python 的说明。
您需要在系统上安装 Python 3.5.x 或更高版本。Python 2.7 的支持结束日期从 2015 年推迟到 2020 年,但在撰写本书时,Python 2.7 将不再由 Python 社区提供支持和维护。
在撰写本书时,我们在 Windows 10 虚拟机上安装了 Python 3.8.3 作为先决条件:www.python.org/ftp/python/3.8.3/python-3.8.3.exe。
在 Linux 上安装和设置 Python
与其他操作系统相比,在 Linux 上安装 Python 要容易得多。要安装基础库,请运行以下命令行指令:
$ pip3 install numpy scipy pandas matplotlib jupyter notebook
如果您在使用的机器上没有足够的权限,在执行上述命令之前,可能需要运行sudo命令。
使用 GUI 安装程序在 Mac OS X 上安装和设置 Python
Python 可以通过从 Python 官方网站下载的安装文件进行安装。安装文件可以从其官方网页(www.python.org/downloads/mac-osx/)下载,适用于 macOS。此安装程序还包含一个名为 "IDLE" 的 IDE,可用于开发。
在 Mac OS X 上使用 brew 安装和设置 Python
对于 Mac 系统,您可以使用 Homebrew 包管理器来安装 Python。它将简化为开发人员、研究人员和科学家安装所需应用程序的过程。brew install 命令用于安装其他应用程序,例如安装 python3 或任何其他 Python 包,如 NLTK 或 SpaCy。
要安装最新版本的 Python,您需要在终端执行以下命令:
$ brew install python3
安装后,您可以通过运行以下命令来确认您已安装的 Python 版本:
$ python3 --version
Python 3.7.4
您还可以通过运行以下命令从命令行打开 Python Shell:
$ python3
现在我们知道如何在系统上安装 Python,让我们深入了解开始数据分析所需的实际工具。
本书中使用的软件
让我们讨论一下本书中将使用的软件。在本书中,我们将使用 Anaconda IDE 来进行数据分析。在安装之前,我们先了解一下什么是 Anaconda。
只要系统安装了 Python 程序,Python 程序就可以轻松运行。我们可以在记事本上编写程序并在命令提示符上运行它。我们还可以在不同的 IDE(如 Jupyter Notebook、Spyder 和 PyCharm)上编写和运行 Python 程序。Anaconda 是一个免费可用的开源软件包,包含各种数据处理 IDE 和一些用于数据分析的包,如 NumPy、SciPy、Pandas、Scikit-learn 等等。Anaconda 可以轻松下载和安装,具体如下:
-
从
www.anaconda.com/distribution/下载安装程序。 -
选择您正在使用的操作系统。
-
从 Python 3.7 版本部分选择 32 位或 64 位安装程序选项并开始下载。
-
双击运行安装程序。
-
安装完成后,在“开始”菜单中检查您的程序或搜索 Anaconda。
Anaconda 还有一个 Anaconda Navigator,这是一个桌面 GUI 应用程序,用于启动应用程序,如 Jupyter Notebook、Spyder、Rstudio、Visual Studio Code 和 JupyterLab:
现在,让我们看一下 IPython,这是一个基于 shell 的计算环境,用于数据分析。
使用 IPython 作为 shell
IPython 是一个交互式 shell,相当于 Matlab 或 Mathematica 等交互式计算环境。这个交互式 shell 是为快速实验而创建的。对于进行小型实验的数据专业人员非常有用。
IPython shell 提供以下功能:
-
方便访问系统命令。
-
轻松编辑内联命令。
-
Tab 键自动完成,帮助您查找命令并加速任务。
-
命令历史记录,帮助您查看先前使用的命令列表。
-
轻松执行外部 Python 脚本。
-
使用 Python 调试器轻松调试。
现在,让我们在 IPython 上执行一些命令。要启动 IPython,请在命令行上使用以下命令:
$ ipython3
当您运行上述命令时,将出现以下窗口:
现在,让我们了解并执行 IPython shell 提供的一些命令:
- 历史命令: 使用
history命令来查看以前使用过的命令列表。下面的截图显示了如何在 IPython 中使用history命令:
- 系统命令: 我们还可以使用感叹号 (
!) 从 IPython 中运行系统命令。在这里,感叹号后的输入命令被视为系统命令。例如,!date将显示系统的当前日期,而!pwd将显示当前工作目录:
- 编写函数: 我们可以像在任何 IDE 中(如 Jupyter Notebook、Python IDLE、PyCharm 或 Spyder)编写函数一样编写它们。让我们看一个函数的例子:
- 退出 Ipython Shell: 你可以使用
quit()或exit(),或者按CTRL + D来退出或退出 IPython shell:
你还可以使用quit()命令退出 IPython shell:
在本小节中,我们已经了解了一些可以在 IPython shell 中使用的基本命令。现在,让我们讨论如何在 IPython shell 中使用help命令。
阅读手册页
在 IPython shell 中,我们可以使用help命令打开可用命令列表。并不需要写出函数的完整名称。你只需输入几个初始字符,然后按tab键,它就会找到你正在寻找的词。例如,让我们使用arrange()函数。我们可以通过两种方式来获取关于函数的帮助:
- 使用帮助功能: 让我们输入
help并写入函数的几个初始字符。然后,按tab键,使用箭头键选择一个函数,按Enter键:
- 使用问号: 我们还可以在函数名称后使用问号。以下截图展示了这个例子:
在本小节中,我们了解了为模块函数提供的帮助和问号支持。我们还可以通过库文档获得帮助。让我们讨论如何获取 Python 数据分析库的文档。
在哪里找到 Python 数据分析库的帮助和参考资料
以下表格列出了我们在本章中讨论的 Python 数据分析库的文档网站:
| 包/软件 | 描述 |
|---|---|
| NumPy | numpy.org/doc/ |
| SciPy | docs.scipy.org/doc/ |
| Pandas | pandas.pydata.org/docs/ |
| Matplotlib | matplotlib.org/3.2.1/contents.html |
| Seaborn | seaborn.pydata.org/ |
| Scikit-learn | scikit-learn.org/stable/ |
| Anaconda | www.anaconda.com/distribution/ |
你还可以在 StackOverflow 平台上找到与 NumPy、SciPy、Pandas、Matplotlib、Seaborn 和 Scikit-learn 相关的各种 Python 编程问题的答案。你还可以在 GitHub 上提出与上述库相关的问题。
使用 JupyterLab
JupyterLab 是一个下一代基于 Web 的用户界面。它提供了一组合适的数据分析和机器学习产品开发工具,如文本编辑器、笔记本、代码控制台和终端。它是一个灵活且强大的工具,应该成为任何数据分析师工具包的一部分:
你可以使用conda、pip或pipenv来安装 JupyterLab。
要使用conda安装,可以使用以下命令:
$ conda install -c conda-forge jupyterlab
要使用pip安装,可以使用以下命令:
$ pip install jupyterlab
要使用pipenv安装,可以使用以下命令:
$ pipenv install jupyterlab
在这一节中,我们已经学习了如何安装 Jupyter Lab。在下一节中,我们将重点介绍 Jupyter Notebooks。
使用 Jupyter Notebooks
Jupyter Notebook 是一个 Web 应用程序,用于创建包含代码、文本、图形、链接、数学公式和图表的数据分析笔记本。最近,社区推出了基于 Web 的下一代 Jupyter Notebooks,称为 JupyterLab。你可以通过以下链接查看这些笔记本集:
这些笔记本通常作为教育工具使用,或者用于展示 Python 软件。我们可以从纯 Python 代码或特殊的笔记本格式导入或导出笔记本。笔记本可以在本地运行,或者我们可以通过运行专用的笔记本服务器使它们在网上可用。一些云计算解决方案,如 Wakari、PiCloud 和 Google Colaboratory,允许你在云端运行笔记本。
"Jupyter" 是一个首字母缩略词,代表 Julia、Python 和 R。最初,开发者为这三种语言实现了它,但现在,它也可以用于其他多种语言,包括 C、C++、Scala、Perl、Go、PySpark 和 Haskell:
Jupyter Notebook 提供以下功能:
-
它具有在浏览器中编辑代码并保持正确缩进的能力。
-
它具有从浏览器执行代码的能力。
-
它具有在浏览器中显示输出的能力。
-
它可以在单元格输出中渲染图形、图像和视频。
-
它具有以 PDF、HTML、Python 文件和 LaTex 格式导出代码的能力。
我们还可以通过在 Anaconda 提示符中运行以下命令,在 Jupyter Notebooks 中同时使用 Python 2 和 3:
# For Python 2.7
conda create -n py27 python=2.7 ipykernel
# For Python 3.5
conda create -n py35 python=3.5 ipykernel
现在我们已经了解了各种工具和库,并且也安装了 Python,让我们进入最常用工具之一 Jupyter Notebooks 的一些高级功能。
Jupyter Notebooks 的高级功能
Jupyter Notebook 提供了各种高级功能,例如快捷键、安装其他内核、执行 shell 命令和使用各种扩展来加快数据分析操作。让我们开始逐一了解这些功能。
快捷键
用户可以通过选择帮助菜单中的“快捷键”选项,或者使用Cmd + Shift + P快捷键,在 Jupyter Notebook 内找到所有可用的快捷命令。这将显示快速选择栏,其中包含所有快捷命令以及每个命令的简要说明。使用这个栏非常简单,用户可以在忘记某些快捷键时使用它:
安装其他内核
Jupyter 可以运行多个内核支持不同的语言。使用 Anaconda 设置特定语言的环境非常容易。例如,可以通过在 Anaconda 中运行以下命令设置 R 内核:
$ conda install -c r r-essentials
然后应会出现 R 内核,如下图所示:
运行 shell 命令
在 Jupyter Notebook 中,用户可以运行 Unix 和 Windows 的 shell 命令。shell 提供了一个与计算机进行通信的接口。用户在运行任何命令前需要加上 !(感叹号):
Notebook 扩展
Notebook 扩展(或 nbextensions)相比基础的 Jupyter Notebook 增加了更多功能。这些扩展提升了用户的体验和界面。用户可以通过选择 NBextensions 标签轻松选择任何扩展。
在 Jupyter Notebook 中使用 conda 安装 nbextension,运行以下命令:
conda install -c conda-forge jupyter_nbextensions_configurator
在 Jupyter Notebook 中使用 pip 安装 nbextension,运行以下命令:
pip install jupyter_contrib_nbextensions && jupyter contrib nbextension install
如果在 macOS 上遇到权限错误,只需运行以下命令:
pip install jupyter_contrib_nbextensions && jupyter contrib nbextension install --user
所有可配置的 nbextensions 将显示在一个不同的标签中,如下图所示:
现在,让我们探索 Notebook 扩展的一些有用功能:
- Hinterland:此扩展为每个按键提供自动完成菜单,像 PyCharm 一样在单元格中工作:
- 目录:此扩展会在侧边栏或导航菜单中显示所有标题。它可以调整大小、拖动、折叠,并且可以停靠:
- 执行时间:此扩展显示单元格执行的时间以及完成单元格代码所需的时间:
-
拼写检查器:拼写检查器会检查并验证每个单元格中书写的拼写,并高亮显示任何拼写错误的单词。
-
变量选择器:此扩展跟踪用户的工作空间。它显示用户创建的所有变量的名称,并显示它们的类型、大小、形状和数值。
- 幻灯片放映:Notebook 结果可以通过幻灯片放映进行展示。这是讲故事的绝佳工具。用户可以轻松将 Jupyter Notebooks 转换为幻灯片,而无需使用 PowerPoint。如以下截图所示,可以通过视图菜单中的单元格工具栏选项启动幻灯片放映:
Jupyter Notebook 还允许你在幻灯片中显示或隐藏任何单元格。将幻灯片选项添加到视图菜单的单元格工具栏后,你可以在每个单元格中使用幻灯片类型下拉列表,并选择不同的选项,如下图所示:
- 嵌入 PDF 文档:Jupyter Notebook 用户可以轻松添加 PDF 文档。以下语法需要运行以添加 PDF 文档:
from IPython.display import IFrame
IFrame('https://arxiv.org/pdf/1811.02141.pdf', width=700, height=400)
这将产生如下输出:
- 嵌入 YouTube 视频:Jupyter Notebook 用户可以轻松添加 YouTube 视频。以下语法需要运行以添加 YouTube 视频:
from IPython.display import YouTubeVideo
YouTubeVideo('ukzFI9rgwfU', width=700, height=400)
这将产生如下输出:
通过这些,你现在了解了数据分析及其所涉及的过程,以及它所包含的角色。你还学习了如何安装 Python 并使用 Jupyter Lab 和 Jupyter Notebook。在接下来的章节中,你将进一步学习各种 Python 库和数据分析技术。
总结
在本章中,我们讨论了各种数据分析过程,包括 KDD、SEMMA 和 CRISP-DM。接着我们讨论了数据分析师和数据科学家的角色与技能要求。随后,我们安装了 NumPy、SciPy、Pandas、Matplotlib、IPython、Jupyter Notebook、Anaconda 和 Jupyter Lab,这些都是我们在本书中将要使用的工具。你也可以选择安装 Anaconda 或 Jupyter Lab,它们自带了 NumPy、Pandas、SciPy 和 Scikit-learn。
接着,我们实现了一个向量加法程序,并了解到 NumPy 相比其他库提供了更优的性能。我们还探讨了可用的文档和在线资源。此外,我们讨论了 Jupyter Lab、Jupyter Notebook 及其功能。
在下一章,第二章,NumPy 和 Pandas 中,我们将深入了解 NumPy 和 Pandas 的内部实现,并探索一些与数组和数据框(DataFrames)相关的基本概念。
第二章:NumPy 和 pandas
现在我们已经理解了数据分析、数据分析过程以及在不同平台上的安装,是时候学习 NumPy 数组和 pandas DataFrames 了。本章将带你了解 NumPy 数组和 pandas DataFrames 的基础知识。在本章结束时,你将对 NumPy 数组、pandas DataFrames 及其相关函数有基本的理解。
pandas 以面板数据(一个计量经济学术语)和 Python 数据分析命名,是一个流行的开源 Python 库。在本章中,我们将学习 pandas 的基本功能、数据结构和操作。官方的 pandas 文档坚持将该项目命名为全小写的 pandas。pandas 项目坚持的另一个惯例是使用 import pandas as pd 的导入语句。
本章我们将重点讨论以下主题:
-
理解 NumPy 数组
-
NumPy 数组数值数据类型
-
操作数组形状
-
NumPy 数组的堆叠
-
划分 NumPy 数组
-
更改 NumPy 数组的数据类型
-
创建 NumPy 视图和副本
-
切片 NumPy 数组
-
布尔和花式索引
-
广播数组
-
创建
pandasDataFrames -
理解
pandasSeries -
阅读和查询 Quandl 数据
-
描述
pandasDataFrames -
分组和连接
pandasDataFrames -
处理缺失值
-
创建数据透视表
-
处理日期
技术要求
本章具有以下技术要求:
-
你可以在以下 GitHub 链接找到代码和数据集:
github.com/PacktPublishing/Python-Data-Analysis-Third-Edition/tree/master/Chapter02。 -
所有代码块都可以在
ch2.ipynb中找到。 -
本章使用四个 CSV 文件(
WHO_first9cols.csv、dest.csv、purchase.csv和tips.csv)进行练习。 -
本章我们将使用 NumPy、
pandas和 Quandl Python 库。
理解 NumPy 数组
可以使用 pip 或 brew 在 PC 上安装 NumPy,但如果用户使用 Jupyter Notebook,则无需安装。NumPy 已经预装在 Jupyter Notebook 中。我建议你使用 Jupyter Notebook 作为 IDE,因为我们将在 Jupyter Notebook 中执行所有代码。我们在第一章中,Python 库入门,已经展示了如何安装 Anaconda,这是一个完整的数据分析套件。NumPy 数组是一系列同质的项目。同质意味着数组中的所有元素都是相同的数据类型。让我们使用 NumPy 创建一个数组。你可以使用 array() 函数结合一个项目列表来创建数组。用户还可以固定数组的数据类型。可能的数据类型有 bool、int、float、long、double 和 long double。
让我们来看一下如何创建一个空数组:
# Creating an array
import numpy as np
a = np.array([2,4,6,8,10])
print(a)
Output:
[ 2 4 6 8 10]
创建 NumPy 数组的另一种方法是使用 arange()。它会创建一个均匀间隔的 NumPy 数组。可以传递三个值 —— start、stop 和 step —— 给 arange(start,[stop],step) 函数。start 是范围的起始值,stop 是范围的结束值,而 step 是该范围内的增量。stop 参数是必须的。在以下示例中,我们使用 1 作为起始值,11 作为结束值。arange(1,11) 函数将返回从 1 到 10 的值,步长默认为 1。arange() 函数会生成一个比 stop 参数值小 1 的值。让我们通过以下示例来理解这一点:
# Creating an array using arange()
import numpy as np
a = np.arange(1,11)
print(a)
Output:
[ 1 2 3 4 5 6 7 8 9 10]
除了 array() 和 arange() 函数外,还有其他选项,如 zeros()、ones()、full()、eye() 和 random(),这些也可以用来创建 NumPy 数组,因为这些函数是初始占位符。以下是每个函数的详细说明:
-
zeros():zeros()函数为给定维度创建一个全为 0 的数组。 -
ones():ones()函数为给定维度创建一个全为 1 的数组。 -
fulls():full()函数生成一个具有常数值的数组。 -
eyes():eye()函数创建一个单位矩阵。 -
random():random()函数创建一个具有任意给定维度的数组。
让我们通过以下示例来理解这些函数:
import numpy as np
# Create an array of all zeros
p = np.zeros((3,3))
print(p)
# Create an array of all ones
q = np.ones((2,2))
print(q)
# Create a constant array
r = np.full((2,2), 4)
print(r)
# Create a 2x2 identity matrix
s = np.eye(4)
print(s)
# Create an array filled with random values
t = np.random.random((3,3))
print(t)
这将产生以下输出:
[[0\. 0\. 0.]
[0\. 0\. 0.]
[0\. 0\. 0.]]
[[1\. 1.]
[1\. 1.]]
[[4 4]
[4 4]]
[[1\. 0\. 0\. 0.]
[0\. 1\. 0\. 0.]
[0\. 0\. 1\. 0.]
[0\. 0\. 0\. 1.]]
[[0.16681892 0.00398631 0.61954178]
[0.52461924 0.30234715 0.58848138]
[0.75172385 0.17752708 0.12665832]]
在前面的代码中,我们已经看到了一些用于创建全零值、全一值和全常数值数组的内置函数。之后,我们使用 eye() 函数创建了一个单位矩阵,并使用 random.random() 函数创建了一个随机矩阵。接下来,我们将在下一节看到一些其他的数组特性。
数组特性
一般来说,NumPy 数组是一种同质的数据结构,所有项的类型相同。数组的主要优点是其存储大小的确定性,因为它们包含相同类型的项。Python 列表使用循环来迭代元素并对其执行操作。NumPy 数组的另一个优点是提供矢量化操作,而不是逐个迭代每个项并对其进行操作。NumPy 数组的索引方式与 Python 列表一样,从 0 开始。NumPy 使用优化的 C API 来加速数组操作的处理。
让我们像前面章节一样,使用 arange() 函数创建一个数组,并检查它的数据类型:
# Creating an array using arange()
import numpy as np
a = np.arange(1,11)
print(type(a))
print(a.dtype)
Output: <class 'numpy.ndarray'>
int64
当你使用 type() 时,它会返回 numpy.ndarray。这意味着 type() 函数返回的是容器的类型。当你使用 dtype() 时,它将返回 int64,因为它是元素的类型。如果你使用的是 32 位的 Python,你也可能得到 int32 作为输出。这两种情况都使用整数(32 位和 64 位)。一维的 NumPy 数组也被称为向量。
让我们找出几分钟前我们生成的向量的形状:
print(a.shape)
Output: (10,)
如你所见,该向量有 10 个元素,值范围从 1 到 10。数组的 shape 属性是一个元组;在这个例子中,它是一个包含一个元素的元组,表示每个维度的长度。
选择数组元素
在这一部分,我们将学习如何选择数组中的元素。让我们看一个 2*2 矩阵的例子:
a = np.array([[5,6],[7,8]])
print(a)
Output: [[5 6]
[7 8]]
在前面的例子中,矩阵是通过 array() 函数创建的,输入是一个包含列表的列表。
选择数组元素非常简单。我们只需要指定矩阵的索引 a[m,n]。这里,m 是行索引,n 是列索引。我们现在将按顺序选择矩阵中的每个元素,如下代码所示:
print(a[0,0])
Output: 5
print(a[0,1])
Output: 6
printa([1,0])
Output: 7
printa([1,1])
Output: 8
在前面的代码示例中,我们尝试使用数组索引访问数组的每个元素。你也可以通过这里的图示理解这一点:
在前面的图示中,我们可以看到它有四个块,每个块代表一个数组元素。每个块中的数值显示其索引。
在这一部分,我们已经了解了数组的基本概念。现在,让我们继续学习数值数据类型的数组。
NumPy 数组数值数据类型
Python 提供了三种数值数据类型:整数类型、浮点类型和复数类型。在实际应用中,我们需要更多的数据类型来进行科学计算操作,以确保精度、范围和大小。NumPy 提供了大量的数学类型和数值类型。让我们看看下面的 NumPy 数值类型表格:
| 数据类型 | 详细信息 |
|---|---|
bool | 这是一个布尔类型,存储一个比特,取值为 True 或 False。 |
inti | 平台整数可以是 int32 或 int64。 |
int8 | 字节存储的值范围从 -128 到 127。 |
int16 | 该类型存储从 -32768 到 32767 的整数。 |
int32 | 该类型存储从 -2 ** 31 到 2 ** 31 -1 的整数。 |
int64 | 该类型存储从 -2 ** 63 到 2 ** 63 -1 的整数。 |
uint8 | 该类型存储无符号整数,范围从 0 到 255。 |
uint16 | 该类型存储无符号整数,范围从 0 到 65535。 |
uint32 | 该类型存储无符号整数,范围从 0 到 2 ** 32 – 1。 |
uint64 | 该类型存储无符号整数,范围从 0 到 2 ** 64 – 1。 |
float16 | 半精度浮点数;符号位,5 位指数和 10 位尾数。 |
float32 | 单精度浮点数;符号位,8 位指数和 23 位尾数。 |
float64 或 float | 双精度浮点数;符号位,11 位指数和 52 位尾数。 |
complex64 | 复数类型存储两个 32 位浮点数:实数和虚数。 |
complex128 或 complex | 复数类型存储两个 64 位浮点数:实数和虚数。 |
对于每种数据类型,都存在一个相应的转换函数:
print(np.float64(21))
Output: 21.0
print(np.int8(21.0))
Output: 42
print(np.bool(21))
Output: True
print(np.bool(0))
Output: False
print(np.bool(21.0))
Output: True
print(np.float(True))
Output: 1.0
print(np.float(False))
Output: 0.0
许多函数都有一个数据类型参数,通常是可选的:
arr=np.arange(1,11, dtype= np.float32)
print(arr)
Output:
[ 1\. 2\. 3\. 4\. 5\. 6\. 7\. 8\. 9\. 10.]
需要注意的是,你不能将复数转换为整数。如果尝试将复合数据类型转换为整数,将会遇到 TypeError。我们来看一下以下示例:
np.int(42.0 + 1.j)
这将产生以下输出:
如果你尝试将复数转换为浮点数,也会遇到同样的错误。
但是,你可以通过设置各个部分,将浮动值转换为复数。你也可以通过 real 和 imag 属性提取这些部分。我们通过以下示例来看一下:
c= complex(42, 1)
print(c)
Output: (42+1j)
print(c.real,c.imag)
Output: 42.0 1.0
在前面的示例中,你已经使用 complex() 方法定义了一个复数。同时,你通过 real 和 imag 属性提取了实部和虚部。接下来,让我们来看看 dtype 对象。
dtype 对象
我们在本章的前面部分已经看到,dtype 告诉我们数组中单个元素的类型。NumPy 数组的元素具有相同的数据类型,这意味着所有元素都有相同的 dtype。dtype 对象是 numpy.dtype 类的实例:
# Creating an array
import numpy as np
a = np.array([2,4,6,8,10])
print(a.dtype)
Output: 'int64'
dtype 对象还通过 itemsize 属性告诉我们数据类型的字节大小:
print(a.dtype.itemsize)
Output:8
数据类型字符代码
字符代码是为了与 Numeric 兼容。Numeric 是 NumPy 的前身。虽然不推荐使用它,但代码仍然被提供,因为它在不同的地方会出现。你应该使用 dtype 对象。以下表格列出了几种不同的数据类型及其相关字符代码:
| 类型 | 字符代码 |
|---|---|
| 整数 | i |
| 无符号整数 | u |
| 单精度浮动 | f |
| 双精度浮动 | d |
| 布尔值 | b |
| 复数 | D |
| 字符串 | S |
| Unicode | U |
| 空类型 | V |
我们来看以下代码,生成单精度浮动数组:
# Create numpy array using arange() function
var1=np.arange(1,11, dtype='f')
print(var1)
Output:
[ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.]
同样,以下代码创建了一个复数数组:
print(np.arange(1,6, dtype='D'))
Output:
[1.+0.j, 2.+0.j, 3.+0.j, 4.+0.j, 5.+0.j]
dtype 构造函数
有许多方法可以通过构造函数创建数据类型。构造函数用于实例化或赋值给对象。在本节中,我们将通过浮动数据类型的例子来理解数据类型的创建:
- 要尝试一个通用的 Python 浮动,请使用以下代码:
print(np.dtype(float))
Output: float64
- 要尝试带有字符代码的单精度浮动,请使用以下代码:
print(np.dtype('f'))
Output: float32
- 要尝试带有字符代码的双精度浮动,请使用以下代码:
print(np.dtype('d'))
Output: float64
- 要尝试带有双字符代码的
dtype构造函数,请使用以下代码:
print(np.dtype('f8'))
Output: float64
这里,第一个字符代表类型,第二个字符是指定类型字节数的数字,例如 2、4 或 8。
dtype 属性
dtype 类提供了多个有用的属性。例如,我们可以通过 dtype 属性获取数据类型的字符代码信息:
# Create numpy array
var2=np.array([1,2,3],dtype='float64')
print(var2.dtype.char)
Output: 'd'
type 属性对应数组元素的对象类型:
print(var2.dtype.type)
Output: <class 'numpy.float64'>
现在我们已经了解了 NumPy 数组中使用的各种数据类型,让我们在下一节中开始操作它们。
操作数组形状
在本节中,我们的主要关注点是数组操作。让我们学习一些 NumPy 的新 Python 函数,如 reshape()、flatten()、ravel()、transpose() 和 resize():
reshape()会改变数组的形状:
# Create an array
arr = np.arange(12)
print(arr)
Output: [ 0 1 2 3 4 5 6 7 8 9 10 11]
# Reshape the array dimension
new_arr=arr.reshape(4,3)
print(new_arr)
Output: [[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]]
# Reshape the array dimension
new_arr2=arr.reshape(3,4)
print(new_arr2)
Output:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
- 另一种可以应用于数组的操作是
flatten()。flatten()将 n 维数组转换为一维数组:
# Create an array
arr=np.arange(1,10).reshape(3,3)
print(arr)
Output:
[[1 2 3]
[4 5 6]
[7 8 9]]
print(arr.flatten())
Output:
[1 2 3 4 5 6 7 8 9]
ravel()函数类似于flatten()函数。它也将 n 维数组转换为一维数组。主要区别在于,flatten()返回的是实际的数组,而ravel()返回的是原数组的引用。由于ravel()不占用额外的内存,它比flatten()更快:
print(arr.ravel())
Output:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
transpose()函数是一个线性代数函数,它将给定的二维矩阵进行转置。转置的意思是将行转化为列,将列转化为行:
# Transpose the matrix
print(arr.transpose())
Output:
[[1 4 7]
[2 5 8]
[3 6 9]]
resize()函数改变 NumPy 数组的大小。它类似于reshape(),但它会改变原数组的形状:
# resize the matrix
arr.resize(1,9)
print(arr)
Output:[[1 2 3 4 5 6 7 8 9]]
在本节的所有代码中,我们看到了用于操作大小的内置函数,如 reshape()、flatten()、ravel()、transpose() 和 resize()。现在,是时候学习 NumPy 数组的堆叠了。
NumPy 数组的堆叠
NumPy 提供了数组堆叠功能。堆叠是指沿着新的轴将具有相同维度的数组连接。堆叠可以在水平方向、垂直方向、列方向、行方向或深度方向进行:
- 水平堆叠:在水平堆叠中,具有相同维度的数组沿水平轴通过
hstack()和concatenate()函数连接。让我们来看下面的例子:
arr1 = np.arange(1,10).reshape(3,3)
print(arr1)
Output: [[1 2 3]
[4 5 6]
[7 8 9]]
我们已经创建了一个 33 的数组,现在是时候创建另一个 33 的数组了:
arr2 = 2*arr1
print(arr2)
Output: [[ 2 4 6]
[ 8 10 12]
[14 16 18]]
创建两个数组后,我们将进行水平堆叠:
# Horizontal Stacking
arr3=np.hstack((arr1, arr2))
print(arr3)
Output: [[ 1 2 3 2 4 6]
[ 4 5 6 8 10 12]
[ 7 8 9 14 16 18]]
在前面的代码中,两个数组沿 x 轴被水平堆叠。concatenate() 函数也可以用来生成水平堆叠,设置轴参数值为 1:
# Horizontal stacking using concatenate() function
arr4=np.concatenate((arr1, arr2), axis=1)
print(arr4)
Output: [[ 1 2 3 2 4 6]
[ 4 5 6 8 10 12]
[ 7 8 9 14 16 18]]
在前面的代码中,两个数组通过 concatenate() 函数被水平堆叠。
- 垂直堆叠:在垂直堆叠中,具有相同维度的数组沿垂直轴通过
vstack()和concatenate()函数连接。让我们来看下面的例子:
# Vertical stacking
arr5=np.vstack((arr1, arr2))
print(arr5)
Output: [[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[ 2 4 6]
[ 8 10 12]
[14 16 18]]
在前面的代码中,两个数组沿 y 轴被垂直堆叠。concatenate() 函数也可以用来生成垂直堆叠,设置轴参数值为 0:
arr6=np.concatenate((arr1, arr2), axis=0)
print(arr6)
Output: [[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[ 2 4 6]
[ 8 10 12]
[14 16 18]]
在前面的代码中,两个数组通过 concatenate() 函数被垂直堆叠。
- 深度堆叠:在深度堆叠中,具有相同维度的数组沿第三个轴(深度)通过
dstack()函数连接。让我们来看下面的例子:
arr7=np.dstack((arr1, arr2))
print(arr7)
Output: [[[ 1 2]
[ 2 4]
[ 3 6]]
[[ 4 8]
[ 5 10]
[ 6 12]]
[[ 7 14]
[ 8 16]
[ 9 18]]]
在前面的代码中,两个数组沿着第三个轴(深度)进行堆叠。
- 按列堆叠:按列堆叠将多个一维数组按列堆叠成一个二维数组。让我们来看一个按列堆叠的例子:
# Create 1-D array
arr1 = np.arange(4,7)
print(arr1)
Output: [4, 5, 6]
在前面的代码块中,我们创建了一个一维的 NumPy 数组。
# Create 1-D array
arr2 = 2 * arr1
print(arr2)
Output: [ 8, 10, 12]
在前面的代码块中,我们创建了另一个一维的 NumPy 数组。
# Create column stack
arr_col_stack=np.column_stack((arr1,arr2))
print(arr_col_stack)
Output: [[ 4 8]
[ 5 10]
[ 6 12]]
在前面的代码中,我们创建了两个一维数组并按列堆叠它们。
- 按行堆叠:按行堆叠将多个一维数组按行堆叠成一个二维数组。让我们来看一个按行堆叠的例子:
# Create row stack
arr_row_stack = np.row_stack((arr1,arr2))
print(arr_row_stack)
Output: [[ 4 5 6]
[ 8 10 12]]
在前面的代码中,两个一维数组按行堆叠。
现在让我们来看一下如何将一个 NumPy 数组划分为多个子数组。
NumPy 数组的划分
NumPy 数组可以被划分为多个子数组。NumPy 提供了三种划分功能:垂直划分、水平划分和深度划分。所有的划分函数默认将数组划分为相同大小的子数组,但我们也可以指定划分位置。让我们详细了解每个函数:
- 水平划分:在水平划分中,给定数组沿水平方向被划分为 N 个相等的子数组,使用
hsplit()函数。让我们看看如何划分一个数组:
# Create an array
arr=np.arange(1,10).reshape(3,3)
print(arr)
Output:
[[1 2 3]
[4 5 6]
[7 8 9]]
# Peroform horizontal splitting
arr_hor_split=np.hsplit(arr, 3)
print(arr_hor_split)
Output: [array([[1],
[4],
[7]]), array([[2],
[5],
[8]]), array([[3],
[6],
[9]])]
在前面的代码中,hsplit(arr, 3) 函数将数组划分为三个子数组。每个部分是原始数组的一列。
- 垂直划分:在垂直划分中,给定数组沿垂直轴被划分为 N 个相等的子数组,使用
vsplit()和split()函数。split函数在axis=0时执行的操作与vsplit()函数相同:
# vertical split
arr_ver_split=np.vsplit(arr, 3)
print(arr_ver_split)
Output: [array([[1, 2, 3]]), array([[4, 5, 6]]), array([[7, 8, 9]])]
在前面的代码中,vsplit(arr, 3) 函数将数组划分为三个子数组。每个部分是原始数组的一行。让我们看一下另一个可以用于垂直和水平划分的函数 split(),以下是一个例子:
# split with axis=0
arr_split=np.split(arr,3,axis=0)
print(arr_split)
Output: [array([[1, 2, 3]]), array([[4, 5, 6]]), array([[7, 8, 9]])]
# split with axis=1
arr_split = np.split(arr,3,axis=1)
Output:
[array([[1],
[4],
[7]]), array([[2],
[5],
[8]]), array([[3],
[6],
[9]])]
在前面的代码中,split(arr, 3) 函数将数组划分为三个子数组。每个部分是原始数组的一行。split 的输出在 axis=0 时类似于 vsplit() 函数,而在 axis=1 时类似于 hsplit() 函数。
更改 NumPy 数组的数据类型
如前所述,NumPy 支持多种数据类型,例如 int、float 和复数。astype() 函数可以将数组的数据类型转换。让我们来看一个 astype() 函数的例子:
# Create an array
arr=np.arange(1,10).reshape(3,3)
print("Integer Array:",arr)
# Change datatype of array
arr=arr.astype(float)
# print array
print("Float Array:", arr)
# Check new data type of array
print("Changed Datatype:", arr.dtype)
在前面的代码中,我们创建了一个 NumPy 数组,并使用 dtype 属性检查它的数据类型。
让我们使用 astype() 函数更改数组的数据类型:
# Change datatype of array
arr=arr.astype(float)
# Check new data type of array
print(arr.dtype)
Output: float64
在前面的代码中,我们使用 astype() 将列的数据类型从整数更改为浮点数。
tolist() 函数将 NumPy 数组转换为 Python 列表。让我们来看一个 tolist() 函数的例子:
# Create an array
arr=np.arange(1,10)
# Convert NumPy array to Python List
list1=arr.tolist()
print(list1)
Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]
在前面的代码中,我们使用 tolist() 函数将数组转换为 Python 列表对象。
创建 NumPy 视图和副本
一些 Python 函数返回输入数组的副本或视图。Python 的副本会将数组存储在另一个位置,而视图则使用相同的内存内容。这意味着副本是独立的对象,并在 Python 中被视为深拷贝。视图是原始的基础数组,并被视为浅拷贝。以下是副本和视图的一些特点:
-
视图中的修改会影响原始数据,而副本中的修改则不会影响原始数组。
-
视图使用共享内存的概念。
-
与视图相比,副本需要额外的空间。
-
副本比视图慢。
让我们通过以下示例来理解副本和视图的概念:
# Create NumPy Array
arr = np.arange(1,5).reshape(2,2)
print(arr)
Output: [[1, 2],
[3, 4]]
创建 NumPy 数组后,我们来进行对象复制操作:
# Create no copy only assignment
arr_no_copy=arr
# Create Deep Copy
arr_copy=arr.copy()
# Create shallow copy using View
arr_view=arr.view()
print("Original Array: ",id(arr))
print("Assignment: ",id(arr_no_copy))
print("Deep Copy: ",id(arr_copy))
print("Shallow Copy(View): ",id(arr_view))
Output: Original Array: 140426327484256
Assignment: 140426327484256
Deep Copy: 140426327483856
Shallow Copy(View): 140426327484496
在前面的示例中,你可以看到原始数组和分配的数组具有相同的对象 ID,意味着它们指向相同的对象。副本和视图具有不同的对象 ID;两者会有不同的对象,但视图对象会引用相同的原始数组,而副本会有该对象的不同副本。
让我们继续这个示例,并更新原始数组的值,查看其对视图和副本的影响:
# Update the values of original array
arr[1]=[99,89]
# Check values of array view
print("View Array:\n", arr_view)
# Check values of array copy
print("Copied Array:\n", arr_copy)
Output:
View Array:
[[ 1 2]
[99 89]]
Copied Array:
[[1 2]
[3 4]]
在前面的示例中,我们可以从结果得出结论:视图是原始数组。当我们更新原始数组时,值发生了变化,而副本是一个独立的对象,因为它的值保持不变。
切片 NumPy 数组
NumPy 中的切片与 Python 列表类似。索引操作倾向于选择单一值,而切片用于从数组中选择多个值。
NumPy 数组也支持负索引和切片。这里,负号表示反向方向,索引从右侧开始,起始值为 -1:
让我们通过以下代码来检查这个:
# Create NumPy Array
arr = np.arange(0,10)
print(arr)
Output: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
在切片操作中,我们使用冒号符号来选择一组值。切片有三个值:起始、停止和步长:
print(arr[3:6])
Output: [3, 4, 5]
这可以表示如下:
在前面的示例中,我们使用了 3 作为起始索引,6 作为停止索引:
print(arr[3:])
Output: array([3, 4, 5, 6, 7, 8, 9])
在前面的示例中,仅给出了起始索引。3 是起始索引。此切片操作将从起始索引开始,选择数组从该索引到数组末尾的值:
print(arr[-3:])
Output: array([7, 8, 9])
这可以表示如下:
在前面的示例中,切片操作将选择从数组右侧第三个值开始到数组末尾的值:
print(arr[2:7:2])
Output: array([2, 4,6])
这可以表示如下:
在前面的示例中,起始、停止和步长索引分别为 2、7 和 2。在这里,切片操作从第二个索引到第六个(停止值减一)索引选择值,索引值增加 2。因此,输出将是 2、4 和 6。
布尔索引和花式索引
索引技术帮助我们从 NumPy 数组中选择和过滤元素。在本节中,我们将重点介绍布尔索引和花式索引。布尔索引在索引的地方使用布尔表达式(在方括号内)来过滤 NumPy 数组。此索引返回对布尔表达式为真的元素:
# Create NumPy Array
arr = np.arange(21,41,2)
print("Orignial Array:\n",arr)
# Boolean Indexing
print("After Boolean Condition:",arr[arr>30])
Output: Orignial Array:
[21 23 25 27 29 31 33 35 37 39]
After Boolean Condition: [31 33 35 37 39]
花式索引是一种特殊的索引类型,其中数组的元素由索引数组选择。这意味着我们在方括号中传递索引数组。花式索引还支持多维数组。这将帮助我们轻松地选择和修改复杂的多维数组集合。让我们看一个以下示例来理解花式索引:
# Create NumPy Array
arr = np.arange(1,21).reshape(5,4)
print("Orignial Array:\n",arr)
# Selecting 2nd and 3rd row
indices = [1,2]
print("Selected 1st and 2nd Row:\n", arr[indices])
# Selecting 3nd and 4th row
indices = [2,3]
print("Selected 3rd and 4th Row:\n", arr[indices])
Output:
Orignial Array:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]
[13 14 15 16]
[17 18 19 20]]
Selected 1st and 2nd Row:
[[ 5 6 7 8]
[ 9 10 11 12]]
Selected 3rd and 4th Row:
[[ 9 10 11 12]
[13 14 15 16]]
在上述代码中,我们创建了一个 5*4 的矩阵,并使用整数索引选择了行。您还可以从以下图表中可视化或内部化此输出:
我们可以看到其代码如下:
# Create row and column indices
row = np.array([1, 2])
col = np.array([2, 3])
print("Selected Sub-Array:", arr[row, col])
Output:
Selected Sub-Array: [ 7 12]
前面的示例将结果作为第一个值[1,2]和第二个值[2,3],作为行和列索引。数组将选择第一个和第二个索引值,分别为 7 和 12。
广播数组
Python 列表不支持直接向量化的算术操作。NumPy 提供了比 Python 列表循环操作更快的向量化数组操作。在这里,所有的循环操作都是在 C 中执行而不是 Python,这使得它更快。广播功能检查应用于数组不同形状的二进制函数(如加法、减法和乘法)的一组规则。
让我们看一个广播的例子:
# Create NumPy Array
arr1 = np.arange(1,5).reshape(2,2)
print(arr1)
Output: [[1 2]
[3 4]]
# Create another NumPy Array
arr2 = np.arange(5,9).reshape(2,2)
print(arr2)Output: [[5 6]
[7 8]]
# Add two matrices
print(arr1+arr2)
Output: [[ 6 8]
[10 12]]
在前面的三个示例中,我们可以看到两个大小相同数组的加法。这个概念称为广播:
# Multiply two matrices
print(arr1*arr2)
Output: [[ 5 12]
[21 32]]
在前面的示例中,两个矩阵进行了乘法运算。让我们执行加法和乘法与标量值:
# Add a scaler value
print(arr1 + 3)
Output: [[4 5]
[6 7]]
# Multiply with a scalar value
print(arr1 * 3)
Output: [[ 3 6]
[ 9 12]]
在前面的两个示例中,矩阵被加和乘以一个标量值。
创建 pandas 数据框
pandas库设计用于处理面板或表格数据。pandas是一个快速、高效且富有生产力的工具,用于处理和分析字符串、数字、日期时间和时间序列数据。pandas提供了如 DataFrame 和 Series 等数据结构。pandas DataFrame 是一个二维的带标签和索引的表格数据结构,具有行和列的网格。它的列是异质类型。它能够处理不同类型的对象,进行分组和连接操作,处理缺失值,创建透视表,处理日期。可以通过多种方式创建pandas DataFrame。让我们创建一个空的 DataFrame:
# Import pandas library
import pandas as pd
# Create empty DataFrame
df = pd.DataFrame()
# Header of dataframe.
df.head()
Output:
_
在前面的示例中,我们创建了一个空的 DataFrame。让我们使用字典列表来创建一个 DataFrame:
# Create dictionary of list
data = {'Name': ['Vijay', 'Sundar', 'Satyam', 'Indira'], 'Age': [23, 45, 46, 52 ]}
# Create the pandas DataFrame
df = pd.DataFrame(data)
# Header of dataframe.
df.head()
Output:
Name Age0 Vijay 231 Sundar 45
2 Satyam 46
3 Indira 52
在前面的代码中,我们使用了一个字典列表来创建一个 DataFrame。这里,字典的键相当于列,而值则表示为一个列表,相当于 DataFrame 的行。让我们使用字典列表创建一个 DataFrame:
# Pandas DataFrame by lists of dicts.
# Initialise data to lists.
data =[ {'Name': 'Vijay', 'Age': 23},{'Name': 'Sundar', 'Age': 25},{'Name': 'Shankar', 'Age': 26}]
# Creates DataFrame.
df = pd.DataFrame(data,columns=['Name','Age'])
# Print dataframe header
df.head()
在前面的代码中,DataFrame 是通过使用字典列表来创建的。在列表中,每个项是一个字典。每个键是列名,每个值是某一行的单元格值。让我们使用元组列表创建一个 DataFrame:
# Creating DataFrame using list of tuples.
data = [('Vijay', 23),( 'Sundar', 45), ('Satyam', 46), ('Indira',52)]
# Create dataframe
df = pd.DataFrame(data, columns=['Name','Age'])
# Print dataframe header
df.head()
Output:
Name Age
0 Vijay 23
1 Sundar 25
2 Shankar 26
在前面的代码中,DataFrame 是通过使用元组列表来创建的。在列表中,每个项是一个元组,每个元组相当于一行的列。
理解 pandas Series
pandas Series 是一个一维的顺序数据结构,能够处理任何类型的数据,如字符串、数字、日期时间、Python 列表和字典,具有标签和索引。Series 是 DataFrame 的其中一列。我们可以使用 Python 字典、NumPy 数组和标量值来创建 Series。我们还将在本节后面看到pandas Series 的特性和属性。让我们创建一些 Python Series:
- 使用 Python 字典:创建一个字典对象,并将其传递给 Series 对象。让我们看一下下面的示例:
# Creating Pandas Series using Dictionary
dict1 = {0 : 'Ajay', 1 : 'Jay', 2 : 'Vijay'}
# Create Pandas Series
series = pd.Series(dict1)
# Show series
series
Output: 0 Ajay
1 Jay
2 Vijay
dtype: object
- 使用 NumPy 数组:创建一个 NumPy 数组对象,并将其传递给 Series 对象。让我们看一下下面的示例:
#Load Pandas and NumPy libraries
import pandas as pd
import numpy as np
# Create NumPy array
arr = np.array([51,65,48,59, 68])
# Create Pandas Series
series = pd.Series(arr)
series
Output: 0 51
1 65
2 48
3 59
4 68
dtype: int64
- 使用单一标量值:要创建一个包含标量值的
pandasSeries,可以将标量值和索引列表传递给 Series 对象:
# load Pandas and NumPy
import pandas as pd
import numpy as np
# Create Pandas Series
series = pd.Series(10, index=[0, 1, 2, 3, 4, 5])
series
Output: 0 10
1 10
2 10
3 10
4 10
5 10
dtype: int64
让我们探索一下pandas Series 的一些特性:
- 我们也可以通过选择一列来创建一个序列,例如
country,它恰好是数据文件中的第一列。然后,显示当前本地作用域中的对象类型:
# Import pandas
import pandas as pd
# Load data using read_csv()
df = pd.read_csv("WHO_first9cols.csv")
# Show initial 5 records
df.head()
这将产生以下输出:
在上述代码中,我们使用read_csv()函数读取了WHO_first9cols.csv文件。您可以从以下 GitHub 位置下载此文件:github.com/PacktPublishing/Python-Data-Analysis-Third-Edition/tree/master/Chapter02。在输出中,您可以看到使用head()函数查看的WHO_first9cols数据集中的前五条记录:
# Select a series
country_series=df['Country']
# check datatype of series
type(country_series)
Output:
pandas.core.series.Series
pandasSeries 数据结构具有与 DataFrame 共享的一些共同属性,并且还具有一个name属性。按以下方式探索这些属性:
# Show the shape of DataFrame
print("Shape:", df.shape)
Output: Shape: (202, 9)
让我们查看一下 DataFrame 的列列表:
# Check the column list of DataFrame
print("List of Columns:", df.columns)
Output:List of Columns: Index(['Country', 'CountryID', 'Continent', 'Adolescent fertility rate (%)',
'Adult literacy rate (%)',
'Gross national income per capita (PPP international $)',
'Net primary school enrolment ratio female (%)',
'Net primary school enrolment ratio male (%)',
'Population (in thousands) total'],
dtype='object')
让我们检查一下 DataFrame 列的数据类型:
# Show the datatypes of columns
print("Data types:", df.dtypes)
Output: Data types: Country object
CountryID int64
Continent int64
Adolescent fertility rate (%) float64
Adult literacy rate (%) float64
Gross national income per capita (PPP international $) float64
Net primary school enrolment ratio female (%) float64
Net primary school enrolment ratio male (%) float64
Population (in thousands) total float64
dtype: object
- 让我们看看
pandasSeries 的切片操作:
# Pandas Series Slicing
country_series[-5:]
Output:
197 Vietnam
198 West Bank and Gaza
199 Yemen
200 Zambia
201 Zimbabwe
Name: Country, dtype: object
现在我们知道如何使用 pandas Series,接下来让我们使用 Quandl 来处理数据库。
读取和查询 Quandl 数据
在上一部分,我们看到了pandas DataFrame,它们具有类似关系数据库的表格结构。它们提供类似的查询操作。在本节中,我们将重点介绍 Quandl。Quandl 是一家总部位于加拿大的公司,提供用于投资数据分析师的商业和替代金融数据。Quandl 理解投资和金融定量分析师的需求。它通过 API、R、Python 或 Excel 提供数据。
在本节中,我们将从 Quandl 中检索 Sunspot 数据集。我们可以使用 API 或手动下载 CSV 格式的数据。
首先,我们使用pip安装 Quandl 包:
$ pip3 install Quandl
如果您想安装 API,可以通过从pypi.python.org/pypi/Quandl下载安装包,或通过运行上述命令来安装。
使用该 API 是免费的,但每天限 50 次 API 调用。如果需要更多的 API 调用,您需要请求一个认证密钥。本教程中的代码没有使用密钥。应该很容易修改代码以使用密钥或读取已下载的 CSV 文件。如果遇到困难,请参考第一章中的如何获取帮助和参考资料部分,或浏览 Python 文档:docs.python.org/2/。
让我们看看如何在pandas DataFrame 中查询数据:
- 第一步,显然我们需要下载数据。在导入 Quandl API 后,按照以下方式获取数据:
import quandl
sunspots = quandl.get("SIDC/SUNSPOTS_A")
head()和tail()方法的功能类似于 Unix 中具有相同名称的命令。选择 DataFrame 的前n和后n条记录,其中n是一个整数参数:
sunspots.head()
这将产生以下输出:
让我们按照如下方式查看tail函数:
sunspots.tail()
这将产生以下输出:
head() 和 tail() 方法分别返回 Sunspot 数据的前五行和最后五行。
- 筛选列:
pandas提供了选择列的功能。我们来选择pandasDataFrame 中的列:
# Select columns
sunspots_filtered=sunspots[['Yearly Mean Total Sunspot Number','Definitive/Provisional Indicator']]
# Show top 5 records
sunspots_filtered.head()
这将产生以下输出:
- 筛选行:
pandas提供了选择行的功能。我们来选择pandasDataFrame 中的行:
# Select rows using index
sunspots["20020101": "20131231"]
这将产生以下输出:
- 布尔过滤:我们可以使用类似于 SQL 中
WHERE子句的布尔条件查询数据。我们来筛选出大于算术平均值的数据:
# Boolean Filter
sunspots[sunspots['Yearly Mean Total Sunspot Number'] > sunspots['Yearly Mean Total Sunspot Number'].mean()]
这将产生以下输出:
描述 pandas DataFrame
pandas DataFrame 具有十几种统计方法。下表列出了这些方法,并简要描述了每种方法:
| 方法 | 描述 |
|---|---|
describes | 此方法返回一个包含描述性统计信息的小表格。 |
count | 此方法返回非 NaN 项的数量。 |
mad | 此方法计算均值绝对偏差,这是类似于标准差的稳健度量。 |
median | 此方法返回中位数。它等于第 50^(th) 百分位数的值。 |
min | 此方法返回最小值。 |
max | 此方法返回最大值。 |
mode | 此方法返回众数,即最频繁出现的值。 |
std | 此方法返回标准差,用于衡量数据的离散程度。它是方差的平方根。 |
var | 此方法返回方差。 |
skew | 此方法返回偏度。偏度表示分布的对称性。 |
kurt | 此方法返回峰度。峰度表示分布的形状。 |
使用上一节相同的数据,我们将展示这些统计方法:
# Describe the dataset
df.describe()
这将产生以下输出:
describe() 方法将展示所有列的绝大多数描述性统计量:
# Count number of observation
df.count()
这将产生以下输出:
count() 方法计算每一列中的观察值数量。它帮助我们检查数据集中的缺失值。除了最初的三列,其他列都有缺失值。类似地,你可以计算中位数、标准差、均值绝对偏差、方差、偏度和峰度:
# Compute median of all the columns
df.median()
这将产生以下输出:
我们可以按如下方式计算所有列的偏差:
# Compute the standard deviation of all the columns
df.std()
这将产生以下输出:
上述代码示例正在计算每个数字列的标准差。
对 pandas DataFrame 的分组与连接
分组是数据聚合操作的一种。分组术语来源于关系型数据库。关系型数据库软件使用 group by 关键字将列中相似的值进行分组。我们可以对分组应用聚合函数,例如均值、最小值、最大值、计数和求和。pandas DataFrame 也提供了类似的功能。分组操作基于拆分-应用-合并策略。它首先将数据分成组,并对每个组应用聚合操作,如均值、最小值、最大值、计数和求和,然后将每个组的结果合并:
# Group By DataFrame on the basis of Continent column
df.groupby('Continent').mean()
这将产生以下输出:
现在,让我们根据文盲率对 DataFrame 进行分组:
# Group By DataFrame on the basis of continent and select adult literacy rate(%)
df.groupby('Continent').mean()['Adult literacy rate (%)']
这将产生以下输出:
在上面的例子中,我们计算了按大洲划分的成人文盲率百分比。你也可以通过将多个列的列表传递给 groupby() 函数来进行多列分组。
连接是一种用于表格数据库的合并操作。连接概念源自关系型数据库。在关系型数据库中,表被规范化或拆分以减少冗余和不一致性,连接用于从多个表中选择信息。数据分析师需要将来自多个来源的数据进行合并。pandas 也提供了通过 merge() 函数连接多个 DataFrame 的功能。
为了理解连接操作,我们将以一个出租车公司为例。我们使用两个文件:dest.csv 和 tips.csv。每当司机将乘客送到目的地时,我们会将一条记录(员工编号和目的地)插入 dest.csv 文件中。每当司机获得小费时,我们会将记录(员工编号和小费金额)插入 tips.csv 文件中。你可以从以下 GitHub 链接下载这两个文件:github.com/PacktPublishing/Python-Data-Analysis-Third-Edition/tree/master/Python-Data-Analysis-Third-Edition/Ch2:
# Import pandas
import pandas as pd
# Load data using read_csv()
dest = pd.read_csv("dest.csv")
# Show DataFrame
dest.head()
这将产生以下输出:
在前面的代码块中,我们使用 read_csv() 方法读取了 dest.csv 文件:
# Load data using read_csv()
tips = pd.read_csv("tips.csv")
# Show DataFrame
tips.head()
这将产生以下输出:
在前面的代码块中,我们使用 read_csv() 方法读取了 tips.csv 文件。接下来,我们将查看不同类型的连接操作:
- 内连接:内连接相当于集合的交集操作。它只会选择两个 DataFrame 中的共同记录。要执行内连接,使用
merge()函数,指定两个 DataFrame 和公共属性作为参数,并设置how为 "inner" 来展示参数。on参数用于提供连接所依据的公共属性,how定义连接类型:
# Join DataFrames using Inner Join
df_inner= pd.merge(dest, tips, on='EmpNr', how='inner')
df_inner.head()
这会产生以下输出:
- 全外连接:外连接相当于集合的并操作。它将合并左右两个 DataFrame。它会包含两个 DataFrame 中的所有记录,并在没有匹配的地方填充 NaN:
# Join DataFrames using Outer Join
df_outer= pd.merge(dest, tips, on='EmpNr', how='outer')
df_outer.head()
这会产生以下输出:
- 右外连接:在右外连接中,所有来自 DataFrame 右侧的记录都会被选中。如果在左侧 DataFrame 中找不到匹配的记录,则用 NaN 填充:
# Join DataFrames using Right Outer Join
df_right= pd.merge(dest, tips, on='EmpNr', how='right')
df_right.head()
这会产生以下输出:
- 左外连接:在左外连接中,所有来自 DataFrame 左侧的记录都会被选中。如果在右侧 DataFrame 中找不到匹配的记录,则用 NaN 填充:
# Join DataFrames using Left Outer Join
df_left= pd.merge(dest, tips, on='EmpNr', how='left')
df_left.head()
这会产生以下输出:
我们现在将继续检查数据集中的缺失值。
处理缺失值
大多数现实世界中的数据集都是杂乱无章且充满噪声的。由于其杂乱和噪声,许多值要么是错误的,要么是缺失的。pandas 提供了许多内置函数来处理 DataFrame 中的缺失值:
- 检查 DataFrame 中的缺失值:
pandas的isnull()函数检查是否存在空值,并返回True或False,其中True表示空值,False表示非空值。sum()函数会将所有True值相加,返回缺失值的数量。我们尝试了两种方法来计算缺失值,两者显示的输出相同:
# Count missing values in DataFrame
pd.isnull(df).sum()
以下是第二种方法:
df.isnull().sum()
这会产生以下输出:
- 删除缺失值:一种非常简单的处理缺失值的方法是删除它们以便进行分析。
pandas提供了dropna()函数来删除 DataFrame 中的这些观察值。在这里,inplace=True属性会在原始 DataFrame 中进行更改:
# Drop all the missing values
df.dropna(inplace=True)
df.info()
这会产生以下输出:
在这里,观察值的数量从 202 减少到 118。
- 填充缺失值:另一种方法是用零、均值、中位数或常数值填充缺失值:
# Fill missing values with 0
df.fillna(0,inplace=True)
df.info()
这会产生以下输出:
在这里,我们用 0 填充了缺失值。这就是处理缺失值的全部内容。
在下一节中,我们将重点讨论数据透视表。
创建数据透视表
数据透视表是一个汇总表格,它是 Excel 中最流行的概念。大多数数据分析师将其作为一个方便的工具来总结他们的结果。pandas 提供了 pivot_table() 函数来汇总 DataFrame。DataFrame 使用聚合函数进行汇总,例如均值、最小值、最大值或总和。你可以从以下 GitHub 链接下载数据集:github.com/PacktPublishing/Python-Data-Analysis-Third-Edition/tree/master/Python-Data-Analysis-Third-Edition/Ch2:
# Import pandas
import pandas as pd
# Load data using read_csv()
purchase = pd.read_csv("purchase.csv")
# Show initial 10 records
purchase.head(10)
这将产生以下输出:
在前面的代码块中,我们使用 read_csv() 方法读取了 purchase.csv 文件。
现在,我们将使用以下代码汇总 DataFrame:
# Summarise dataframe using pivot table
pd.pivot_table(purchase,values='Number', index=['Weather',],
columns=['Food'], aggfunc=np.sum)
这将产生以下输出:
在前面的示例中,purchase DataFrame 被汇总。这里,index 是 Weather 列,columns 是 Food 列,values 是 Number 列的聚合总和。aggfun 被初始化为 np.sum 参数。现在是时候学习如何在 pandas DataFrame 中处理日期了。
处理日期
处理日期是繁琐而复杂的。你可以回想起 Y2K 问题、即将到来的 2038 问题以及时区处理的不同问题。在时间序列数据集中,我们会遇到日期。pandas 提供了日期范围,重新采样时间序列数据,并执行日期算术操作。
创建一个从 2020 年 1 月 1 日开始的日期范围,持续 45 天,如下所示:
pd.date_range('01-01-2000', periods=45, freq='D')
Output: DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03', '2000-01-04',
'2000-01-05', '2000-01-06', '2000-01-07', '2000-01-08',
'2000-01-09', '2000-01-10', '2000-01-11', '2000-01-12',
'2000-01-13', '2000-01-14', '2000-01-15', '2000-01-16',
'2000-01-17', '2000-01-18', '2000-01-19', '2000-01-20',
'2000-01-21', '2000-01-22', '2000-01-23', '2000-01-24',
'2000-01-25', '2000-01-26', '2000-01-27', '2000-01-28',
'2000-01-29', '2000-01-30', '2000-01-31', '2000-02-01',
'2000-02-02', '2000-02-03', '2000-02-04', '2000-02-05',
'2000-02-06', '2000-02-07', '2000-02-08', '2000-02-09',
'2000-02-10', '2000-02-11', '2000-02-12', '2000-02-13',
'2000-02-14'],
dtype='datetime64[ns]', freq='D')
1 月份的天数少于 45 天,因此结束日期落在了 2 月份,你可以自己检查。
date_range() 的 freq 参数可以取值,例如 B 表示工作日频率,W 表示每周频率,H 表示每小时频率,M 表示每分钟频率,S 表示每秒频率,L 表示每毫秒频率,U 表示每微秒频率。更多详情,请参考官方文档:pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html。
- pandas 日期范围:
date_range()函数生成具有固定频率间隔的日期和时间序列:
# Date range function
pd.date_range('01-01-2000', periods=45, freq='D')
这将产生以下输出:
to_datetime():to_datetime()将时间戳字符串转换为 datetime:
# Convert argument to datetime
pd.to_datetime('1/1/1970')
Output: Timestamp('1970-01-01 00:00:00')
- 我们可以将时间戳字符串转换为指定格式的 datetime 对象:
# Convert argument to datetime in specified format
pd.to_datetime(['20200101', '20200102'], format='%Y%m%d')
Output: DatetimeIndex(['2020-01-01', '2020-01-02'], dtype='datetime64[ns]', freq=None)
- 处理未知格式字符串: 未知的输入格式可能会导致值错误。我们可以通过使用带有
coerce的errors参数来处理这种情况。coerce将无效的字符串设置为 NaT:
# Value Error
pd.to_datetime(['20200101', 'not a date'])
Output: ValueError: ('Unknown string format:', 'not a date')
# Handle value error
pd.to_datetime(['20200101', 'not a date'], errors='coerce')
Output: DatetimeIndex(['2020-01-01', 'NaT'], dtype='datetime64[ns]', freq=None)
在前面的示例中,第二个日期仍然无效,无法转换为 datetime 对象。errors 参数帮助我们通过输入值 NaT(不是时间)来处理此类错误。
摘要
在本章中,我们探讨了 NumPy 和 pandas 库。这两个库都用于处理数组和 DataFrame。NumPy 数组能够处理 n 维数组。我们学习了各种数组属性和操作。我们的主要关注点是数据类型、数据类型作为对象、重塑、堆叠、拆分、切片和索引。
我们还专注于用于 Python 数据分析的pandas库。我们看到了pandas如何模拟关系数据库表的功能。它提供了查询、聚合、操作和高效连接数据的功能。
NumPy 和pandas作为工具协同工作,使得执行基本的数据分析成为可能。此时,您可能会认为pandas是我们进行数据分析所需的一切。然而,数据分析远不止于此。
在掌握了基础知识后,是时候进入使用第三章中常用统计函数进行数据分析的环节,统计学。这包括了统计概念的应用。
鼓励您阅读参考文献部分中提到的书籍,深入探索 NumPy 和pandas。
参考文献
-
Ivan Idris, NumPy Cookbook – 第二版,Packt Publishing,2015 年。
-
Ivan Idris, 学习 NumPy 数组,Packt Publishing,2014 年。
-
Ivan Idris, NumPy:初学者指南 – 第三版,Packt Publishing,2015 年。
-
L. (L.-H.) Chin 和 T. Dutta,NumPy 基础,Packt Publishing,2016 年。
-
T. Petrou, pandas Cookbook,Packt Publishing,2017 年。
-
F. Anthony, 精通 pandas,Packt Publishing,2015 年。
-
M. Heydt, 金融领域的 pandas 精通,Packt Publishing,2015 年。
-
T. Hauck, 使用 pandas 进行数据密集型应用的操作指南,Packt Publishing,2013 年。
-
M. Heydt, 学习 pandas,Packt Publishing,2015 年。
第三章:统计学
探索性数据分析 (EDA) 是数据分析和构建机器学习模型的第一步。统计学提供了探索性或描述性数据分析的基础知识和一套工具。本章旨在使您具备处理真实世界数据的能力,这些数据通常具有噪声、缺失值,并从各种来源收集而来。
在进行任何预处理和分析之前,您需要熟悉当前的数据,统计学是唯一能帮助您的工具。这使得统计学成为数据专业人士的一项主要且非常必要的技能,帮助他们获得初步见解和对数据的理解。例如,员工每月工作小时的算术平均数可以帮助我们了解组织中员工的工作负荷。类似地,每月工作小时的标准差可以帮助我们推断工作小时的范围。血压和患者年龄之间的相关性可以帮助我们理解血压和年龄之间的关系。抽样方法在任何类型的主数据收集中都可能有用。我们还可以执行参数和非参数假设检验以推断有关总体的事实。
在本章中,我们将涵盖以下主题:
-
理解属性及其类型
-
测量中心趋势
-
测量离散度
-
偏度和峰度
-
使用协方差和相关系数理解关系
-
中心极限定理
-
收集样本
-
执行参数检验
-
执行非参数检验
技术要求
对于本章,以下技术信息可用:
-
您可以在以下 GitHub 链接找到代码和数据集:
github.com/PacktPublishing/Python-Data-Analysis-Third-Edition/tree/master/Chapter03. -
所有代码块均在
ch3.ipynb中可用。 -
在本章中,我们将使用 Python 的 NumPy、Pandas 和 SciPy 库。
理解属性及其类型
数据是原始事实和统计数据的集合,如数字、文字和观察结果。属性是表示对象特征的列、数据字段或系列,也称为变量、特征或维度。统计学家使用术语变量,而机器学习工程师更喜欢术语特征。数据仓库中使用术语维度,而数据库专业人员使用术语属性。
属性类型
属性的数据类型对数据分析更为关键,因为某些情况需要特定的数据类型。属性的数据类型帮助分析人员选择正确的数据分析和可视化绘图方法。以下列表显示了各种属性:
-
名义属性: 名义是指类别变量的名称或标签。名义属性的值可以是项目的符号或名称。这些值是类别性的、定性的,且没有顺序性,如产品名称、品牌名称、邮政编码、州、性别和婚姻状况。对于定性和类别性的值,计算均值和中位数是没有意义的,但数据分析师可以计算众数,即出现频率最高的值。
-
顺序属性: 顺序是指具有有意义顺序或排名的名称或标签,但值的大小并不明确。这些类型的属性仅用于衡量主观特质。这就是为什么它们被广泛用于客户满意度调查、产品评级和电影评分等领域。客户满意度评级按以下顺序出现:
-
1: 非常不满意
-
2: 有点不满意
-
3: 中立
-
4: 满意
-
5: 非常满意
-
另一个例子可能是饮料的大小:小号、中号或大号。顺序属性只能通过众数和中位数来衡量。由于顺序属性具有定性的特点,因此无法计算均值。顺序属性也可以通过将定量变量离散化,将其值划分为有限数字范围来重新创建。
- 数值属性: 数值属性以整数或实数值定量表示。数值属性可以分为两种类型:区间尺度或比例尺度。
区间尺度属性是在有序的等大小单位尺度上进行测量的。区间尺度属性两个值之间的有意义差异可以被计算出来,这使得可以进行两者的比较——例如,出生年份和摄氏温度。区间尺度属性值的主要问题是它们没有“真实的零点”——例如,摄氏温度为 0 时并不意味着温度不存在。区间尺度数据可以进行加法和减法运算,但不能进行乘法和除法,因为没有真实零点。我们还可以计算区间尺度属性的均值,除了中位数和众数之外。
比例尺度属性是按等大小单位的有序尺度进行测量的,类似于具有固有零点的区间尺度。比例尺度属性的例子包括身高、体重、纬度、经度、工作年限和文档中的单词数量。我们可以进行乘法和除法运算,并计算比例尺度值之间的差异。我们还可以计算集中趋势度量,如均值、中位数和众数。摄氏度和华氏度温标是按区间尺度进行测量的,而开尔文温标则按比例尺度进行测量,因为它具有真实的零点。
离散和连续属性
有多种方式可以对属性进行分类。在前一个小节中,我们已经见过了名义型、顺序型和数值型属性。在本小节中,我们将讨论另一种属性分类方法。这里我们将讲解离散型或连续型属性。离散变量只接受有限个可数的数值,例如班级中有多少学生、卖出多少辆车、出版多少本书。这些数值可以通过计数得到。连续变量则接受无限多个可能的数值,例如学生的体重和身高。这些数值可以通过测量得到。
离散变量接受整数值,而连续变量接受实数值。换句话说,我们可以说离散变量接受的值的分数没有意义,而连续变量接受的值的分数是有意义的。离散属性使用有限数量的值,而连续属性则使用无限数量的值。
在理解了属性及其类型后,接下来我们要关注基本的统计描述,如集中趋势测量。
测量集中趋势
集中趋势是值围绕均值、众数和中位数等平均值聚集的趋势。集中趋势的主要目的是计算观测值的中心导向值。集中趋势决定了描述性总结,并提供了关于一组观测值的定量信息。它有能力代表整个观测集。接下来,我们将在各个小节中详细探讨每种集中趋势度量方法。
均值
均值是算术平均数或平均值,通过将观测值的总和除以观测次数来计算。它对异常值和噪声非常敏感,因此每当把不常见或异常的值添加到一组数据中时,其均值就会偏离典型的中心值。假设 x[1], x[²], . . . , x [N] 是 N 次观测值。这些值的均值公式如下所示:
让我们使用 pandas 库来计算沟通技能得分列的均值,如下所示:
# Import pandas library
import pandas as pd
# Create dataframe
sample_data = {'name': ['John', 'Alia', 'Ananya', 'Steve', 'Ben'],
'gender': ['M', 'F', 'F', 'M', 'M'],
'communication_skill_score': [40, 45, 23, 39, 39],
'quantitative_skill_score': [38, 41, 42, 48, 32]}
data = pd.DataFrame(sample_data, columns = ['name', 'gender', 'communcation_skill_score', 'quantitative_skill_score'])
# find mean of communication_skill_score column
data['communcation_skill_score'].mean(axis=0)
Output:
37.2
在前面的代码块中,我们创建了一个名为 data 的 DataFrame,它有四列(name、gender、communication_skill_score 和 quantitative_skill_score),并使用 mean(axis=0) 函数计算了均值。这里,axis=0 表示按行计算均值。
众数
众数是观测值中出现频率最高的项。众数值在数据中出现频繁,主要用于分类值。如果一组数据中的所有值都是独一无二的或不重复的,那么该组数据就没有众数。也有可能有多个值的出现频率相同,在这种情况下,可以有多个众数。
让我们使用 pandas 库来计算沟通技能得分列的众数值,如下所示:
# find mode of communication_skill_score column
data['communcation_skill_score'].mode()
Output:
39
在前面的代码块中,我们通过使用mode()函数计算了沟通技巧得分列的众数。让我们计算另一个集中趋势度量:中位数。
中位数
中位数是一个观察组中的中点或中间值。它也被称为第 50 百分位数。中位数比均值更不容易受异常值和噪声的影响,这也是它被认为是更适合报告的统计量度量的原因。它通常接近典型的中央值。让我们使用pandas库计算沟通技巧得分列的中位数值,如下所示:
# find median of communication_skill_score column
data['communcation_skill_score'].median()
Output:
39.0
在前面的代码块中,我们通过使用median()函数计算了沟通技巧得分列的中位数。让我们在下一节中了解离散度量并计算它们。
测量离散程度
正如我们所见,集中趋势展示了观察组的中间值,但并未提供观察的整体图像。离散度量衡量的是观察值的偏差。最常见的离散度量有范围、四分位间距(IQR)、方差和标准差。这些离散度量关注的是观察值的变异性或观察值的分布。让我们详细了解每个离散度量,如下所示:
- 范围: 范围是观察值的最大值和最小值之间的差异。它易于计算且易于理解。它的单位与观察值的单位相同。让我们计算沟通技巧得分的范围,如下所示:
column_range=data['communcation_skill_score'].max()-data['communcation_skill_score'].min()
print(column_range)
Output:
22
在前面的代码块中,我们通过计算最大值和最小值之间的差异,得出了沟通技巧得分的范围。最大值和最小值是通过使用max()和min()函数计算得出的。
- IQR: IQR 是第三四分位数和第一四分位数之间的差值。它易于计算且易于理解。它的单位与观察值的单位相同。它衡量了观察值的中间 50%。它表示大多数观察值所在的范围。IQR 也称为中间差距或中间 50%,或者 H-差距。让我们计算沟通技巧得分的 IQR,如下所示:
# First Quartile
q1 = data['communcation_skill_score'].quantile(.25)
# Third Quartile
q3 = data['communcation_skill_score'].quantile(.75)
# Inter Quartile Ratio
iqr=q3-q1
print(iqr)
Output:
1.0
在前面的代码块中,我们通过计算得分的第一和第三四分位数之间的差异,得出了沟通技巧得分的 IQR。第一和第三四分位数的得分是通过使用quantile(.25)和quantile(.75)函数计算得出的。
- 方差: 方差衡量的是观察值与均值之间的偏差。它是观察值与均值之间平方差的平均值。方差的主要问题在于其测量单位,因为它是观察值与均值之间差值的平方。假设 x[1]、x[²]、...、x[N]是N个观察值,那么这些值的方差公式将如下所示:
让我们计算沟通技巧得分的方差,如下所示:
# Variance of communication_skill_score
data['communcation_skill_score'].var()
Output:
69.2
在前面的代码块中,我们使用var()函数计算了沟通技能评分的方差。
- 标准差: 这是方差的平方根。它的单位与原始观测值相同。这使得分析师更容易评估数据点与均值的偏差。标准差值越小,表示数据点距离均值越近;也就是说,数据分布较集中。标准差值越大,表示数据点距离均值越远——也就是说,数据分布较分散。标准差在数学上用希腊字母 sigma (Σ) 表示。假设 x[1]、x[²]、...、x[N] 是 N 个观测值。以下是这些值的标准差公式:
让我们计算沟通技能评分的标准差,如下所示:
# Standard deviation of communication_skill_score
data['communcation_skill_score'].std()
Output:
8.318653737234168
在前面的代码块中,我们使用std()函数计算了沟通技能评分的标准差。
我们还可以尝试描述这个函数,以便通过一个命令获取所有的摘要统计信息。describe()函数返回每个数值型列的计数、均值、标准差、第一四分位数、中位数、第三四分位数、最小值和最大值,具体如以下代码块所示:
# Describe dataframe
data.describe()
Output:
communcation_skill_score quantitative_skill_score
count 5.000000 5.000000
mean 37.200000 40.200000
std 8.318654 5.848077
min 23.000000 32.000000
25% 39.000000 38.000000
50% 39.000000 41.000000
75% 40.000000 42.000000
max 45.000000 48.000000
在前面的代码块中,我们使用describe()方法生成了数据的描述性统计摘要。
偏度和峰度
偏度衡量分布的对称性。它显示分布偏离正态分布的程度。其值可以是零、正值或负值。零值表示完全正态的分布形状。正偏度表现为尾部指向右侧——即异常值偏向右侧,数据堆积在左侧。负偏度表现为尾部指向左侧——即异常值偏向左侧,数据堆积在右侧。当均值大于中位数和众数时,会出现正偏度;当均值小于中位数和众数时,会出现负偏度。让我们在以下代码块中计算偏度:
# skewness of communication_skill_score column
data['communcation_skill_score'].skew()
Output:
-1.704679180800373
在前面的代码块中,我们使用skew()方法计算了沟通技能评分列的偏度。
峰度衡量与正态分布相比的尾部(尾部的厚度)。高峰度表示重尾分布,这意味着数据中有更多的异常值;低峰度表示轻尾分布,这意味着数据中异常值较少。峰度有三种形状:中峰、平峰和尖峰。我们逐一定义它们,如下所示:
-
具有零峰度的正态分布被称为中峰分布。
-
平峰分布具有负的峰度值,并且相比于正态分布,它的尾部较薄。
-
尖峰峰度分布的峰度值大于 3,相较于正态分布,它呈现肥尾特征。
让我们看看下图中不同的峰度形态类型:
直方图是展示偏度和峰度的有效方式。让我们计算一下沟通技能分数列的峰度,如下所示:
# kurtosis of communication_skill_score column
data['communcation_skill_score'].kurtosis()
Output:
3.6010641852384015
在前面的代码块中,我们使用kurtosis()方法计算了沟通技能分数列的峰度。
使用协方差和相关系数理解关系
测量变量之间的关系将有助于数据分析师理解变量之间的动态关系——例如,人力资源经理需要了解员工绩效分数与满意度分数之间关系的强度。统计学提供了两种度量协方差和相关性来理解变量之间的关系。协方差衡量一对变量之间的关系。它显示变量的变化程度——即一个变量的变化如何影响另一个变量。其值范围从负无穷到正无穷。协方差的问题在于,它没有提供有效的结论,因为它没有标准化。让我们使用协方差来找出沟通技能和定量技能分数之间的关系,如下所示:
# Covariance between columns of dataframe
data.cov()
这将产生以下输出:
在前面的代码块中,协方差是通过cov()方法计算的。这里,该方法的输出是协方差矩阵。
皮尔逊相关系数
相关性显示了变量之间的相关程度。与协方差相比,相关性提供了更好的理解,并且是协方差的标准化版本。相关性的范围是从-1 到 1。负值表示一个变量的增加导致另一个变量的减少,或者变量朝同一方向变化。正值表示一个变量的增加导致另一个变量的增加,或者一个变量的减少导致另一个变量的减少。零值表示变量之间没有关系,或者变量是独立的。请看下面的代码片段:
# Correlation between columns of dataframe
data.corr(method ='pearson')
这将产生以下输出:
'method'参数可以取以下三种参数之一:
-
pearson: 标准相关系数 -
kendall: 肯德尔的 tau 相关系数 -
spearman: 斯皮尔曼等级相关系数
斯皮尔曼等级相关系数
斯皮尔曼等级相关系数是皮尔逊相关系数在观察值排名上的应用。它是一个非参数的等级相关度量,用于评估两个有序变量之间关联的强度。排名变量是顺序数值,按顺序排列。首先,我们对观察值进行排名,然后计算排名的相关性。它可以应用于连续型和离散型有序变量。当数据分布偏斜或受到异常值影响时,使用斯皮尔曼等级相关性而不是皮尔逊相关性,因为它不对数据分布做任何假设。
肯德尔等级相关系数
肯德尔等级相关系数或肯德尔 tau 系数是一个非参数统计量,用于衡量两个有序变量之间的关联性。它是等级相关的一种类型,衡量两个变量之间的相似性或不相似性。如果两个变量都是二元的,则皮尔逊相关系数=斯皮尔曼相关系数=肯德尔 tau 系数。
到目前为止,我们已经学习了描述性统计的主题,例如集中趋势度量、离散度量、分布度量和变量关系度量。现在是时候转向推断统计的主题,如中心极限定理、抽样技术,以及参数和非参数检验。
中心极限定理
数据分析方法包括假设检验和置信区间的确定。所有统计检验都假设总体呈正态分布。中心极限定理是假设检验的核心。根据该定理,随着样本量的增加,抽样分布趋近于正态分布。此外,样本的均值会更接近总体均值,样本的标准差会减小。这个定理对于推断统计学至关重要,它帮助数据分析师理解如何通过样本来获取关于总体的见解。
它是否能回答诸如“应该抽取多大样本”或“哪个样本量能准确代表总体”等问题?你可以通过以下图示来理解这一点:
在上面的图示中,你可以看到针对不同样本量(50、100、200 和 500)的四个直方图。如果你观察,会发现随着样本量的增加,直方图趋近于正态曲线。接下来让我们学习抽样技术。
收集样本
样本是用于数据分析的小规模群体。抽样是从各个来源收集样本数据的一个方法或过程,它是数据收集过程中至关重要的部分。实验的成功与否取决于数据收集的质量。如果抽样出现问题,将对最终的解读产生巨大影响。此外,收集整个群体的数据几乎是不可能的。抽样帮助研究人员从样本推断总体,并减少收集和管理数据的调查成本和工作量。有许多抽样技术可供选择,适用于不同目的。这些技术可以分为两类:概率抽样和非概率抽样,下面将详细描述这两类抽样方法:
-
概率抽样: 这种抽样方法对每个受访者进行随机选择,每个样本被选中的机会相等。这类抽样技术更耗时且成本较高,具体包括以下几种:
-
简单随机抽样: 采用这种技术,每个受访者都是通过随机方式选出的,这意味着每个受访者都有相等的机会被选中。这是一种简单直接的方法——例如,从 500 个产品中随机选出 20 个产品进行质量检测。
-
分层抽样: 采用这种技术时,整个群体被划分为小组,称为“层”,这些层是基于某些相似标准划分的。这些层的大小可能不相等。该技术通过减少选择偏差来提高准确性。
-
系统抽样: 采用这种技术时,受访者会按照规律性的间隔被选出。换句话说,可以说受访者是按系统顺序从目标群体中选出的,例如每隔n个受访者选出一个。
-
整群抽样: 这种抽样技术将整个群体划分为若干个群体或小组。群体的划分通常基于性别、地点、职业等因素。整个群体将用于抽样,而不是单独选择某一受访者。
-
-
非概率抽样: 这种抽样方法是非随机地从整个群体中选取每个受访者,选中的样本有不等的机会。其结果可能会存在偏差。这类抽样技术成本较低且更方便,具体包括以下几种:
-
方便抽样: 这是最简单的收集数据的方法。它根据受访者的可用性和参与意愿来选取受访者。统计学家通常偏爱这种方法进行初步调查,因为其成本低且数据收集速度快,但结果容易受到偏差的影响。
-
目的性抽样: 这种方法也称为判断抽样,因为它依赖于统计学家的判断。在实际操作中,统计学家根据一些预先定义的特征来决定谁将参与调查。新闻记者也常使用这种方法,选择他们希望获取意见的人。
-
配额抽样: 该技术预先定义了样本层次和比例的属性。样本受访者被选择,直到满足特定比例为止。它与分层抽样在选择策略上有所不同;它通过随机抽样选择各个层次中的项目。
-
滚雪球抽样: 该技术用于在样本人群稀少且难以追踪的情况下,如非法移民或艾滋病等领域。统计学家联系志愿者,帮助联系受害者。此方法也被称为推荐抽样,因为最初参与调查的人会推荐另一位符合样本描述的人。
-
在本节中,我们已了解了抽样方法及其类型:概率抽样和非概率抽样。接下来,我们将进入假设检验技术。在接下来的章节中,我们将重点讨论参数假设检验和非参数假设检验。
执行参数检验
假设是推断统计的核心主题。在本节中,我们将专注于参数检验。参数检验的基本假设是潜在的统计分布。大多数基础统计方法都是参数性质的。参数检验用于定量和连续数据。参数是代表整个总体的数字量。参数检验比非参数检验更强大、更可靠。假设是建立在总体分布参数上的。以下是一些参数检验的示例:
- t 检验是一种参数检验,用于检查两个相关组的均值是否存在显著差异。它是最常用的推断统计量,遵循正态分布。t 检验有两种类型:单样本 t 检验和双样本 t 检验。单样本 t 检验用于检查样本与假设总体均值之间是否存在显著差异。我们可以通过 t 检验,检查 10 名学生的平均体重是否为 68 公斤,如下所示:
import numpy as np
from scipy.stats import ttest_1samp
# Create data
data=np.array([63, 75, 84, 58, 52, 96, 63, 55, 76, 83])
# Find mean
mean_value = np.mean(data)
print("Mean:",mean_value)
Output:
Mean: 70.5
在前面的代码块中,我们创建了一个包含 10 名学生体重的数组,并使用numpy.mean()计算了其算术平均值。
让我们进行一个单样本 t 检验,如下所示:
# Perform one-sample t-test
t_test_value, p_value = ttest_1samp(data, 68)
print("P Value:",p_value)
print("t-test Value:",t_test_value)
# 0.05 or 5% is significance level or alpha.
if p_value < 0.05:
print("Hypothesis Rejected")
else:
print("Hypothesis Accepted")
Output:
P Value: 0.5986851106160134
t-test Value: 0.5454725779039431
Hypothesis Accepted
在前面的代码块中,我们使用ttest_1samp()检验了原假设(10 名学生的平均体重为 68 公斤)。输出结果显示,在 95%的置信区间内,原假设被接受,这意味着 10 名学生的平均体重是 68 公斤。
- 双样本 t 检验用于比较两组独立样本之间的显著差异。该检验也被称为独立样本 t 检验。我们可以比较两组独立学生的平均体重,如下所示:
原假设 H[0]: 样本均值相等—μ [1] = μ [2]
备择假设 H[a]: 样本均值不相等—μ [1] > μ [2] 或 μ [2] > μ [1]
看一下以下代码块:
from scipy.stats import ttest_ind
# Create numpy arrays
data1=np.array([63, 75, 84, 58, 52, 96, 63, 55, 76, 83])
data2=np.array([53, 43, 31, 113, 33, 57, 27, 23, 24, 43])
在前面的代码块中,我们创建了两组包含 10 名学生体重的数组。
接下来,我们进行双样本 t 检验,如下所示:
# Compare samples
stat, p = ttest_ind(data1, data2)
print("p-values:",p)
print("t-test:",stat)
# 0.05 or 5% is significance level or alpha.
if p < 0.05:
print("Hypothesis Rejected")
else:
print("Hypothesis Accepted")
Output:
p-values: 0.015170931362451255
t-test: 2.6835879913819185
Hypothesis Rejected
在前面的代码块中,我们使用 ttest_ind() 方法测试了两个组的平均体重的假设,结果显示原假设在 95%的置信区间内被拒绝,这意味着样本均值之间存在差异。
- 配对样本 t 检验是一种依赖样本 t 检验,用于判断同一组的两次观察值之间的均值差异是否为零——例如,比较患者群体在某种药物治疗前后的血压变化。这相当于单样本 t 检验,也称为依赖样本 t 检验。让我们进行配对 t 检验,以评估减重治疗的效果。我们已经收集了患者治疗前后的体重数据。可以通过以下假设表示:
原假设 H[0]: 两个依赖样本之间的均值差异为 0。
备择假设 H[a]: 两个依赖样本之间的均值差异不为 0。
看一下以下代码块:
# paired test
from scipy.stats import ttest_rel
# Weights before treatment
data1=np.array([63, 75, 84, 58, 52, 96, 63, 65, 76, 83])
# Weights after treatment
data2=np.array([53, 43, 67, 59, 48, 57, 65, 58, 64, 72])
在前面的代码块中,我们创建了两组包含 10 名患者治疗前后体重的数组。接下来,我们进行配对样本 t 检验,如下所示:
# Compare weights
stat, p = ttest_rel(data1, data2)
print("p-values:",p)
print("t-test:",stat)
# 0.05 or 5% is the significance level or alpha.
if p < 0.05:
print("Hypothesis Rejected")
else:
print("Hypothesis Accepted")
Output:
p-values: 0.013685575312467715
t-test: 3.0548295044306903
Hypothesis Rejected
在前面的代码块中,我们使用 ttest_rel() 方法测试了两个组的平均体重在治疗前后的假设。结果表明,原假设在 95%的置信区间内被拒绝,这意味着减重治疗对患者体重有显著影响。
-
方差分析(ANOVA):t 检验只适用于两组数据,但有时我们需要同时比较两组以上的数据。方差分析(ANOVA)(ANalysis Of VAriance)是一种统计推断检验,用于比较多个组之间的差异。它分析多个组之间和组内的方差,并同时检验多个原假设。通常,它用于比较两组以上的数据并检查统计显著性。我们可以通过三种方式使用方差分析:单因素方差分析、双因素方差分析和多因素方差分析。
-
使用单因素方差分析(ANOVA)方法,我们基于一个自变量比较多个组——例如,一家 IT 公司想根据绩效分数比较多个员工组或团队的生产力。在我们的例子中,我们正在比较三个位于不同地点的 IT 公司员工的绩效:孟买、芝加哥和伦敦。接下来,我们将进行单因素方差分析检验并检查绩效是否存在显著差异。我们先定义原假设和备择假设,如下所示:
原假设 H[0]: 多个地点的平均绩效得分没有差异。
备择假设 H[a]: 多个地点的平均绩效得分存在差异。
看一下以下的代码块:
from scipy.stats import f_oneway
# Performance scores of Mumbai location
mumbai=[0.14730927, 0.59168541, 0.85677052, 0.27315387, 0.78591207,0.52426114, 0.05007655, 0.64405363, 0.9825853 , 0.62667439]
# Performance scores of Chicago location
chicago=[0.99140754, 0.76960782, 0.51370154, 0.85041028, 0.19485391,0.25269917, 0.19925735, 0.80048387, 0.98381235, 0.5864963 ]
# Performance scores of London location
london=[0.40382226, 0.51613408, 0.39374473, 0.0689976 , 0.28035865,0.56326686, 0.66735357, 0.06786065, 0.21013306, 0.86503358]
在前面的代码块中,我们为三个地点:孟买、芝加哥和伦敦创建了三个员工表现分数的列表。
让我们进行一个单因素方差分析(ANOVA)检验,如下所示:
# Compare results using Oneway ANOVA
stat, p = f_oneway(mumbai, chicago, london)
print("p-values:", p)
print("ANOVA:", stat)
if p < 0.05:
print("Hypothesis Rejected")
else:
print("Hypothesis Accepted")
Output:
p-values: 0.27667556390705783
ANOVA: 1.3480446381965452
Hypothesis Accepted
在前面的代码块中,我们使用 f_oneway() 方法检验了不同地点之间平均表现分数没有差异的假设。前述结果显示,在 95% 的置信区间下,接受了原假设,这意味着各地点的平均表现分数之间没有显著差异。
-
通过双因素方差分析方法,我们基于两个独立变量比较多个组——例如,如果一家 IT 公司想要根据工作时长和项目复杂度来比较多个员工组或团队的生产力。
-
在 N 维方差分析中,我们基于 N 个独立变量比较多个组——例如,如果一家 IT 公司想要根据工作时长、项目复杂度、员工培训以及其他员工福利设施来比较多个员工组或团队的生产力。
在本节中,我们详细探讨了参数检验,如 t 检验和方差分析(ANOVA)检验。接下来让我们进入非参数假设检验部分。
执行非参数检验
非参数检验不依赖于任何统计分布,因此被称为“无分布”假设检验。非参数检验没有总体的参数。这类检验用于观察的顺序和排名,并需要特殊的排名和计数方法。以下是一些非参数检验的例子:
- 卡方检验 是通过单一总体中两个类别变量之间的显著差异或关系来确定的。通常,这个检验评估类别变量的分布是否相互不同。它也被称为卡方拟合优度检验或卡方独立性检验。卡方统计量的较小值意味着观察数据与期望数据吻合,而卡方统计量的较大值则意味着观察数据与期望数据不符。例如,性别对投票偏好的影响,或公司规模对健康保险覆盖范围的影响,可以通过卡方检验来评估:
这里,O 是观察值,E 是期望值,"i" 是列联表中的 "i^(th)" 位置。
让我们通过一个例子来理解卡方检验。假设我们在一家拥有 200 名员工的公司进行了调查,询问他们的最高学历,如高中、高中以上、大专、研究生,并将其与表现水平(如普通和优秀)进行对比。以下是假设和列联标准:
原假设 H[0]: 两个类别变量是独立的——即员工表现与最高学历水平是独立的。
备择假设 H[a]: 两个分类变量不是独立的——也就是说,员工表现与最高学历水平之间并非独立。
列联表可以表示如下:
| 高中 | 高等中学 | 本科 | 研究生 | |
|---|---|---|---|---|
| 平均值 | 20 | 16 | 13 | 7 |
| 优秀 | 31 | 40 | 50 | 13 |
让我们进行卡方检验,并检查变量之间的关联是否存在显著差异,具体如下:
from scipy.stats import chi2_contingency
# Average performing employees
average=[20, 16, 13, 7]
# Outstanding performing employees
outstanding=[31, 40, 60, 13]
# contingency table
contingency_table= [average, outstanding]
在上面的代码块中,我们创建了两组员工表现的列表,并构建了一个列联表。
让我们进行卡方检验,具体如下:
# Apply Test
stat, p, dof, expected = chi2_contingency(contingency_table)
print("p-values:",p)
if p < 0.05:
print("Hypothesis Rejected")
else:
print("Hypothesis Accepted")
Output:
p-values: 0.059155602774381234
Hypothesis Accepted
在上面的代码块中,我们检验了员工表现是否与最高学历水平独立的假设。结果表明,在 95% 的置信区间内接受了原假设,这意味着员工表现与最高学历水平之间是独立的。
- Mann-Whitney U 检验是 t 检验的非参数对应检验,适用于两个样本。它不假设样本之间的差异符合正态分布。当观察值为序数且 t 检验的假设条件不成立时(例如,比较两组电影评分偏好),可以使用 Mann-Whitney U 检验。让我们通过以下标准比较两组电影评分:
原假设 H[0]: 两个样本分布之间没有差异。
备择假设 H[a]: 两个样本分布之间存在差异。
请查看以下代码块:
from scipy.stats import mannwhitneyu
# Sample1
data1=[7,8,4,9,8]
# Sample2
data2=[3,4,2,1,1]
在上面的代码块中,我们创建了两个数据列表。
让我们进行 Mann-Whitney U 检验,具体如下:
# Apply Test
stat, p = mannwhitneyu(data1, data2)
print("p-values:",p)
# 0.01 or 1% is significance level or alpha.
if p < 0.01:
print("Hypothesis Rejected")
else:
print("Hypothesis Accepted")
Output:
p-values: 0.007666581056801412
Hypothesis Rejected
在上面的代码块中,我们使用 mannwhitneyu() 方法检验了“两个电影评分组之间是否存在差异”的假设。结果表明,原假设在 99% 的置信区间内被拒绝,意味着两个电影评分组之间存在显著差异。
- Wilcoxon 符号秩检验用于比较两个配对样本。它是配对 t 检验的非参数对应检验。它检验的原假设是两个配对样本是否属于同一分布——例如,比较多组治疗观察的差异。让我们通过以下标准比较两组治疗观察的差异:
原假设 H[0]: 两个依赖样本分布之间没有差异。
备择假设 H[a]: 依赖样本分布之间存在差异。
请查看以下代码块:
from scipy.stats import wilcoxon
# Sample-1
data1 = [1, 3, 5, 7, 9]
# Sample-2 after treatement
data2 = [2, 4, 6, 8, 10]
在上面的代码块中,我们创建了两个数据列表。
让我们进行 Wilcoxon 符号秩检验,具体如下:
# Apply
stat, p = wilcoxon(data1, data2)
print("p-values:",p)
# 0.01 or 1% is significance level or alpha.
if p < 0.01:
print("Hypothesis Rejected")
else:
print("Hypothesis Accepted")
Output:
p-values: 0.025347318677468252
Hypothesis Accepted
在前面的代码块中,我们使用 wilcoxon() 方法检验了治疗前后组间分布是否有差异的假设。前面的结果表明,在 99%的置信区间内接受了原假设,这意味着治疗前后组之间没有显著差异。
- Kruskal-Wallis 检验是单因素方差分析(ANOVA)的非参数版本,用于评估样本是否来自相同的分布。它比较两个或更多独立样本。它扩展了 Mann-Whitney U 检验的限制,后者仅比较两组样本。我们通过以下代码来比较三组样本:
from scipy.stats import kruskal
# Data sample-1
x = [38, 18, 39, 83, 15, 38, 63, 1, 34, 50]
# Data sample-2
y = [78, 32, 58, 59, 74, 77, 29, 77, 54, 59]
# Data sample-3
z = [117, 92, 42, 79, 58, 117, 46, 114, 86, 26]
在前面的代码块中,我们创建了三组数据列表。接下来,我们进行 Kruskal-Wallis 检验,如下所示:
# Apply kruskal-wallis test
stat, p = kruskal(x,y,z)
print("p-values:",p)
# 0.01 or 1% is significance level or alpha.
if p < 0.01:
print("Hypothesis Rejected")
else:
print("Hypothesis Accepted")
Output:
p-values: 0.01997922369138151
Hypothesis Accepted
在前面的代码块中,我们使用 kruskal() 方法检验了三组样本间是否有差异的假设。前面的结果表明,在 99%的置信区间内接受了原假设,这意味着三组样本之间没有差异。接下来,我们将比较参数检验和非参数检验,如下所示:
| 特征 | 参数检验 | 非参数检验 |
|---|---|---|
| 检验统计量 | 分布 | 任意分布或“无分布假设” |
| 属性类型 | 数值型 | 名义型和有序型 |
| 集中趋势测量 | 均值 | 中位数 |
| 相关性检验 | Pearson 相关性 | Spearman 相关性 |
| 关于总体的信息 | 完整信息 | 无信息 |
在前面的表格中,您看到了基于多种特征(如检验统计量、属性类型、集中趋势测量、相关性检验和总体信息)进行的参数检验和非参数检验的示例。最后,您完成了这一章节。在本章节中,我们探讨了描述性统计学和推断性统计学的基础知识,并结合 Python 进行了实践。
总结
统计学的核心基础将为数据分析提供基础,帮助我们理解数据的描述和意义。在本章节中,您学习了统计学的基础知识,如属性及其不同类型(如名义型、顺序型和数值型)。您还学习了用于衡量集中趋势的均值、中位数和众数。范围、四分位距、方差和标准差用于估计数据的变异性;偏度和峰度用于理解数据分布;协方差和相关性用于理解变量间的关系。您还了解了推断性统计学的相关主题,如中心极限定理、样本收集以及参数检验和非参数检验。您还使用 pandas 和 scipy.stats 库在统计学概念上进行了动手实践。
下一章,第四章,线性代数,将帮助我们学习如何解线性方程组,求解特征值和特征向量,并使用 Python 包 NumPy 和 SciPy 学习二项分布和正态分布、正态性检验以及掩蔽数组。