Python-和-R-的-Excel-扩展指南-全-

Python 和 R 的 Excel 扩展指南(全)

原文:zh.annas-archive.org/md5/57a2a415d424b29995b77f095caad66b

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

欢迎来到 使用 Python 和 R 扩展 Excel 的世界!在这本书中,我们深入探讨了 Excel 与 Python 和 R 强大功能的结合,提供了利用这些语言进行数据操作、分析、可视化和更多方面的全面指南。

加入我们的旅程,探索 Excel、R 和 Python 的交汇点,让你在当今数据驱动型环境中脱颖而出。

本书面向读者

本书是为有一定数据分析经验且熟悉 Excel 基础的 R 和/或 Python 中级或高级用户设计的。

本书涵盖内容

第一章读取 Excel 工作表,深入探讨了将数据从 Excel 导入 R/Python 的过程。你将从将第一个 Excel 表格导入 R 开始,了解 Excel 文件的高级细节,并以 Python 的对应部分结束。

第二章编写 Excel 工作表,解释了在 R/Python 中分析数据后,如何有效地与 Excel 用户沟通发现。本章提供了从 R/Python 创建 Excel 表格以及导出分析结果的见解。

第三章从 R 和 Python 执行 VBA 代码,探讨了除了将结果输出到 Excel 之外,你可能还想向结果 Excel 表格中添加 VBA 宏和函数,以进一步增强分析结果最终用户的功能。我们可以在本章中做到这一点。

第四章进一步自动化 - 任务调度和电子邮件,涵盖了如何使用 R 的 RDCOMClient 包(与 Outlook 一起工作)和 Blastula 包(在 R 中帮助自动化分析和发送报告)。在 Python 中,smtplib 包具有相同的功能。

第五章格式化您的 Excel 工作表,讨论了如何使用包在 Excel 中创建带有格式化数据的表格和表格,以及如何使用它们创建精美的 Excel 报告。

第六章插入 ggplot2/matplotlib 图表,展示了如何从 ggplot2matplotlib 创建图形。用户还可以使用 ggplot2 主题以及其他主题在 R/Python 中创建美观的图形,并将它们放置在 Excel 中。

第七章数据透视表和汇总表,探讨了使用 R 和 Python 在 Excel 中的数据透视表世界。学习如何直接从 R/Python 创建和操作数据透视表,以便与 Excel 无缝交互。

第八章使用 R 和 Python 进行数据探索分析,解释了如何从 Excel 中提取数据并执行 R 的 {skimr} 和 Python 的 pandasppscore

第九章, 统计分析:线性与逻辑回归,教您如何在 Excel 数据上使用 R 和 Python 进行简单的统计分析。

第十章, 时间序列分析:统计、绘图和预测,解释了如何使用 R 中的forecast包和 Python 中的kats以及长短期记忆LSTM)进行简单的时间序列分析。

第十一章, 从 Excel 直接或通过 API 调用 R/Python,从 Excel 本地和通过 API 调用 R 和 Python。本章还涵盖了使用 BERT 和xlwings从 Excel 调用本地 R/Python 安装的开源工具,以及开源和商业 API 解决方案。

第十二章, 使用 R 和 Python 在 Excel 中进行数据分析与可视化——案例研究,展示了通过调用 R 或 Python 在 Excel 中执行数据可视化和机器学习的案例研究。

要充分利用本书

在深入本书之前,对 R 或 Python(或两者)有一个中级理解是有帮助的,包括使用 pandas、NumPy 和 tidyverse 等库进行数据操作和分析的中级熟练度。熟悉 Excel 基础知识,如导航电子表格和执行简单的数据操作,也是假设的。此外,对统计概念和数据可视化技术的初步了解将有助于跟随本书中提供的示例和练习。

本书涵盖的软件/硬件 操作系统要求
R Windows(用于 VBA 部分),macOS 或 Linux(用于除 VBA 之外的所有内容)
Python 3.11
Excel(包括 VBA)

每章将提供相关包和工具的安装指南。

如果您正在使用本书的数字版,我们建议您自己输入代码或从本书的 GitHub 仓库(下一节中有一个链接)获取代码。这样做将帮助您避免与代码的复制和粘贴相关的任何潜在错误

免责声明

作者承认使用了尖端的人工智能,如 ChatGPT,其唯一目的是增强本书的语言和清晰度,从而确保读者有一个顺畅的阅读体验。重要的是要注意,内容本身是由作者创作的,并由专业出版团队编辑的。

下载示例代码文件

您可以从 GitHub 下载本书的示例代码文件:github.com/PacktPublishing/Extending-Excel-with-Python-and-R。如果代码有更新,它将在 GitHub 仓库中更新。

使用的约定

本书使用了多种文本约定。

文本中的代码:表示文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称。以下是一个示例:“styledtables 包只能通过 devtools 包从 GitHub 安装。”

代码块设置如下:

install.packages("devtools")
# Install development version from GitHub
devtools::install_github(
'R-package/styledTables',
build_vignettes = TRUE
)

任何命令行输入或输出都按以下方式编写:

python –m pip install pywin32==306

iris_data.xlsm 文件中包含宏,可以通过转到 开发者 | 宏(或 Visual Basic) 来查看宏是否存在。”

小贴士或重要注意事项

看起来像这样。

联系我们

我们读者的反馈始终受到欢迎。

总体反馈:如果您对本书的任何方面有任何疑问,请通过电子邮件发送至 customercare@packtpub.com,并在邮件主题中提及书名。

勘误:尽管我们已经尽一切努力确保内容的准确性,但错误仍然可能发生。如果您在本书中发现错误,我们将不胜感激,如果您能向我们报告,请访问 www.packtpub.com/support/errata 并填写表格。

盗版:如果您在互联网上发现我们作品的任何形式的非法副本,如果您能提供位置地址或网站名称,我们将不胜感激。请通过电子邮件发送至 copyright@packt.com 并附上材料的链接。

如果您有兴趣成为作者:如果您在某个领域有专业知识,并且您有兴趣撰写或为书籍做出贡献,请访问 authors.packtpub.com

分享您的想法

读完 使用 Python 和 R 扩展 Excel 后,我们很乐意听到您的想法!请 点击此处直接转到该书的 Amazon 评论页面 并分享您的反馈。

您的评论对我们和科技社区都很重要,并将帮助我们确保我们提供高质量的内容。

下载本书的免费 PDF 副本

感谢您购买本书!

您喜欢在路上阅读,但又无法携带您的印刷书籍到处走?

您的电子书购买是否与您选择的设备不兼容?

别担心,现在每购买一本 Packt 书籍,您都可以免费获得该书的 DRM 免费 PDF 版本。

在任何地方、任何地点、任何设备上阅读。直接从您最喜欢的技术书籍中搜索、复制和粘贴代码到您的应用程序中。

优惠不会就此结束,您还可以获得独家折扣、时事通讯和每日免费内容的每日电子邮件。

按照以下简单步骤获取好处:

  1. 扫描二维码或访问以下链接

![下载本书的免费 PDF 副本

二维码

](https://packt.link/free-ebook/9781804610695)

packt.link/free-ebook/9781804610695

  1. 提交您的购买证明

  2. 就这样!我们将直接将您的免费 PDF 和其他福利发送到您的邮箱

第一部分:基础知识 - 从 R 和 Python 读取和写入 Excel 文件

这一部分为在 R 和 Python 中处理 Excel 文件奠定了基础。章节涵盖了诸如使用 R 和 Python 等流行库读取和写入 Excel 电子表格等基本任务,使您能够使用RDCOMClientblastulaschedulesmtplib等工具自动化任务,并进一步通过这些工具增强您的 Excel 工作流程,例如安排运行和发送emails.readxlopenxlsxxlsxpandasopenpyxl。此外,您还将学习如何执行 VBA 代码。

本部分包含以下章节:

  • 第一章读取 Excel 电子表格

  • 第二章编写 Excel 电子表格

  • 第三章从 R 和 Python 执行 VBA 代码

  • 第四章进一步自动化 - 任务调度和电子邮件

第一章:读取 Excel 电子表格

在深入和广泛的数据分析领域中,Excel 作为一位值得信赖的战士,站在您的身边,简化了组织、计算和展示信息的过程。其直观的界面和广泛的使用使其在商业世界中成为必备品。然而,随着数据量和复杂性的指数级增长,Excel 的功能可能会开始感到受限。正是在这一点上,Excel、R 和 Python 的世界交汇。通过 R 和 Python 扩展 Excel,邀请您踏上真正变革的旅程。这次旅行将向您展示这些编程语言与 Excel 协同工作的力量,扩展其视野,并使您能够轻松征服数据挑战。在这本书中,我们将深入研究如何将 Excel 与 R 和 Python 集成,揭示隐藏在表面之下的潜力,并使您能够提取有价值的见解,自动化流程,并释放数据分析的真正力量。

微软 Excel 于 1985 年上市,并一直是一种流行的电子表格软件选择。Excel 最初被称为 MultiPlan。在组织和管理数据方面,Microsoft Excel 和数据库在某种程度上具有相似之处,尽管它们服务于不同的目的。Excel 是一种电子表格程序,允许用户以表格格式存储和操作数据。它由行和列组成,其中每个单元格可以包含文本、数字或公式。同样,数据库是一个结构化数据集合,以表格形式存储,由行和列组成。

Excel 和数据库都提供了一种存储和检索数据的方式。在 Excel 中,您可以输入数据,执行计算,并创建图表和图形。同样,数据库存储和管理大量结构化数据,并支持查询、排序和过滤。Excel 和数据库也支持关系概念。在 Excel 中,您可以链接不同工作表中的单元格或范围,创建数据之间的连接。数据库使用关系根据公共字段链接表,允许您从多个表中检索相关数据。

本章旨在使您熟悉将 Excel 文件读取到 R 环境中,并对它们进行一些操作。具体来说,在本章中,我们将涵盖以下主要主题:

  • 用于 Excel 操作的 R 包

  • 使用 R 读取 Excel 文件进行操作

  • 使用自定义 R 函数读取多个 Excel 工作表

  • 用于 Excel 操作的 Python 包

  • 从 Python 打开 Excel 工作表并读取数据

技术要求

在编写本文档时,我们使用以下:

  • R 4.2.1

  • RStudio 2023.03.1+446“樱花”版本,适用于 Windows

对于本章,您需要安装以下包:

  • readxl

  • openxlsx

  • xlsx

要运行本章中的 Python 代码,我们将使用以下:

  • Python 3.11

  • pandas

  • openpyxl

  • 本书 GitHub 仓库中提供的 iris.xlsx Excel 文件

虽然设置 Python 环境超出了本书的范围,但这很容易做到。可以通过运行以下命令来安装必要的包:

python -m pip install pandas==2.0.1
python -m pip install openpyxl==3.1.2

注意,这些命令必须在终端中运行,而不是在 Python 脚本内部运行。它们需要在 requirements.txt 文件所在的文件夹中运行,或者必须包含 requirements.txt 文件的完整路径。

本书 GitHub 仓库还包含一个 requirements.txt 文件,你可以使用它来安装所有依赖。你可以通过运行以下命令来完成此操作:

python -m pip install -r requirements.txt

此命令安装了本章将使用的所有包,这样你就不必逐个安装它们。它还保证了整个依赖树(包括依赖的依赖)将与本书作者使用的完全相同。

或者,当使用 Jupyter Notebooks 时,你可以使用以下魔法命令:

%pip install pandas==2.0.1
%pip install openpyxl==3.1.2

本书中的所有代码示例的 GitHub 账户位于以下链接:github.com/PacktPublishing/Extending-Excel-with-Python-and-R。每个章节都有自己的文件夹,当前文件夹名为 Chapter01

注意

本书对 Python 的技术要求方便地编译在 requirements.txt 文件中,可在 GitHub 仓库中找到,github.com/PacktPublishing/Extending-Excel-with-Python-and-R/blob/main/requirements.txt。安装这些依赖项将简化你的编码体验,并确保你在本书中的学习过程顺利。在开始练习之前,请确保安装所有这些依赖项。

使用 R 包进行 Excel 操作

在 CRAN 和 GitHub 上都有几个包可用于读取和操作 Excel 文件。在本节中,我们将特别关注以下包:readxlopenxlsxxlsx,用于读取 Excel 文件。这些包都有自己的函数来读取 Excel 文件。这些函数如下:

  • readxl::read_excel()

  • openxlsx::read.xlsx()

  • xlsx::read.xlsx()

每个函数都有一组参数和遵循的约定。由于 readxltidyverse 包集合的一部分,它遵循其约定,并在读取文件时返回一个 tibble 对象。如果你不知道什么是 tibble,它是一种 R 的 data.frame 的现代版本,在 R 环境中类似于电子表格。它是大多数分析的基础。接下来是 openxlsxxlsx,它们都返回一个基本的 R data.frame 对象,后者还能返回一个 list 对象。如果你想知道这如何与操作实际的 Excel 文件相关联,我可以解释。首先,要在 R 中操作某些东西,数据必须位于 R 环境中,因此除非数据被读取,否则你不能操作文件。这些包有不同的函数用于以特定方式操作 Excel 或读取数据,从而允许进行进一步的分析和或操作。需要注意的是,xlsx 需要安装 Java。

随着我们从对 R 包的 Excel 操作探索过渡,我们将把注意力转向一个关键任务,即有效地将 Excel 文件读入 R,从而解锁数据分析和处理更多的可能性。

将 Excel 文件读入 R

在本节中,我们将使用几个不同的 R 库从 Excel 中读取数据。在我们考虑对 Excel 文件中的工作表中的数据进行任何类型的操作或分析之前,我们必须这样做。

如技术要求部分所述,我们将使用 readxlopenxlsxxlsx 包将数据读入 R。

安装和加载库

在本节中,如果你还没有这些库,我们将安装和加载必要的库。我们将使用 openxlsxxlsxreadxlreadxlsb 库。要安装和加载它们,请运行以下代码块:

pkgs <- c("openxlsx", "xlsx", "readxl")
install.packages(pkgs, dependencies = TRUE)
lapply(pkgs, library, character.only = TRUE)

R 中的 lapply() 函数是一个适用于将函数应用于列表、向量或 DataFrame 中每个元素的通用工具。它接受两个参数,xFUN,其中 x 是列表,FUN 是应用于列表对象 x 的函数。

现在库已经安装好了,我们可以开始工作了。为此,我们将读取由 R 的基础库中构建的 Iris 数据集构建的电子表格。我们将使用三个不同的库来读取文件,然后我们将创建一个自定义函数来使用 readxl 库读取 Excel 文件的全部工作表。我们将把这个函数称为 read_excel_sheets()

让我们开始读取文件。我们将使用 openxlsx 库来打开 Excel 文件。要读取我们正在处理的 Excel 文件,你可以运行本书 GitHub 仓库中 chapter1 文件夹中的 ch1_create_iris_dataset.R 文件中的代码。参考以下截图以了解如何将文件读入 R。

你会注意到一个名为f_pat的变量。这是将 Iris 数据集保存为 Excel 文件的路径——例如,C:/User/UserName/Documents/iris_data.xlsx

图 1.1 – 使用 openxlsx 包读取 Excel 文件

图 1.1 – 使用 openxlsx 包读取 Excel 文件

上述截图显示了如何读取 Excel 文件。这个例子假设你已经使用了ch1_create_iris_datase.R文件来创建示例 Excel 文件。实际上,你可以读取任何你想要或需要的 Excel 文件。

现在,我们将执行相同类型的操作,但这次使用的是xlsx库。参考以下截图,它使用了与openxlsx包相同的方法:

图 1.2 – 使用 xlsx 库和 read.xlsx()函数打开我们创建的 Excel 文件

图 1.2 – 使用 xlsx 库和 read.xlsx()函数打开我们创建的 Excel 文件

最后,我们将使用readxl库,它是 tidyverse 的一部分:

图 1.3 – 使用 readxl 库和 read_excel()函数将 Excel 文件读入内存

图 1.3 – 使用 readxl 库和 read_excel()函数将 Excel 文件读入内存

在本节中,我们学习了如何使用几个不同的包读取 Excel 文件。虽然这些包可以完成比简单地读取 Excel 文件更多的工作,但这是我们本节需要关注的内容。你现在应该熟悉如何使用readxl::read_excel()xlsx::read.xlsx()openxlsx::read.xlsx()函数。

建立在将 Excel 文件读入 R 的专长之上,我们现在将开始旅程的下一阶段:揭示从 Excel 文件中的多个工作表高效提取数据的秘密。

使用 readxl 和自定义函数读取多个工作表

在 Excel 中,我们经常遇到包含多个工作表的电子表格。这些可能是不同月份的统计数据,按月遵循特定格式的表格数据,或者某些其他周期。关键是,我们可能出于某种原因想要读取文件中的所有工作表,并且我们不应该为每个工作表从特定的包中调用读取函数。相反,我们应该使用 R 的力量通过purrr循环遍历:

让我们构建一个自定义函数。为此,我们将加载readxl函数。如果我们已经加载了它,那么这就不必要了;然而,如果它已经安装并且我们不希望将库加载到内存中,那么我们可以通过使用readxl::excel_sheets()来调用excel_sheets()函数:

图 1.4 – 创建一个函数,一次性将所有工作表读入 Excel 文件 – read_excel_sheets()

图 1.4 – 创建一个函数,一次性将所有工作表读入 Excel 文件 – read_excel_sheets()

新代码可以分解如下:

 read_excel_sheets <- function(filename, single_tbl) {

这一行定义了一个名为read_excel_sheets的函数,它接受两个参数:filename(要读取的 Excel 文件名)和single_tbl(一个逻辑值,指示函数是否应返回单个表格或表格列表)。

接下来,我们有以下行:

sheets <- readxl::excel_sheets(filename)

这一行使用readxl包从指定的filename Excel 文件中提取所有工作表的名称。工作表名称存储在sheets变量中。

这是下一行:

if (single_tbl) {

这一行开始了一个if语句,用于检查single_tbl参数的值。

现在,我们有以下内容:

x <- purrr::map_df(sheets, read_excel, path = filename)

如果single_tblTRUE,则这一行使用purrr包的map_df函数遍历sheets中的每个工作表名称,并使用readxl包的read_excel函数读取相应的工作表。结果DataFrame合并为一个单独的表格,并分配给x变量。

现在,我们有以下行:

} else {

这一行表示if语句的else块的开始。如果single_tblFALSE,则执行此块中的代码。

这是下一行:

 x <- purrr::map(sheets, ~ readxl::read_excel(filename, sheet = .x))

在这一行中,使用purrr包的map函数遍历sheets中的每个工作表名称。对于每个工作表,调用readxl包中的read_excel函数从指定的filename Excel 文件中读取相应的工作表。结果DataFrame存储在分配给x变量的列表中。

现在,我们有以下内容:

 purrr::set_names(x, sheets)

这一行使用purrr包的set_names函数将x列表中元素的名字设置为sheets中的工作表名称。

最后,我们有以下行:

 x

这一行返回函数中的x值,如果single_tblTRUE,则返回单个表格(data.frame),如果single_tblFALSE,则返回表格列表(data.frame)。

总结来说,read_excel_sheets函数接受一个 Excel 文件名和一个逻辑值,表示是否返回单个表格或表格列表。它使用readxl包从 Excel 文件中提取工作表名称,然后根据single_tbl的值(如果为TRUE则将对应的工作表读入单个表格,如果为FALSE则读入表格列表)读取相应的工作表。结果数据作为函数的输出返回。为了了解其工作原理,让我们看看以下示例。

我们有一个包含四个标签的工作表——每个标签对应著名的 Iris 数据集中的每个物种,还有一个名为iris的工作表,它包含完整的数据集。

图 1**.5所示,read_excel_sheets()函数已读取 Excel 文件中的所有四个工作表。我们还可以看到,该函数已将工作表作为列表对象导入,并且已将列表中的每个项目命名为 Excel 文件中对应标签的名称。值得注意的是,为了使此操作生效,所有工作表必须具有相同的列名和结构:

图 1.5 – read_excel_sheets()读取的 Excel 文件

图 1.5 – 使用 read_excel_sheets() 读取的 Excel 文件

在本节中,我们学习了如何编写一个函数,该函数将读取任何 Excel 文件中的所有工作表。此函数还将它们作为命名项列表返回,其中名称是文件本身中标签页的名称。

现在我们已经学习了如何在 R 中读取 Excel 表格,在下一节中,我们将介绍 Python,我们将从 Python 语言的角度重新审视相同的概念。

用于 Excel 操作的 Python 包

在本节中,我们将探讨如何使用 Python 读取 Excel 工作表。在 Python 中处理 Excel 文件的一个关键方面是拥有提供必要功能的正确包集。在本节中,我们将讨论一些常用的用于 Excel 操作的 Python 包,并突出它们的优点和考虑因素。

用于 Excel 操作的 Python 包

当涉及到在 Python 中与 Excel 文件交互时,有几个包提供了一系列的功能和特性。这些包允许您从 Excel 文件中提取数据,操作数据,并将其写回 Excel 文件。让我们来看看一些流行的用于 Excel 操作的 Python 包。

pandas

pandas 是一个强大的数据处理库,它可以通过 read_excel 函数读取 Excel 文件。使用 pandas 的优点是它提供了一个 DataFrame 对象,这使得您能够以表格形式操作数据。这使得进行数据分析和操作变得容易。pandas 在高效处理大型数据集方面表现出色,并提供了灵活的数据过滤、转换和聚合选项。

openpyxl

openpyxl 是一个广泛使用的库,专门设计用于处理 Excel 文件。它提供了一套全面的特性用于读取和写入 Excel 工作表,包括对各种 Excel 文件格式的支持以及与不同版本 Excel 的兼容性。此外,openpyxl 允许对 Excel 文件的结构和内容进行精细控制,使得访问单个单元格、创建新工作表和应用格式等任务成为可能。

xlrd 和 xlwt

xlrdxlwt 是一些较老的库,它们仍然被用于读取和写入 Excel 文件,尤其是用于 .xls 这样的旧格式。xlrd 允许从 Excel 文件中读取数据,而 xlwt 则便于将数据写入 Excel 文件。这些库轻量级且易于使用,但它们缺乏 pandasopenpyxl 提供的一些高级特性。

考虑因素

在选择用于 Excel 操作的 Python 包时,考虑您项目的具体需求至关重要。以下是一些需要考虑的因素:

  • 功能:评估包的功能,并确保它满足您读取 Excel 文件的需求。考虑您是否需要高级数据操作功能,或者一个更简单的包是否足够。

  • pandas 拥有优化的算法,可以提供显著的性能优势。

  • 兼容性:检查包与不同 Excel 文件格式和版本的兼容性。确保它支持您正在使用的特定格式,以避免任何兼容性问题。

  • pandas 拥有更广泛的功能,但可能需要更多的时间和精力来掌握。

每个包都提供独特的功能,各有其优势和劣势,使您能够有效地在 Python 中读取 Excel 电子表格。例如,如果您需要读取和操作大量数据,pandas 可能是更好的选择。然而,如果您需要精细控制 Excel 文件,openpyxl 可能更适合您的需求。

考虑您项目的具体要求,例如数据大小、功能性和兼容性,以选择最适合您需求的包。在接下来的章节中,我们将深入探讨如何使用这些包通过 Python 读取和提取 Excel 文件中的数据。

从 Python 中打开 Excel 工作表并读取数据

在 Python 中处理 Excel 文件时,通常需要打开特定的工作表并将数据读入 Python 进行进一步分析。这可以通过使用前面章节中讨论的流行库,如 pandasopenpyxl 来实现。

您很可能会使用其他 Python 和包版本,但本节中的代码尚未与其他任何内容进行测试,除了我们在此处所提到的。

使用 pandas

pandas 是一个强大的数据处理库,简化了处理结构化数据的过程,包括 Excel 电子表格。要使用 pandas 读取 Excel 工作表,您可以使用 read_excel 函数。让我们考虑使用名为 setosa 的工作表来使用 iris_data.xlsx 文件的一个示例:

import pandas as pd
# Read the Excel file
df = pd.read_excel('iris_data.xlsx', sheet_name='setosa')
# Display the first few rows of the DataFrame
print(df.head())

您需要将此代码运行在 Python 的工作目录设置为 Excel 文件所在的位置,或者您需要在 read_excel() 命令中提供文件的完整路径:

图 1.6 – 使用 pandas 包读取 Excel 文件

图 1.6 – 使用 pandas 包读取 Excel 文件

在前面的代码片段中,我们导入了 pandas 库并使用了 read_excel 函数从 iris_data.xlsx 文件中读取 setosa。结果数据存储在 pandasDataFrame 中,它提供了数据的表格表示。通过在 DataFrame 上调用 head(),我们显示了数据的前几行,以便快速预览。

使用 openpyxl

openpyxl 是一个强大的库,用于处理 Excel 文件,它提供了对单个单元格和工作表的更细粒度控制。要使用 openpyxl 打开 Excel 工作表并访问其数据,我们可以使用 load_workbook 函数。请注意,openpyxl 无法处理 .xls 文件,只能处理更现代的 .xlsx.xlsm 版本。

让我们考虑一个使用名为 versicolor 的工作表的 iris_data.xlsx 文件的例子:

import openpyxl
import pandas as pd
# Load the workbook
wb = openpyxl.load_workbook('iris_data.xlsx')
# Select the sheet
sheet = wb['versicolor']
# Extract the values (including header)
sheet_data_raw = sheet.values
# Separate the headers into a variable
header = next(sheet_data_raw)[0:]
# Create a DataFrame based on the second and subsequent lines of data with the header as column names
sheet_data = pd.DataFrame(sheet_data_raw, columns=header)
print(sheet_data.head())

以下代码的结果如下:

图 1.7 – 使用 openpyxl 包读取 Excel 文件

图 1.7 – 使用 openpyxl 包读取 Excel 文件

在这个代码片段中,我们从 openpyxl 库中导入 load_workbook 函数。然后,我们通过提供 iris_data.xlsx 文件名来加载工作簿。接下来,我们通过访问其名称来选择所需的工作表——在这种情况下,这是 versicolor。一旦我们完成这个操作,我们就使用加载的工作表对象的 values 属性来读取原始数据。这是一个生成器,可以通过 for 循环或将其转换为列表或 DataFrame 等方式来访问。在这个例子中,我们将其转换为 pandas DataFrame,因为这是以后最舒适的工作格式。

pandasopenpyxl 都为在 Python 中处理 Excel 文件提供了有价值的特性。虽然 pandas 通过其 DataFrame 结构简化了数据操作,但 openpyxl 提供了对单个单元格和工作表的更精细的控制。根据您的具体需求,您可以选择最适合您需求的库。

通过掌握打开 Excel 工作表并将数据读入 Python 的技术,您将能够从 Excel 数据中提取有价值的见解,执行各种数据转换,并为其进一步的分析或可视化做准备。这些技能对于任何寻求利用 Python 和 Excel 的力量在他们的数据驱动工作流程中的人来说是必不可少的。

使用 Python 读取多个工作表(openpyxl 和自定义函数)

在许多 Excel 文件中,常见的情况是包含多个工作表,每个工作表包含不同的数据集。能够读取多个工作表并将数据合并到单一的数据结构中,对于分析和处理来说非常有价值。在本节中,我们将探讨如何使用 openpyxl 库和自定义函数来实现这一点。

读取多个工作表的重要性

当处理复杂的 Excel 文件时,遇到相关数据分散在不同工作表中的情况并不少见。例如,您可能有一个用于销售数据的工作表,另一个用于客户信息,还有一个用于产品库存。通过读取多个工作表并合并数据,您可以获得全面的视角并执行全面的分析。

让我们先来检查读取多个工作表所涉及的基本步骤:

  1. openpyxl 提供的 load_workbook 函数。

  2. sheetnames 属性。这允许我们识别我们想要读取的工作表。

  3. Openpyxl 提供了 iter_rowsiter_cols 等方法来遍历每个工作表的单元格并检索所需的数据。

  4. pandas DataFrame 或 Python 列表。当我们从每个工作表读取数据时,我们将它连接或合并到合并的数据结构中:

    • 如果所有工作表中的数据都遵循相同的格式(如本章中使用的示例),我们可以简单地连接数据集

    • 然而,如果数据集具有不同的结构,因为它们描述了数据集的不同方面(例如,一个工作表包含产品信息,下一个包含客户数据,第三个包含产品对客户的销售),那么我们可以根据唯一标识符合并这些数据集以创建一个综合数据集

使用 openpyxl 访问工作表

openpyxl 是一个强大的库,它允许我们使用 Python 与 Excel 文件交互。它提供了一系列功能,包括访问和操作多个工作表。在我们深入了解细节之前,让我们花点时间了解为什么 openpyxl 是这个任务的流行选择。

openpyxl 的一个主要优点是它能够处理各种 Excel 文件格式,如 .xlsx.xlsm。这种灵活性允许我们处理不同版本的 Excel 文件而不会出现兼容性问题。此外,openpyxl 提供了一个简单直观的接口来访问工作表数据,这使得我们更容易检索所需的信息。

从每个工作表中读取数据

要开始读取多个工作表,我们需要使用 openpyxl 提供的 load_workbook 函数加载 Excel 工作簿。这个函数接受文件路径作为输入,并返回一个表示整个 Excel 文件的工作簿对象。

一旦我们加载了工作簿,我们可以使用 sheetnames 属性检索所有工作表的名称。这给我们一个在 Excel 文件中存在的表名列表。然后我们可以遍历这些表名,逐个读取每个工作表中的数据。

使用 openpyxl 获取工作表数据

openpyxl 提供了各种方法来访问工作表中的数据。

两种常用的方法是 iter_rowsiter_cols。这些方法允许我们遍历工作表的行或列,并检索单元格值。

让我们看看 iter_rows 可以如何使用:

# Assuming you are working with the first sheet
sheet = wb['versicolor']
# Iterate over rows and print raw values
for row in sheet.iter_rows(min_row=1, max_row=5, values_only=True):
    print(row)

类似地,iter_cols 可以这样使用:

# Iterate over columns and print raw values
for column in sheet.iter_cols(min_col=1, max_col=5, values_only=True):
    print(column)

当使用 iter_rowsiter_cols 时,我们可以指定我们想要检索单元格值是原始值还是格式化值。原始值给我们实际的单元格数据,而格式化值包括应用于单元格的任何格式,例如日期格式或数字格式。

通过遍历工作表的行或列,我们可以检索所需数据并将其存储在合适的数据结构中。一个流行的选择是使用 pandas DataFrame,它提供了数据的表格表示,并提供了方便的数据操作和分析方法。

另一种解决方案是使用工作表对象的values属性。这为工作表中的所有值提供了一个生成器(类似于iter_rowsiter_cols分别对行和列做的那样)。虽然生成器不能直接用于访问数据,但它们可以在for循环中使用以遍历每个值。pandas库的DataFrame函数还允许直接从合适的生成器对象转换为DataFrame

从多个工作表中合并数据

在我们从每个工作表中读取数据时,我们可以根据需要将其存储在列表或字典中。一旦我们从所有工作表中检索到数据,我们就可以将其组合成一个单一的综合数据结构。这一步对于进一步的分析和处理至关重要。

为了合并数据,我们可以使用pandas DataFrame。通过为每个工作表的数据创建单独的DataFrame,然后将它们连接或合并成一个单一的DataFrame,我们可以获得一个包含多个工作表中所有信息的综合数据集。

读取多个工作表的自定义函数

为了简化读取多个工作表和合并数据的过程,我们可以创建针对特定需求的自定义函数。这些函数封装了必要的步骤,并允许我们高效地重用代码。

在我们的示例中,我们定义了一个名为read_multiple_sheets的函数,该函数接受文件路径作为输入。在函数内部,我们使用load_workbook加载工作簿,并遍历通过sheets属性检索到的工作表名称。

对于每个工作表,我们使用工作簿对象访问它,并使用自定义的read_single_sheet函数检索数据。然后我们将检索到的数据存储在列表中。最后,我们使用pandas的适当连接方法将所有工作表的数据合并成一个单一的pandas DataFrame`。

通过使用这些自定义函数,我们可以轻松地从 Excel 文件中读取多个工作表,并获取一个准备分析的综合数据集。该函数提供了一个可重用且高效的解决方案,节省了我们处理复杂 Excel 文件的时间和精力。

自定义代码

提供的示例是一个起点,你可以根据具体需求进行自定义。以下是自定义代码的一些考虑因素:

  • 使用iter_cols方法而不是values属性,并在for循环中使用过滤列表或通过过滤结果pandas DataFrame对象。

  • 处理缺失数据:如果工作表包含缺失数据,你可以采用适当的数据处理技术,例如填充缺失值或排除不完整行。

  • 应用转换:根据数据性质,你可能需要对综合数据集应用转换或计算。自定义函数可以扩展以适应这些转换。

记住,目标是使代码适应您独特的需求并确保它与数据处理要求保持一致。

通过利用openpyxl的力量并创建自定义函数,您可以高效地从 Excel 文件中读取多个工作表,合并数据,并为其进一步分析做好准备。这种能力使您能够从复杂的 Excel 文件中解锁有价值见解并发挥数据的全部潜力。

现在,让我们深入一个示例,演示这个过程:

from openpyxl import load_workbook
import pandas as pd
def read_single_sheet(workbook, sheet_name):
   # Load the sheet from the workbook
    sheet = workbook[sheet_name]
    # Read out the raaw data including headers
    sheet_data_raw = sheet.values
    # Separate the headers into a variable
    columns = next(sheet_data_raw)[0:]
    # Create a DataFrame based on the second and subsequent lines of data with the header as column names and return it
    return pd.DataFrame(sheet_data_raw, columns=columns)
def read_multiple_sheets(file_path):
    # Load the workbook
    workbook = load_workbook(file_path)
    # Get a list of all sheet names in the workbook
    sheet_names = workbook.sheetnames
    # Cycle through the sheet names, load the data for each and concatenate them into a single DataFrame
    return pd.concat([read_single_sheet(workbook=workbook, sheet_name=sheet_name) for sheet_name in sheet_names], ignore_index=True)
# Define the file path and sheet names
file_path = 'iris_data.xlsx' # adjust the path as needed
# Read the data from multiple sheets
consolidated_data = read_multiple_sheets(file_path)
# Display the consolidated data
print(consolidated_data.head())

让我们看看结果:

图 1.8 – 使用 openxlsx 包读取 Excel 文件

图 1.8 – 使用 openxlsx 包读取 Excel 文件

在前面的代码中,我们定义了两个函数:

  • read_single_sheet: 这将从单个工作表读取数据到pandas DataFrame

  • read_multiple_sheets: 这将读取并连接工作簿中所有工作表的数据

read_multiple_sheets函数中,我们使用load_workbook加载工作簿,并遍历工作表名称。对于每个工作表,我们使用read_single_sheet辅助函数检索数据,该函数从工作表读取数据并为每个工作表的数据创建一个pandas DataFrame,使用标题行作为列名。最后,我们使用pd.concat将所有DataFrame合并成一个单一的综合DataFrame

通过利用这些自定义函数,我们可以轻松地从 Excel 文件中读取多个工作表并获取一个综合数据集。这使我们能够对合并后的数据进行各种数据操作、分析或可视化。

理解如何高效地处理多个工作表增强了我们处理复杂 Excel 文件和从不同数据集中提取有价值见解的能力。

摘要

在本章中,我们探讨了将数据从 Excel 工作表导入到我们的编程环境中的过程。对于 R 用户,我们深入探讨了readxlxlsxopenxlsx等库的功能,提供了高效的数据提取和操作解决方案。我们还介绍了一个自定义函数read_excel_sheets,以简化从 Excel 文件中的多个工作表提取数据的过程。在 Python 方面,我们讨论了用于 Excel 操作的必要pandasopenpyxl包,并通过实际示例展示了它们的功能。到这一点,你应该对这些工具及其在高效 Excel 操作和数据分析方面的能力有了坚实的理解。

在下一章中,我们将学习如何将结果写入 Excel。

第二章:编写 Excel 工作表

这可能听起来与现代数据科学实践相矛盾,但 Excel 在分析和数据叙事的世界中仍有其位置。将数据从 R 和 Python 导出到 Excel 可以出于几个原因而有益,为用户提供利用两个平台优势的机会。Excel 是一个用户界面友好的广泛使用的电子表格程序,而 R 和 Python 是一种强大的统计编程语言。通过将数据从 R 和 Python 导出到 Excel,用户可以利用 Excel 熟悉且多功能的特性来进一步分析、可视化和共享数据。

将数据从 R 和 Python 导出到 Excel 的一大优势是能够利用 Excel 广泛的数据操作和可视化功能。Excel 提供了各种工具,如数据透视表、图表和条件格式化,这些工具使用户能够更互动和直观地探索和展示数据。这些功能允许快速的数据探索、识别趋势,并创建外观专业的报告或演示文稿。

此外,将数据导出到 Excel 可以方便与可能不熟悉 R 和 Python 或统计编程的同事或利益相关者进行协作。Excel 是一个被广泛认可且易于使用的工具,常用于各个行业的数据分析和报告。通过将数据导出到 Excel,用户可以与他人共享数据,这些人可能更愿意使用电子表格,从而实现更便捷的协作和知识交流。

另一个将数据从 R 和 Python 导出到 Excel 的原因是利用 Excel 广泛的插件和扩展生态系统。Excel 提供了众多专业工具和插件,可以增强数据分析,如 Power Query、Power Pivot 和 Solver。这些工具提供了数据清理、高级计算和优化的额外功能,这些功能在 R 和 Python 中可能不太容易获得或不够用户友好。将数据导出到 Excel 允许用户利用这些工具并从更广泛的 Excel 生态系统中受益。

总结来说,将数据从 R 和 Python 导出到 Excel 允许您利用 Excel 的用户友好界面、强大的数据操作和可视化能力,以及与广泛用户的兼容性。通过结合 R 和 Excel 的优势,个人可以增强他们的数据分析工作流程,提高协作,并有效地传达从统计分析中得出的见解。

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

  • 可写入 Excel 工作表的包

  • 使用 Python 创建和操作 Excel 工作表

  • 保持简单 —— 使用 pandas 将数据导出到 Excel

  • 高级模式 —— 使用 openpyxl 操作 Excel

  • openpyxlpandas 之间进行选择

  • 其他替代方案

技术要求

在本章中,我们将使用内置的 Iris 数据集。这是一个用于演示的好数据集。

本章的代码可以在本书的 GitHub 仓库中找到:github.com/PacktPublishing/Extending-Excel-with-Python-and-R/tree/main/Chapter2

写入 Excel 文件的包

在本节中,我们将介绍几个不同的库,我们可以使用这些库将data.frames/tibbles写入 Excel 文件。我们将使用writexlopenxlsxxlsx库。

在下一节中,我们将列出每个包,指定您可以在哪里找到写入 Excel 数据的功能文档,并介绍函数的参数。

writexl

writexl包是 rOpenSci 联盟的一部分,可以在docs.ropensci.org/writexl/reference/write_xlsx.html找到。

该库不需要 Java 或 Excel 即可工作。

将数据写入 Excel 的函数是write_xlsx()。让我们来看看函数的不同参数,并查看一个完整的伪函数调用。

首先,让我们看看函数调用本身——即write_xlsx()

write_xlsx(
  x,
  path = tempfile(fileext = ".xlsx"),
  col_names = TRUE,
  format_headers = TRUE,
  use_zip64 = FALSE
)

现在,让我们来看看这段代码中的每个参数:

  • x:这是将成为.xlsx文件工作表的 DataFrame 或命名 DataFrame 列表。

  • path:要写入的文件名。在这里,您可以输入类似于tempfile(fileext = ".xlsx")的内容,以在文件顶部写入列名。

  • format_headers:使.xlsx文件中的col_names居中并加粗。

  • use_zip64:使用.xlsx文件。并非所有平台都能读取此文件。

让我们看看这个函数在典型实践中的简单示例会是什么样子:

write_xlsx(list(mysheet = iris), path = "./iris_data_written.xlsx")

openxlsx

openxlsx包可以在ycphs.github.io/openxlsx/找到;我们将使用write.xlsx()函数写入 Excel 文件。同样,我们将介绍完整的函数调用以及传递给此函数的参数:

write.xlsx(
  x,
  file,
  asTable = FALSE,
  overwrite = TRUE,
  …
)

现在,让我们过一遍函数的所有参数:

  • x:一个 DataFrame 或可以由writeData()writeDataTable()处理的(命名)对象列表,用于写入文件。

  • file:保存.xlsx文件的文件路径。

  • asTable:如果为TRUE,则将使用writeDataTable()而不是writeData()x写入文件(默认值为FALSE)。

  • overwrite:覆盖现有文件(默认为TRUE,与write.table相同)。

  • ...:传递给buildWorkbook()函数的附加参数。要查看更多详细信息,您可以在 R 控制台中输入?openxlsx::buildWorkbook

让我们看看一段简短的代码示例,我们将使用它将 Iris 数据集写入文件:

openxlsx::write.xlsx(
x = iris,
File = paste0(getwd(), "/iris.xlsx"
)

接下来,我们将查看最后一个包,xlsx

xlsx

可以在github.com/colearendt/xlsx找到xlsx包;我们用来探索写入 Excel 文件的函数是write.xlsx()。鉴于这个函数与openxlsx库中的函数同名,了解命名空间冲突是很重要的。这种情况发生在有两个或更多独立包中的函数具有相同名称时。避免用户出现任何可能的命名空间冲突很容易,但可能会有些繁琐。为此,你可以写xlsx::write.xlsx()。再次强调,让我们回顾一下完整的函数调用以及传递给此函数的参数:

write.xlsx(
  x,
  file,
  sheetName = "Sheet1",
  col.names = TRUE,
  row.names = TRUE,
  append = FALSE,
  showNA = TRUE,
  password = NULL
)

现在,让我们回顾一下函数的参数:

  • x: 要写入工作簿的 DataFrame。

  • file: 输出文件的路径。

  • sheetName: 包含工作表名称的字符字符串。

  • col.names: 一个逻辑值,指示是否将x的列名与x一起写入文件。

  • row.names: 一个逻辑值,指示是否将x的行名与x一起写入文件。

  • append: 一个逻辑值,指示是否将x附加到现有文件。如果为TRUE,则从磁盘读取文件。否则,创建文件。

  • showNA: 一个逻辑值。如果设置为FALSENA值将保留为空单元格。

  • password: 包含密码的字符串。

一个简单的函数调用将采取以下形式:

xlsx::write.xlsx(x = iris,
File = paste0(getwd(), "/iris.xlsx"
)

现在我们已经讨论了三个不同的函数,重要的是要看到每个函数是如何写入的——也就是说,它们写入磁盘所需的时间以及输出文件的大小。为此,我们将使用rbenchmark库进行速度测试。我们还将引入dplyr库,按速度的相对顺序排列结果。之后,我们将看到哪个文件具有最小的输出大小。

这里是完成这个任务的代码:

图 2.1 – 文件写入基准测试

图 2.1 – 文件写入基准测试

这段 R 代码用于比较将 DataFrame 写入 Excel 文件的三个不同包的性能:writexlopenxlsxxlsx。以下是代码的分解:

  1. 代码首先使用library()函数加载几个库(rbenchmarkxlsxwritexlopenxlsxdplyr)。这些库提供了将在代码中稍后使用的函数。如果你没有安装它们,你需要使用类似install.packages("package")的命令来安装。

  2. n变量被赋予值为5。这个变量代表代码将为每个包执行多少次以衡量性能。

  3. 调用benchmark()函数来比较三个 Excel 写入包的性能。它接受几个参数:

    • 第一个参数 writexl 是分配给第一个测试的名称。在大括号内,调用 writexl 包中的 write_xlsx() 函数将 iris 数据集写入临时 Excel 文件。

    • 第二个参数 openxlsx 是分配给第二个测试的名称。在大括号内,调用 openxlsx 包中的 write.xlsx() 函数将 iris 数据集写入临时 Excel 文件。

    • 第三个参数 xlsx 是分配给第三个测试的名称。在大括号内,调用 xlsx 包中的 write.xlsx() 函数将 iris 数据集写入具有 .xlsx 扩展名的临时 Excel 文件。

    • replications 参数设置为 n,表示每个测试应该重复的次数。

    • columns 参数指定要在输出中包含的列。它包括测试名称、任何重复项、经过的时间、相对性能、用户时间和系统时间。

  4. 然后将生成的基准测试结果通过管道(|>)传递到 dplyr 包的 arrange() 函数。arrange() 函数用于根据相对性能列对结果进行排序,按升序排列。

    对于前面的基准测试过程,结果如下:

      test      replications elapsed relative  user.self  sys.self
    1 writexl      5     0.03   1.000      0.01        0.00
    2 openxlsx     5     0.32   10.667     0.01        0.00
    3 xlsx         5     0.88   29.333     0.81      0.01
    

    总结来说,前面的代码加载必要的库,对三个不同的 Excel 写入包(writexlopenxlsxxlsx)进行基准测试,并根据相对性能对结果进行排序。目的是比较这些包在将 iris 数据集写入 Excel 文件时的效率。需要注意的是,这里有许多因素在起作用,例如系统和操作系统等。现在,让我们看看文件大小如何:

图 2.2 – 文件大小比较

图 2.2 – 文件大小比较

这段 R 代码使用不同的包将 iris 数据集写入 Excel 文件,然后检索这些文件的大小(以字节为单位):

  • writexl 包中的 write_xlsx() 函数使用两个参数:iris 数据集和由 tempfile() 函数生成的临时文件路径。write_xlsx() 函数将 iris 数据集写入临时 Excel 文件。

  • file.info() 函数使用临时文件路径 (tmp1) 作为参数被调用。它检索有关文件的信息,包括其大小。使用 $size 属性来提取文件的大小。

  • openxlsx 包中的 write.xlsx() 函数使用两个参数:iris 数据集和由 tempfile() 函数生成的另一个临时文件路径。write.xlsx() 函数将 iris 数据集写入临时 Excel 文件。

  • 第二点类似,file.info() 函数使用临时文件路径 (tmp2) 作为参数来检索文件的大小。

  • 来自xlsx包的write.xlsx()函数使用两个参数调用:iris数据集和由tempfile()paste0()函数组合生成的临时文件路径。write.xlsx()函数将iris数据集写入具有.xlsx扩展名的临时 Excel 文件。对于xlsx包,我们使用paste0()并指定文件扩展名,因为这不是函数的默认行为,所以用户必须小心并相应地指定这一点。

  • 再次,file.info()函数使用临时文件路径(tmp3)作为参数来检索文件大小。

总结来说,这段代码使用不同的包(writexlopenxlsxxlsx)将iris数据集写入三个单独的 Excel 文件。然后,它使用file.info()函数检索这些文件的大小。其目的是比较使用这些不同包生成的 Excel 文件的大小。再次强调,许多超出本书范围的因素可能会影响文件大小,但你必须意识到不同的系统和配置可能会对此产生影响。

一个全面的总结和洞察

在上一节中,我们学习了如何使用三个不同的包(data.tabledplyrtidyr)将data.frame写入 Excel。我们了解到,这三个不同的包在文件写入速度和输出文件本身的大小上存在差异。运行这些基准测试很重要,因为我们可能试图实现速度、小文件大小或两者的组合。

当谈到速度时,有几个原因说明为什么在 R 中运行基准测试是好的:

  • 准确性:基准测试可以用来准确测量不同函数的速度。这很重要,因为它可以帮助你选择最适合你任务的函数。

  • 一致性:基准测试可以用来在一段时间内一致地测量不同函数的速度。这很重要,因为它可以帮助你识别任何可能发生的性能变化。

  • 可靠性:基准测试可以用来在不同平台上可靠地测量不同函数的速度。这很重要,因为它可以帮助你确保基准测试的结果是准确和可重复的。

除了这些优点之外,基准测试还可以用来识别代码中的瓶颈。这可以帮助你提高代码的性能,因为你可以在执行时间最长的区域进行优化。

这里有一些最受欢迎的 R 基准测试包:

  • microbenchmark:这个包提供了一个简单方便的方式来基准测试 R 代码

  • rbenchmark:这个包提供了比microbenchmark更全面的基准测试功能

  • rbenchmark2:这个包是rbenchmark的分支,提供了额外的功能,例如能够基准测试多个核心

在选择基准测试包时,考虑你的需求和可用功能非常重要。例如,如果你需要基准测试大量代码,你可能希望选择支持 并行基准测试 的包。

一旦你选择了基准测试包,你就可以用它来比较不同函数的速度。为此,你需要创建一个包含你想要比较的函数的基准测试对象。然后你可以使用 benchmark 对象来运行这些函数并测量它们的执行时间。

基准测试的结果可以用来确定适合你任务的最高效函数。然后你可以利用这些信息来提升你代码的性能。

在本节中,我们不仅学习了如何将数据写入 Excel 文件,还学习了如何使用不同的 R 库来完成这一任务。这很重要,因为它帮助你探索实现同一目标的不同方法。这项练习还展示了实现方式之间的差异,我们通过检查输出文件大小以及通过基准测试每个包将数据写入 Excel 所需的时间来观察到这些差异。接下来,我们将使用 Python 进行类似的练习。

使用 Python 创建和操作 Excel 表格

在本节中,我们将探讨如何使用 Python 创建和操作 Excel 表格。

在各种数据分析和报告场景中,将数据导出到 Excel 是一个常见需求。Excel 提供了一个熟悉且广泛使用的界面,用于数据可视化、共享和进一步分析。

在接下来的章节中,我们将涵盖各种任务,包括创建新工作簿、向现有工作簿添加工作表、删除工作表以及在 Excel 工作簿中操作数据。Python 提供了几个库,使这些任务变得简单高效。但首先,让我们了解为什么我们需要将数据导出到 Excel。

为什么要将数据导出到 Excel?

将数据导出到 Excel 提供了几个好处。首先,Excel 提供了一个用户友好的环境,用于数据探索和可视化,使用户能够轻松地对数据进行排序、筛选和分析。此外,Excel 丰富的格式化功能使其适合生成专业报告或与可能没有编程知识的利益相关者共享数据。此外,Excel 支持各种公式和函数,使用户能够轻松地对导出的数据进行计算。

让我们看看如何使用 Python 将数据导出到 Excel!

保持简单——使用 pandas 将数据导出到 Excel

pandas 是 Python 中一个流行的数据处理库,它提供了强大的数据分析工具,同时也提供了将数据导出到 Excel 的出色功能。使用 pandas,你可以轻松地将你的数据转换成 Excel 表格或工作簿。

pandas 提供了 DataFrame.to_excel() 方法,允许你仅用几行代码就将数据导出到 Excel 文件。以下是一个示例:

import pandas as pd
# Create a DataFrame with sample data
data = {
    'Name': ['John', 'Jane', 'Mike'],
    'Age': [25, 30, 35],
    'City': ['New York', 'London', 'Sydney']
}
df = pd.DataFrame(data)
# Export the DataFrame to an Excel file
df.to_excel('data.xlsx', index=False)

代码不返回任何内容,但它确实有一个副作用 – 它创建了包含导出数据的 data.xlsx 文件:

图 2.3 – 使用 pandas 导出 Excel

图 2.3 – 使用 pandas 导出 Excel

虽然 pandas 在简单的数据导出方面做得很好,但我们可能希望对 Excel 工作簿有更多的控制。接下来的几个小节将涵盖使用 openpyxl 的更高级 Excel 操作。我们将从创建和删除工作表等基础知识开始,包括在现有工作表中操作数据。

高级模式 – 使用 openpyxl 操作 Excel

在本节中,我们将探讨 openpyxl 包,它允许在写入数据时与 Excel 进行更细致的交互。

创建新工作簿

要在 Python 中开始处理 Excel 工作表,我们需要创建一个新的工作簿。openpyxl 提供了一个直观的 API 来创建、修改和保存 Excel 工作簿。以下是一个示例代码片段,演示了如何创建一个新的工作簿:

import openpyxl
# Create a new workbook
workbook = openpyxl.Workbook()

再次强调,前面的代码片段不返回任何内容,但它确实有一个副作用 – 它创建了工作簿:

图 2.4 – 使用 openpyxl 创建工作簿

图 2.4 – 使用 openpyxl 创建工作簿

向工作簿中添加工作表

一旦我们有了工作簿,我们就可以向其中添加工作表。添加工作表使我们能够将数据组织到单独的分区或类别中。openpyxl 提供了一个简单的方法 create_sheet(),用于向工作簿中添加工作表。让我们看看一个示例:

import openpyxl
# Create a new workbook
workbook = openpyxl.Workbook()
# Add a new sheet
workbook.create_sheet(title="Sheet2")
# Save the changes
workbook.save("example.xlsx")

结果是一个我们可以继续使用的 openpyxl 工作表对象。然后可以将结果工作簿保存以供将来使用。

前面的示例尝试保存您正在处理的工作簿。如果工作簿在 Excel 中打开,尝试将失败,并显示一个难以理解的关于 COM 系统的错误消息。在尝试从 Python 端保存工作之前,请确保关闭 Excel 实例!这个警告将适用于本书的大部分内容,所以请记住在后面的章节中也要注意。

删除工作表

有时,我们可能需要从工作簿中删除一个工作表。openpyxl 中的 remove() 方法允许我们通过名称删除工作表。以下是如何从工作簿中删除工作表的示例。请注意,我们不会保存结果,因此文件存储的版本保持不变:

import openpyxl
# Load an existing workbook
workbook = openpyxl.load_workbook("example.xlsx")
# Delete a sheet
sheet_name = "Sheet2"
sheet = workbook[sheet_name]
workbook.remove(sheet)

与之前一样,代码有一个副作用(被删除的工作表)但没有返回值:

图 2.5 – 使用 openpyxl 删除工作表

图 2.5 – 使用 openpyxl 删除工作表

在本例中,我们使用了之前创建的工作表。使用 openpyxlload_workbook() 方法来加载现有工作簿,之后使用 remove() 方法删除指定名称的工作表。

操作现有工作簿

Python 库如 openpyxl 提供了强大的方法来操作现有的 Excel 工作簿。我们可以修改单元格、应用格式、插入公式等。让我们看看如何更新现有工作簿中单元格值的示例:

import openpyxl
# Load an existing workbook
workbook = openpyxl.load_workbook("example.xlsx")
# Add a new sheet
workbook.create_sheet(title="Sheet1")
# Select a sheet
sheet_name = "Sheet1"
sheet = workbook[sheet_name]
# Update a cell value
sheet["A1"] = "Hello, World!"
# Save the changes
workbook.save("example.xlsx")

这段代码将直接更改 Excel 表格中单元格的值:

图 2.6 – 使用 openpyxl 更新单元格的值

图 2.6 – 使用 openpyxl 更新单元格的值

结果正如我们所预期(请注意,删除工作表的过程没有被保存):

图 2.7 – 我们努力的成果 – A1 单元格中的 Hello, World! 在 Sheet1 表格中

图 2.7 – 我们努力的成果 – A1 单元格中的 Hello, World! 在 Sheet1 表格中

选择 openpyxl 和 pandas

当涉及到将数据导出到 Excel 时,openpyxlpandas 都是极佳的选择。openpyxl 是一个专门用于处理 Excel 文件的库,因为它提供了创建、修改和保存 Excel 工作簿的广泛功能。另一方面,pandas 提供了一个高级数据操作接口,并提供了方便的方法将数据导出到 Excel,这在只需要简单的数据导出时非常理想。

如果您需要精细控制 Excel 文件的结构,例如添加格式、公式或图表,openpyxl 是一个合适的选择。它允许您直接与底层的 Excel 对象工作,提供更多灵活性。另一方面,如果您主要关注数据操作,并希望以更简单的方式将 DataFrame 导出到 Excel 而不必担心 Excel 特定功能,pandas 是一个方便的选择。它抽象了一些底层细节,并为导出数据提供了一个更直接的接口。虽然 openpyxl 提供了一种简单的抽象方式来操作和控制工作表,R 语言也有类似的功能,例如在 openxlsxxlsx 等包中,它们都提供了自己形式的这些功能。

其他替代方案

除了 pandasopenpyxl 之外,还有其他库可以从 Python 将数据导出到 Excel。一些流行的替代方案包括 XlsxWriterxlrdxlwt。这些库提供了不同的功能和能力,选择取决于您的具体需求。例如,XlsxWriter 强调性能并支持高级 Excel 功能,而 xlrdxlwt 提供了读取和写入旧版 Excel 文件格式(.xls)的功能。

在本节中,我们探讨了将数据导出到 Excel 的好处,展示了如何使用 pandas 来实现这一操作,介绍了使用 openpyxl 创建和操作 Excel 表格的过程,讨论了根据您的需求选择 openpyxlpandas 的原因,并提到了其他可用的替代方案。通过利用这些库的强大功能,您可以从 Python 无缝地将数据导出到 Excel,从而实现高效的分析、报告和协作。

摘要

第二章,我们探讨了使用不同的 R 和 Python 库将数据写入 Excel 的过程,并对它们的性能进行了基准测试。我们还讨论了使用 pandasopenpyxl 从 Python 创建和操作 Excel 工作表。通过比较它们的特性和探索替代方案,你已对 R 和 Python 在 Excel 任务方面的能力有了深入了解。

在下一章中,我们将学习如何使用 R 和 Python 执行 VBA 代码。

第三章:在 R 和 Python 中执行 VBA 代码

集成不同的编程语言可以解锁强大的功能并简化工作流程。当涉及到处理 Excel 文件时,Visual Basic for Applications (VBA) 是自动化任务的一个流行选择。然而,在某些情况下,您可能希望从 R 或 Python 中执行 VBA 代码,利用这些语言在数据处理、分析和可视化方面的优势。

通过 R 或 Python 从 Excel 文件中执行 VBA 代码提供了一种灵活的方法来利用现有的 VBA 宏或扩展 Excel 的功能。这种集成使数据科学家、分析师和开发者能够无缝地将 Excel 文件纳入其工作流程,结合 VBA 的优势与 R 或 Python 的分析能力。

通过从 R 或 Python 中执行 VBA 代码,您可以自动化复杂的过程,执行数据处理,生成报告,并以编程方式与 Excel 的功能交互。这种能力使用户能够处理大型数据集,实施高级数据处理技术,并生成定制化的输出。

R 和 Python 中有几种库和包可用于从 Excel 文件中执行 VBA 代码。这些工具提供 API 和函数,用于与 Excel 通信并直接从您的脚本中执行 VBA 宏,从而消除手动干预的需要。

在本章中,我们将探讨从 Excel 文件中执行 VBA 代码的不同方法,使用 R 和 Python。我们将深入实际示例,展示如何将这些语言与 Excel 集成,并利用其结合的力量来自动化任务并增强数据分析工作流程。

通过结合 R 或 Python 中的 VBA 执行功能,用户可以将基于 Excel 的项目提升到新的水平,提高效率、准确性和生产力。请继续关注,了解更多关于这个激动人心的集成及其广泛应用的详细信息。

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

  • 安装并解释 R 包,RDCOMClient

  • 使用 RDCOMClient 执行示例 VBA 代码

  • 使用 pywin32 进行 VBA 集成的 Python

技术要求

在本节中,我们需要安装一个 R 库和一个 Python 库:

  • RDCOMClient R 库

  • Python 的 pywin32

本章中所有相关的代码都可以在以下 GitHub 仓库中找到:

github.com/PacktPublishing/Extending-Excel-with-Python-and-R/main/chapter3

安装并解释 RDCOMClient R 库

RDCOMClient 是一个 R 包,它为 R 和微软的 组件对象模型 (COM) 架构之间提供了一个桥梁,使用户能够在 R 中与 COM 对象交互。通过 RDCOMClient,用户可以利用基于 COM 的应用程序(如 Microsoft Excel、Word、PowerPoint 和 Outlook)的力量来自动化任务、操作数据并将 R 与其他软件系统集成。

在深入了解 RDCOMClient 之前,理解 COM 对象的概念非常重要。COM 是一种二进制接口标准,允许不同的软件组件在多种编程语言和平台上相互交互并共享功能。在 RDCOMClient 的上下文中,COM 对象是指由基于 COM 的应用程序公开的应用特定对象,这些对象可以通过编程方式访问和操作。

RDCOMClient 提供了一套函数和方法来与 COM 对象交互,使自动化任务和从基于 COM 的应用程序中提取数据变得更加容易。以下是一些关键特性:

  • RDCOMClient 允许用户创建和连接到 COM 对象,在 R 和目标应用程序之间建立通信通道。例如,您可以从 R 中直接创建 Excel 应用程序对象并访问其功能。

  • RDCOMClient 允许您调用方法和检索或修改对象属性。这种功能使您能够自动化复杂任务,操作数据并自定义应用程序行为。

  • RDCOMClient 允许访问 COM 对象中的集合,例如 Excel 中的工作簿、工作表或范围。这种能力使您能够直接从 R 中提取、操作和分析数据,利用 Excel 内置功能的强大功能。

  • RDCOMClient 支持事件处理,使用户能够对 COM 对象触发的事件做出响应。例如,您可以编写 R 代码,以便在 Excel 中发生特定事件(如单元格值更改或工作表激活)时执行。

  • RDCOMClient 提供了处理 COM 对象交互过程中可能出现的错误机制,确保代码的健壮性。它还管理内存分配和清理,防止内存泄漏并优化资源利用。

RDCOMClient 的多功能性为各种应用打开了广泛的可能性。以下是一些示例:

  • RDCOMClient 允许用户在 Excel 中自动化重复性任务,例如数据提取、格式化、图表创建和报告生成。这可以显著提高数据分析工作流程中的生产力和准确性。

  • RDCOMClient,您可以通过编程方式创建、修改和从 Word 文档中提取内容,从而实现自动化文档生成、格式化和数据集成。

  • RDCOMClient 促进与 Outlook 的集成,使用户能够自动化电子邮件管理、日历安排和联系人同步等功能。

  • 使用 RDCOMClient 动态创建和修改 PowerPoint 演示文稿,自动化生成幻灯片、格式化以及根据数据分析结果嵌入图表或表格。

RDCOMClient 作为将 R 与基于 COM 的应用程序集成的强大工具,提供了自动化、数据处理和系统集成的大量功能。通过弥合 R 和 COM 架构之间的差距,RDCOMClient 使用户能够利用 R 和各种 COM 应用程序的优势,为提高生产力、数据分析和工作自动化开辟无限可能。

既然我们已经讨论了我们可以使用 RDCOMClient 做什么,那么让我们来了解一下安装过程。

安装 RDCOMClient

要在 R 中安装包,你通常会在命令提示符中输入类似 install.packages("dplyr") 的命令来安装 dplyr 库。

对于 RDCOMClient 库,这会有一些变化。通常情况下,如果你使用 RStudio——你获取包的默认仓库——它将默认使用全局(CDN)RStudio 仓库,但针对这个包,我们将为安装命令提供一些特殊指令。

注意

RDCOMClient 仅在 Windows 系统上可用。

下面是命令的显示方式:

install.packages(
"RDCOMClient",
repos = "http://www.omegahat.net/R",
type = "win.binary"
)

现在我们已经安装了 RDCOMClient,我们可以继续使用它做一些事情。在下一节中,我们将介绍如何使用它的几个示例。这个库的安装可能会有些繁琐,对于一些人来说,以下方法可能更有效:

Install.packages("devtools")
Library(devtools)
Install_github("omegahat/RDCOMClient")

执行带有 RDCOMClient 的示例 VBA

对于这次执行,我们首先需要一个新的工作簿。让我们称它为 mult_by_rand_ch3

Record 和其他名为 Value 的列上。这些列将简单地是数字 1 到 10。完成这个步骤后,我们需要继续创建一个简单的 VBA 脚本来从 RDCOMClient 库中执行。

我们将编写一个宏,该宏将获取 Value 列,然后使用 RAND() 函数将数字乘以一个随机数。

让我们回顾一下创建宏的步骤,并描述它是如何工作的。首先,看一下以下 VBA 代码:

Sub MultiplyByRandom()
    Dim rng As Range
    Dim cell As Range
    ' Set the range to the desired range on Sheet1
    Set rng = Sheets("Sheet1").Range("B2:B11")
    ' Loop through each cell in the range
    For Each cell In rng
        ' Multiply the cell value by RAND() and store the result in the adjacent cell
        cell.Offset(0, 1).Value = cell.Value * Rnd()
    Next cell
End Sub

为了创建这个宏,你需要点击 开发者 选项卡或按 Alt + F11 打开 Visual Basic 编辑器。

通过访问 插入 | 模块 来插入一个新模块。完成此操作后,您可以将前面的代码输入到窗口中,然后关闭编辑器窗口。

为了获得一些清晰度,让我们回顾一下宏的每一行都做了什么:

  • Sub MultiplyByRandom(): 这行定义了一个名为 MultiplyByRandom 的 VBA 子程序的开始。

  • Dim rng As RangeDim cell As Range:这些行声明了两个名为 rngcellRange 变量。这些变量将分别用于存储范围和单个单元格。

  • Set rng = Sheets("Sheet1").Range("B2:B11"): 这行将 rng 变量设置为指向 Sheet1 上从 B2 到 B11 的单元格范围。它指定了存储数字的位置。

  • For Each cell In rng:这一行启动一个循环,该循环将遍历rng范围内的每个单元格。它将当前单元格分配给cell变量,每次循环迭代一次。

  • cell.Offset(0, 1).Value = cell.Value * Rnd():这一行使用Rnd()函数将当前单元格的值乘以一个随机生成的数字。然后将结果存储在相邻的单元格中,该单元格是通过使用Offset方法将引用向右移动一列(0行,1列)获得的。

  • Next cell:这一行表示循环的结束。它将循环移动到范围内的下一个单元格并重复该过程,直到处理完所有单元格。

  • End Sub:这一行标志着MultiplyByRandom VBA 子程序的结束。

为了运行这个宏,我们可以编写将执行它的 R 代码。我们将使用RDCOMClient库,并使用我们创建的 Excel Workbook对象中的$Run()方法来完成这项工作。

让我们继续编写这个脚本。

以下是对 R 代码中每一行的简单解释。

这一行加载了RDCOMClient库,该库提供了与 Microsoft Office 应用程序(如 Excel)交互的功能:

# Load the library
library(RDCOMClient)

以下几行定义了 Excel 工作簿的文件路径和名称变量。它们仅适用于作者,并且应更新以反映您的工作位置。您可能在项目中工作并使用类似paste0(getwd(), "/")的东西。f_pathf_chapterf_name变量分别指定目录路径、子目录名称和文件名。paste0()函数用于将这些变量连接起来以创建完整的文件路径:

# Set file path
f_path <- "C:/Users/steve/Documents/GitHub/Extending-Excel-with-Python-and-R/"
f_chapter <- "chapter3/"
f_name <- "mult_by_rand_ch3.xlsm"
f <- paste0(f_path, f_chapter, f_name)

接下来的几行使用COMCreate()函数创建 Excel 应用程序的一个实例。xl_app变量代表 Excel 应用程序。然后,使用 Excel 应用程序的Workbooks()属性的Open()方法打开指定的工作簿(f)。最后,xl_app[['Visible']] <- TRUE将 Excel 应用程序的可见性设置为可见:

# Make Excel App
xl_app <- COMCreate("Excel.Application")
xl_wkbk <- xl_app$Workbooks()$Open(f)
xl_app[['Visible']] <- TRUE

这一行将要在 Excel 中执行的宏的名称分配给macro_name变量。宏名称设置为MultiplyByRandom

macro_name <- "MultiplyByRandom"

这一行在 Excel 应用程序中执行MultiplyByRandom宏。使用 Excel 应用程序的Run()方法运行指定的宏:

# Run the macro
xl_app$Run(macro_name)

这些行使用xl_wkbk工作簿对象的close()方法保存工作簿并关闭它。TRUE参数表示在关闭之前应保存更改。最后,使用xl_app Excel 应用程序的Quit()方法关闭 Excel 应用程序:

# Save and Quit
xl_wkbk$close(TRUE); xl_app$Quit()

总结来说,代码使用RDCOMClient打开一个 Excel 工作簿,运行名为MultiplyByRandom的宏,保存更改,然后关闭工作簿和 Excel 应用程序。

让我们看看这是如何在 Python 中工作的!

使用 pywin32 将 VBA 与 Python 集成

在本节中,我们将深入探讨从 Python 执行 VBA 代码,探索两种语言之间的无缝集成以及它为自动化 Excel 任务、扩展功能和在 Python 工作流程中利用 Excel 的力量所开启的无限可能性。

本节将涵盖从 Python 使用 VBA 的动机、如何在 Windows 上设置环境以及如何编写和执行 VBA 代码。让我们深入探讨。

为什么要从 Python 执行 VBA 代码?

在深入细节之前,让我们探讨为什么从 Python 执行 VBA 代码可以非常有益。

Excel,凭借其广泛的功能和特性,是数据分析、报告和自动化的关键工具。然而,当处理复杂的数据操作或高级计算时,Excel 的内置功能有时可能不足。这就是 Python 和 VBA 集成发挥作用的地方。

Python 为数据处理、分析和机器学习提供了一个丰富的生态系统。其库,如 pandasNumPySciPy,提供了强大的数据处理、统计分析建模工具。通过利用 Python 的灵活性和丰富的库,您可以增强 Excel 的功能,轻松应对复杂的数据分析任务。

通过将 Python 与 VBA 集成,您可以利用两种语言的优势。Python 提供了一个强大且灵活的数据分析环境,而 VBA 在自动化特定于 Excel 的任务和访问高级 Excel 功能方面表现出色。这种协同作用允许您使用 Python 的丰富库扩展 Excel 的功能,高效地处理大型数据集,并无缝地进行复杂计算和数据转换。

从 Python 执行 VBA 代码的好处不仅限于数据分析。您可以利用 Python 更广泛的生态系统来处理网络抓取、文本处理、机器学习和与外部 API 集成等任务。通过结合 Python 的多功能性和 VBA 的特定于 Excel 的功能,您可以创建超越 Excel 单独限制的动态和高效的工作流程。

此外,将 Python 和 VBA 集成开辟了协作和代码共享的机会。Python 在数据科学家、分析师和开发者中的流行确保了一个庞大的社区和丰富的共享知识。通过通过 VBA 将 Python 与 Excel 集成,您可以弥合这两个世界之间的差距,使数据分析师、开发人员和 Excel 高级用户能够协作并从彼此的专业知识中受益。

总结来说,从 Python 执行 VBA 代码使您能够做到以下事项:

  • 利用 Python 丰富的库和工具进行数据分析和操作

  • 使用 VBA 自动化重复性任务并构建自定义 Excel 应用程序

  • 使用 Python 强大的生态系统进行复杂计算、数据处理和统计分析

  • 利用 Python 的多功能性和访问外部数据源和 API 来扩展 Excel 的功能

  • 在 Python 数据分析师、开发人员和 Excel 高级用户之间协作和共享代码

Python 和 VBA 的集成使您能够释放 Excel 的全部潜力,利用两种语言的优势,并将您的数据分析、报告和自动化技能提升到新的高度。

让我们继续设置从 Python 执行 VBA 代码的环境。

设置环境

要成功从 Python 执行 VBA 代码,我们需要通过安装所需的依赖项和配置必要的连接来设置环境。本节将指导您通过三个简单步骤确保设置过程的顺利。

安装 pywin32 库

pywin32 库作为 Python 和 Windows API 以及 COM 对象之间的桥梁。它使 Python 能够与 Excel 的对象模型交互并执行 VBA 代码。

要安装 pywin32,您可以使用包管理器,如 pip,在您的命令提示符或终端中运行以下命令:

python –m pip install pywin32==306

这是它的运行方式:

图 3.1 – 使用 pip 在 Windows 上安装 pywin32

图 3.1 – 使用 pip 在 Windows 上安装 pywin32

这将安装 pywin32 包及其依赖项,使 Python 能够与 Excel 通信。

建立与 Excel 的连接

一旦安装了 pywin32,我们就可以从 Python 建立与 Excel 的连接。此连接使我们能够以编程方式访问 Excel 的工作簿、工作表、范围和其他 Excel 特定功能。

要建立连接,我们可以利用 pywin32 提供的 win32com.client 模块。以下是如何创建与 Excel 连接的示例:

import win32com.client as win32
excel_app = win32.Dispatch("Excel.Application")

如果环境设置正确,此代码将返回空值。然而,如果代码返回 com_error,请转到“环境设置错误处理”部分。

图 3.2 – 测试与 Excel 的连接

图 3.2 – 测试与 Excel 的连接

在前面的代码片段中,我们导入了 win32com.client 模块,并使用 win32.Dispatch 方法创建了一个新的 Excel 应用程序实例。这创建了 Python 和 Excel 之间的连接,使我们能够与 Excel 的对象交互并执行 VBA 代码。

创建与 VBA 代码交互的界面

连接建立后,我们可以创建一个界面,使我们能够从 Python 执行 VBA 代码。此界面作为 Python 和 VBA 之间的桥梁,使我们能够发送命令、调用 VBA 函数和访问 VBA 宏。要创建一个界面,我们可以使用前一步骤中获得的 excel_app 对象:

vba_interface = excel_app.VBE

您可能会收到类似“程序访问 Visual Basic 项目不受信任”的错误。在这种情况下,您可以在 stackoverflow.com/questions/17033526/programmatic-access-to-visual-basic-project-is-not-trusted-from-iis 查找解决方案。

在前面的代码中,我们访问了 excel_app 对象。这使我们能够访问 VBA 的功能,包括执行 VBA 代码、操作模块以及从 Python 与 Excel 的对象交互。

通过遵循这些步骤,我们可以无缝地设置环境以执行 VBA 代码。pywin32 库的安装和与 Excel 的连接建立为执行 VBA 代码和利用 Excel 功能的基础。在接下来的章节中,我们将更深入地探讨执行 VBA 代码、与 Excel 对象交互以及探索将 Python 和 VBA 集成的各种用例。

环境设置中的错误处理

最后一条代码可能会给你显示“项目不受信任”的错误。正如错误提示的那样,这是因为你的 Excel 安全设置中 VBA 不受信任。要程序化访问 VBA,你需要更改安全设置。

注意

这超出了本书的范围,因此只有在你接受风险的情况下才更改设置。

要更改安全设置,你需要创建一个新的注册表键并向其中添加一个新的属性,方法是作为管理员运行 PowerShell。运行以下代码:

 New-Item -path HKLM:\Software\Microsoft\Office\16.0\Excel\ -Name "Security"
Set-ItemProperty -path HKLM:\Software\Microsoft\Office\16.0\Excel\Security -Name "AccessVBOM" -Value 1
'''

然后,重新运行 Python 代码以测试环境是否正确设置。

现在我们已经设置了环境,让我们继续从 Python 执行 VBA 代码并探索它提供的可能性。

编写和执行 VBA 代码

一旦环境设置完成,我们就可以深入到从 Python 编写和执行 VBA 代码的过程。本节将介绍与 Excel 交互、运行 VBA 宏以及将结果检索回 Python 的不同方法和技巧。

让我们探索编写和执行 VBA 代码的一些关键方面。

使用 win32com.client 模块

pywin32 库提供的 win32com.client 模块提供了一种方便的方式来创建 COM 接口并从 Python 与 Excel 交互。使用此模块,你可以访问 Excel 的对象、打开工作簿、操作工作表以及执行 VBA 宏。

这里有一个示例,演示了如何使用 win32com.client 打开 Excel 工作簿并执行 VBA 宏。在运行此代码之前,你可以确保 iris_data.xlsm 包含宏,方法是转到 开发者 | (或 Visual Basic),查看是否存在宏:

import win32com.client as win32
import os
excel_app = win32.Dispatch("Excel.Application")
path =  os.getcwd().replace('\'','\\') + '\\'
workbook = excel_app.Workbooks.Open(path+"iris_data.xlsm")
excel_app.Run("examplePythonVBA")
workbook.Close(SaveChanges=True)
excel_app.Quit()

在相关方面,这里我们使用 os 库来处理工作目录和 Windows 特定的目录分隔符,以确保使用正确的绝对路径。这已经在之前的章节中进行了注释——文件必须位于 Python 运行的同一文件夹中(工作目录)或者你需要提供一个绝对路径。

代码没有返回任何内容,因为我们得到的效果是在 Excel 一侧:

图 3.3 – 从 Python 运行 VBA 宏

图 3.3 – 从 Python 运行 VBA 宏

在前面的代码中,我们使用 win32.Dispatch 创建了 Excel 应用程序的实例,并使用 Workbooks.Open 方法打开了一个工作簿。然后,我们使用 excel_app.Run 执行名为 examplePythonVBA 的 VBA 宏。最后,我们关闭工作簿,不保存更改,并退出 Excel 应用程序。

宏只是简单地在一个单元格中创建一个包含简短信息的新的工作表。

运行此代码后,您可以打开 .xlsm 工作簿,查看宏是否实际工作。

与 Excel 对象交互

使用 win32com.client,您可以访问各种 Excel 对象,如工作表、范围和图表,允许您以编程方式操作它们。例如,您可以将数据写入特定范围,格式化单元格,创建图表或执行计算。以下是一个使用 Python 将数据写入 Excel 工作表的示例:

import win32com.client as win32
import os
excel_app = win32.Dispatch("Excel.Application")
path =  os.getcwd().replace('\'','\\') + '\\'
workbook = excel_app.Workbooks.Open(path+"iris_data.xlsm")
worksheet = workbook.Worksheets("Sheet1")
data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
for row_index, row_data in enumerate(data, start=1):
for col_index, value in enumerate(row_data, start=1):
worksheet.Cells(row_index, col_index).Value = value
workbook.Close(SaveChanges=True)
excel_app.Quit()

如果成功,代码不会返回任何输出:

图 3.4 – 交互单元格的输出

图 3.4 – 交互单元格的输出

在前面的代码中,我们打开了一个 Excel 工作簿,访问名为 Sheet1 的特定工作表,并使用单元格的 属性 将数据写入单元格。我们遍历数据,并在相应的单元格中设置值。

将结果返回到 Python

在 Excel 中执行 VBA 代码后,您可能希望将结果返回到 Python 以进行进一步的分析或处理。完成此操作的一种方法是通过使用 Excel 的对象模型访问特定的值或范围,并将它们检索到 Python 变量中。

以下是一个使用 Python 从 Excel 工作表检索数据到 Python 列表的示例:

import win32com.client as win32
import os
excel_app = win32.Dispatch("Excel.Application")
path =  os.getcwd().replace('\'','\\') + '\\'
workbook = excel_app.Workbooks.Open(path+"iris_data.xlsm")
worksheet = workbook.Worksheets("Sheet1")
# Access multiple cells using Range notation
range_of_cells = worksheet.Range('A1:C3')
# Read the values from the range of cells
values = range_of_cells.Value
workbook.Close(SaveChanges=False)
excel_app.Quit()
print(values)

代码的结果是一个元组的元组:

((1.0, 2.0, 3.0), (4.0, 5.0, 6.0), (7.0, 8.0, 9.0))

图 3.5 – 从 Excel 中检索数据

图 3.5 – 从 Excel 中检索数据

在前面的代码中,我们定义了一个 Excel 单元格范围,并使用 Value 属性检索它们的值。我们将这些值存储在 Python 列表中,以便进一步处理或分析。

通过利用 win32com.client 模块和 Excel 对象模型,你可以有效地从 Python 编写和执行 VBA 代码。

提供的代码示例说明了如何与 Excel 交互、运行 VBA 宏,并将数据返回到 Python 以进行进一步操作。尝试这些技术,根据您的具体需求进行修改,并探索将 Python 和 VBA 集成到 Excel 自动化和数据处理中的可能性。

让我们看看这个设置如何帮助自动化任务。

自动化 Excel 任务

从 Python 执行 VBA 代码的主要好处之一是自动化 Excel 任务。

本节将讨论使用 Python 中的 VBA 自动化常见 Excel 操作的实际示例。通过无缝集成 Python 和 VBA,您可以简化您的数据分析工作流程,并显著提高您的生产力。

让我们探索一些可以使用这种强大组合自动化的任务。

数据操作

通过 Python 和 VBA 的集成,您可以在 Excel 中自动化数据操作任务。这包括排序数据、筛选记录、合并数据集和执行复杂转换等任务。例如,您可以使用 Python 从外部源检索数据,使用 Python 库如 pandasNumPy 处理数据,然后使用 VBA 更新 Excel 工作表中的转换数据。这种集成允许您自动化重复的数据操作任务并确保数据来源的一致性。

格式化

在 Excel 中自动化格式化任务可以节省大量的时间和精力。通过 Python 和 VBA,您可以定义格式化规则并将它们应用到特定的单元格、范围或整个工作表中。这包括字体样式、单元格边框、背景颜色和数字格式等格式化选项。通过结合 Python 的灵活性和 VBA 的格式化功能,您可以轻松地创建动态且视觉上吸引人的 Excel 报告或仪表板。

图表创建

Excel 的图表功能可以通过自动化从 Python 创建图表来有效利用。您可以从各种来源提取数据,在 Python 中进行必要的计算或汇总,然后使用 VBA 动态生成图表。这种自动化允许您直接从 Python 分析创建交互式和数据驱动的可视化,节省您的时间并提供对图表过程的更多控制。

由于这个主题相当庞大且重要,我们将在后面的专门章节中对其进行详细阐述。

复杂计算

Excel 以其强大的内置函数和公式而闻名。通过结合 Python 和 VBA,您可以进一步扩展 Excel 的计算能力。您可以利用 Python 的库进行高级数学或统计计算,并使用 VBA 将结果无缝集成到 Excel 中。这种集成使您能够在熟悉的 Excel 环境中执行复杂的计算、模拟或预测建模。

通过 Python 和 VBA 集成自动化 Excel 任务,您可以节省时间、消除手动错误并提高数据分析工作流程的效率。提供的代码示例和解释为您探索自动化的广泛可能性提供了一个起点。尝试不同的场景,根据您的具体需求调整代码,并充分发挥 Python 和 VBA 在 Excel 自动化方面的潜力。

我们现在知道如何从 Python 自动化 Excel 任务。我们也应该考虑为什么(或为什么不)这样做。

执行 VBA 从 Python 的优缺点

在本节中,我们将深入探讨从 Python 执行 VBA 代码的优缺点。通过了解这种方法的优点和局限性,您可以在选择适合您特定需求的工具时做出明智的决定。

让我们探讨从 Python 执行 VBA 代码的益处和考虑因素。

这里是从 Python 执行 VBA 代码的好处:

  • 灵活性与强大功能:通过结合 Python 和 VBA,您可以同时获得这两种语言的灵活性和强大功能。Python 提供了丰富的库和工具,用于数据分析、科学计算和自动化。另一方面,VBA 在 Excel 中提供了广泛的功能,允许您利用其内置功能、公式和宏。这种组合使您能够高效地完成复杂任务并自动化 Excel 操作。

  • 与外部数据源的集成:Python 在连接外部数据源方面表现出色,例如数据库、API 或网络爬取。通过从 Python 执行 VBA 代码,您可以无缝地将这些外部数据源与 Excel 集成。Python 可以检索数据,执行计算或转换,然后使用 VBA 更新 Excel 工作簿。这种集成使您能够利用 Python 的数据处理和分析能力,同时利用 Excel 的可视化和报告功能。

  • 自动化与效率:从 Python 执行 VBA 代码允许您自动化重复的 Excel 任务,从而提高生产力和效率。您可以通过自动化数据导入/导出、数据清理、格式化和报告生成来简化工作流程。这种自动化消除了手动错误,减少了手动工作量,并为您腾出更多时间进行更关键的分析和决策任务。

以下是从 Python 执行 VBA 代码的改进领域:

  • 兼容性与平台依赖性:从 Python 执行 VBA 代码主要支持基于 Windows 的系统。如果您在不同的操作系统上工作,例如 macOS 或 Linux,可能会遇到兼容性问题。此外,与不同版本的 Excel 或 Office 的兼容性可能有所不同,因此在共享或分发您的 Python 和 VBA 集成解决方案时需要仔细考虑。

  • 学习曲线和技能要求:成功从 Python 执行 VBA 代码需要熟悉这两种语言。您需要了解 VBA 的语法和功能,以便进行 Excel 自动化,以及 Python 的语法和功能,以便与 Excel 交互并执行 VBA 代码。这可能需要一些学习和实践,尤其是如果您对这两种语言中的任何一种都不熟悉。

  • 维护和更新:与任何软件集成一样,维护和更新可能需要考虑。如果 Excel 或 Python 生态系统有变化或更新,您可能需要相应地调整您的代码。此外,确保在不同版本的 Excel 和 Python 之间的兼容性和功能可能需要定期更新和测试。

尽管有这些考虑,但从 Python 执行 VBA 代码提供了一种强大的方法来自动化 Excel 任务,利用外部数据源,并创建高效的数据分析工作流程。通过结合 Python 和 VBA 的优势,你可以在 Python 项目中充分发挥 Excel 的潜力,并提高你的生产力和数据处理能力。

摘要

在本章中,我们学习了如何分别使用 RDCOMClientpywin32 集成 R、Python 和 VBA。我们获得了从 Python 执行 VBA 代码、设置环境以及自动化 Excel 任务的知识,并理解了这种集成的优缺点。

这项知识将使你能够提升你的 Excel 自动化技能。

在下一章中,我们将深入探讨高级主题,基于你现有的知识进行构建。

第四章:进一步自动化 - 任务调度和电子邮件

有时候,我们可能会花费无数个小时耐心地创建、格式化和发送 Excel 电子表格。但是,别担心!有了编程的力量,特别是 R 或 Python,您可以轻松自动化这些繁琐的任务,并重新获得宝贵的时间。

想象一下:您有一份需要整理成专业外观的销售额数据列表,并通过电子邮件发送给多个收件人。与其手动进行数据输入和格式化,您可以利用 R 或 Python 的强大功能简化您的工作流程。

在 R 中,您可以使用惊人的 taskscheduleR 包来安排任务,并在指定时间自动运行您的脚本。有了这个,您可以设置一个重复的任务来生成您的 Excel 电子表格并发送它们,无需动手。对于电子邮件,您可以使用 RDCOMClientWindows365Rblastula 包,这些包允许您直接与 Outlook 和 Gmail 交互。这意味着您可以轻松地编写和发送带有附件的电子邮件,并根据需要自定义内容和收件人。

但是,Python 爱好者们,不要担心,您也可以达到同样的自动化魔法水平。在 Python 中,您可以使用 pywin32 库通过 Gmail 发送格式优美的电子邮件。它与您的代码无缝集成,使您能够轻松地附加 Excel 电子表格并自定义电子邮件的内容和收件人。

通过利用 R 或 Python 的力量,结合 taskscheduleRRDCOMClientWindows365Rblastula,您可以成为办公室的英雄,迅速提供准确、视觉上吸引人的电子表格,同时品尝您的咖啡。告别令人厌烦的重复工作,迎接高效的自动化。让您的创造力蓬勃发展,解锁 R 或 Python 的力量,自信且轻松地征服 Excel 电子表格和电子邮件分发的世界!

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

  • 安装和理解 taskscheduleR

  • 使用 RDCOMClientWindows365Rblastula 在 Outlook 或 Gmail 中进行电子邮件操作

  • 安排 Python 脚本

  • 使用 Python 进行电子邮件通知和自动化

技术要求

本章的代码可以在以下位置找到:github.com/PacktPublishing/Extending-Excel-with-Python-and-R/tree/main/Chapter%204

您需要安装以下新的 R 和 Python 包:

  • Blastula

  • Windows365R

  • schedule==1.2.0

  • apscheduler==3.10.1

安装和理解 tasksheduleR 库

taskscheduleR R 包允许您使用 Windows 任务计划程序安排 R 脚本或进程。这意味着您可以在 R 内部自动执行特定时间点的 R 进程。该包基本上是Schtasks.exe功能的包装器。Schtasks.exe是一个命令行工具,允许您在本地或远程计算机上创建、删除、查询、更改、运行和完成计划任务。要使用taskscheduleR,您首先需要从 CRAN 安装该包。一旦安装了包,您就可以使用以下函数来安排 R 脚本:

  • taskscheduler_create(): 此函数创建一个新的计划任务。

  • taskscheduler_remove(): 此函数删除现有的计划任务。如果您使用的是版本 1.8,则该函数为taskscheduler_delete()

  • taskscheduler_get(): 此函数获取现有计划任务的信息。

taskscheduler_create()函数接受多个参数,包括计划任务名称、要运行的 R 脚本和运行脚本的计划。例如,以下代码将创建一个每天上午 10:00 运行 R 脚本my_scheduled_excel_script.R的计划任务:

taskscheduler_create(
  name = "My Scheduled Excel Task",
  rscript = "my_scheduled_excel_script.R",
  schedule = "DAILY",
  start_time = "10:00:00"
)`

您还可以通过安装miniUIshiny来使用 GUI 为作业调度器创建任务。这将安装包的附加功能,让您可以轻松创建任务而无需编写任何代码。如果您想安装前面列出的包,可以使用以下代码:

# The initial package itself
install.packages("taskscheduleR")
# To use the GUI
install.packages('miniUI')
install.packages('shiny')

现在,我们来看看如何创建这些脚本。

创建示例脚本

我们需要做的第一件事是创建一个可以通过 Windows 任务计划程序运行的脚本。让我们保持脚本简单,只使用 R 函数Sys.time()打印Hello和当前日期和时间。完成此操作后,我们就可以创建几个将运行脚本的作业。

这里是hello_world.R脚本:

library("tcltk")
tkmessageBox(
  title='Message',
  message = paste0("Hello, it is: ", Sys.time()),
  type = "ok"
  )

第一行代码,library("tcltk"),加载了tcltk包,该包提供了在 R 中创建和与图形用户界面GUIs)交互的函数。

第二行代码,tkmessageBox(),创建一个消息框。消息框是一个弹出窗口,显示一条消息并允许用户采取某些操作,例如点击按钮。

tkmessageBox()函数的参数如下:

  • title: 消息框的标题。

  • message: 将在消息框中显示的消息。

  • type: 消息框的类型。可能的值有okokcancelyesnoyesnocancelretrycancelabortretryignore

在这种情况下,消息框的类型是ok,这意味着用户只能点击一个ok按钮来关闭消息框。

第三行代码,paste0("Hello, it is: ", Sys.time()),创建一个将在消息框中显示的字符串。该字符串包括从Sys.time()函数获取的当前时间。

当运行此代码时,将弹出一个消息框,显示当前时间和一个 ok 按钮。用户可以点击 OK 按钮关闭消息框。

下面是消息框外观的截图:

图 4.1 – Hello world 消息框

图 4.1 – Hello world 消息框

现在,让我们编写几个脚本,它们将在预定时间在屏幕上弹出此消息。以下是一个每小时运行一次的脚本:

taskscheduler_create(
  taskname = "Hello World Hourly",
  rscript = "hello_world.R",
  schedule = "HOURLY"
)

代码的第一行,taskscheduler_create(),调用了来自 taskscheduleR 包的 taskscheduler_create() 函数。taskscheduleR 包提供了用于创建和管理 Windows 任务调度器作业的函数。

taskscheduler_create() 函数接受以下三个参数:

  • taskname:任务调度器作业的名称

  • rscript:任务调度器作业将要运行的 R 脚本的路径

  • schedule:任务调度器作业的调度

在这种情况下,任务名称是 Hello World Hourly,R 脚本是 hello_world.R,调度是 "HOURLY"

代码的第二行,taskname = "Hello World Hourly",将任务名称设置为 Hello World Hourly。任务名称是任务调度器作业的唯一标识符。

代码的第三行,rscript = "hello_world.R",设置了任务调度器作业将要运行的 R 脚本的路径。R 脚本必须保存在任务调度器可以访问的位置。

代码的第四行,schedule = "HOURLY",设置了任务调度器作业的调度。调度是一个字符串,指定了任务调度器作业何时运行。调度 "HOURLY" 表示任务调度器作业将每小时运行一次。当运行此代码时,将创建一个新的任务调度器作业,每小时运行 hello_world.R R 脚本。

现在,如果你不使用 Microsoft 365,我们将继续使用 RDCOMClient 来操作 Outlook。这将使我们能够在其他进程中编写发送电子邮件的脚本。

Outlook 的 RDCOMClient

正如我们所见,RDCOMClient 是一个强大的 R 包,它允许你通过 COM 接口与 Microsoft Outlook 进行交互。使用 RDCOMClient,你可以自动化 Outlook 中的任务,例如发送电子邮件、访问文件夹、管理约会等。通过 RDCOMClient 使用 Outlook 发送电子邮件非常简单,只需遵循几个步骤即可。以下是相应的脚本:

install.packages("RDCOMClient")
library(RDCOMClient)
OutApp <- COMCreate("Outlook.Application")
OutMail <- OutApp$CreateItem(0)
outMail[["To"]] <- "recipient@example.com"
outMail[["Subject"]] <- "Hello from RDCOMClient"
outMail[["Body"]] <- "This is the body of the email."
outMail$Attachments$Add("C:/path/to/attachment.txt")
outMail$Send()
outMail <- NULL
OutApp <- NULL

让我们现在理解前面代码的每一行:

  1. 首先,你需要在 R 环境中安装并加载 RDCOMClient 包。

  2. 一旦安装,使用 library() 函数加载该包。

  3. 接下来,使用 COMCreate() 函数创建一个新的 Outlook 应用程序对象。

  4. 这将建立与 Outlook 应用程序的连接。现在,你可以使用 OutApp$CreateItem() 方法创建一个新的电子邮件对象,并指定电子邮件类型为 olMailItem

  5. 接下来,您可以设置电子邮件的各种属性,例如收件人、主题、正文、附件等。以下是如何设置这些属性的示例:

    outMail[["To"]] <- "recipient@example.com"
    outMail[["Subject"]] <- "Hello from RDCOMClient"
    outMail[["Body"]] <- "This is the body of the email."
    outMail$Attachments$Add("C:/path/to/attachment.txt")
    
  6. 在设置所需的属性后,您可以使用Send()方法发送电子邮件,然后就可以结束了!

    电子邮件将从您的 Outlook 账户发送到指定的收件人,并带有配置的属性。记得在完成操作后释放 COM 对象并终止连接。

    这确保了资源得到适当的释放。

通过使用RDCOMClient,您可以直接从 R 中自动化 Outlook 中的电子邮件发送任务,从而让您的工作流程更加流畅并节省时间。它提供了一个方便的方法将 R 与 Outlook 集成,并允许以编程方式利用其功能。

现在,我们将深入探讨Microsoft365Rblastula这两个协同工作的包。这将替代使用RDCOMClient库,原因在于Microsoft365R适用于使用 Microsoft Azure 而不是通过 Outlook 的通用 SMTP 连接的用户。

使用 Microsoft365R 和 blastula 包

我们现在将介绍两个可以相互配合使用以通过 Microsoft Outlook 创建电子邮件的包。这些包是 Microsoft365R 和 blastula。让我们在接下来的部分中查看它们。

Microsoft365R

Microsoft365R是一个 R 库,它提供了一个接口来访问 Microsoft 365(以前称为 Office 365)云服务。它建立在AzureGraph包之上,该包为与 Microsoft Graph API 交互提供了高级抽象。目前,Microsoft365R支持以下 Microsoft 365 服务:

  • Teams

  • Outlook

  • SharePoint Online

  • OneDrive

该库为访问每个这些服务提供了几个顶级客户端函数。例如,get_personal_onedrive()函数可以用来访问您的个人 OneDrive 账户,而get_business_outlook()函数可以用来访问您的工作或学校 Outlook 账户。

Microsoft365R 还提供了一些用于处理 Microsoft Graph API 的辅助函数。例如,list_drive_contents()函数可以用来列出 OneDrive 驱动器的内容,而send_email()函数可以用来从 Outlook 发送电子邮件。

该库有良好的文档记录,并提供了一些示例来帮助您开始使用。它还定期积极维护和更新,包括新功能和错误修复。

使用 Microsoft365R 的一些好处如下:

  • 它提供了一个简单易用的界面,用于访问 Microsoft 365 云服务

  • 它建立在AzureGraph包之上,该包为与 Microsoft Graph API 交互提供了高级抽象

如果你正在寻找一个提供访问 Microsoft 365 云服务的 R 库,那么 Microsoft365R 是一个不错的选择。它在包的 vignettes 中有很好的文档记录,积极维护,并支持广泛的 Microsoft 365 服务。我们将只关注其 Outlook 的使用。

blastula 包

blastula R 包是一个工具,它使得从 R 生成和发送 HTML 电子邮件变得容易。你可以使用 Markdown 文本、基于块的组件,甚至 HTML 片段来创建包含三个内容区域的电子邮件消息:正文、页眉和页脚。该包还提供了设置 install.packages("blastula") 的函数。

使用 blastula 而不是其他电子邮件包的一些优点如下:

  • 它允许你使用 Markdown 文本、基于块的组件,甚至 HTML 来创建专业且可能计算出的文档电子邮件。你可以在电子邮件的正文、页眉和页脚中实现这一点。

  • 该包还提供了设置 SMTP 访问凭证和通过传统 SMTP 服务器发送电子邮件的功能,或者如果你是 RStudio Connect 用户,你可以通过 RStudio Connect 发送电子邮件。

  • 生成的电子邮件在任何显示器上看起来都会很棒。

  • 语法直观,让你可以快速有效地编写代码,同时将主要关注点放在电子邮件本身的信息上。

下面是一个使用 blastula 创建和发送简单 HTML 电子邮件消息的示例:

  1. 首先,我们需要使用 library(blastula)library(glue) 加载 blastula 包。

  2. 接下来,我们可以使用 compose_email() 函数创建电子邮件消息。我们可以向正文参数提供 Markdown 文本以在 HTML 中渲染;例如,参见以下:

    email <- compose_email(
      body = md(glue(
    "Hello, this is {sale_file} contains the latest quarters data. Here is a picture of the graph that will be on our dashboard:![sales dashboard] https://dashboard.company.com/)")
    )
    
  3. 然后,我们可以通过调用电子邮件对象在查看器中预览电子邮件消息:

    email
    
  4. 最后,我们可以使用 smtp_send() 函数通过 SMTP 服务器发送电子邮件消息。我们需要提供收件人的电子邮件地址、发件人的电子邮件地址、主题行和 SMTP 服务器的凭证:

    email %>%
      smtp_send(
         to = "jane_doe@example.com",
         from = "joe_public@example.net",
         subject = "Testing the `smtp_send()` function",
         credentials = creds_file("email_creds")
      )
    

    creds_file() 函数是一个辅助函数,用于为 SMTP 访问创建凭证文件。

    我们可以使用 create_smtp_creds_file() 函数交互式地生成此文件:

    create_smtp_creds_file(
      file = "email_creds",
      user = "joe_public@example.net",
      provider = "gmail"
    )
    

这将提示我们输入我们的密码和两步验证码(如果已启用)以访问 Gmail。凭证文件将保存在安全位置,并可以用于未来的电子邮件消息。

既然我们已经单独了解了这两个包,让我们看看如何将它们结合起来使用,以实现更稳健和流畅的效果。

下面是一个完整的脚本,然后我们将讨论它是如何工作的:

install.packages("blastula")
install.packages("Microsoft365R")
library(blastula)
library(Microsoft365R)
# Get work/school email
outlb <- get_business_outlook()
# compose an email with blastula
bl_body <- "## Hello!
You can write email in **Markdown** with the blastula package."
bl_em <- compose_email(
     body=md(bl_body),
     footer=md("sent via Microsoft365R and R")
)
em <- outlb$create_email(bl_em, subject="Hello from R", to="email@example.com")
# add an attachment and send it
em$add_attachment("mydocument.docx")
em$send()

现在,让我们逐一查看脚本中的每个部分,以了解正在发生的事情。

  1. 首先,我们必须安装 blastulaMicrosoft365R 包。

  2. 然后,我们使用 library() 函数将那些库调用到当前会话中。

  3. 然后,我们创建一个名为 outlb 的变量,用于存储 get_business_outlook() 函数的变量。

  4. 然后我们创建电子邮件的主体。我们可以使用 Markdown 语法编写电子邮件。

  5. 在我们创建电子邮件的主体之后,我们接着创建一个变量来保存使用 compose_email() 函数创建的电子邮件本身。

  6. 从这里,我们添加附件并发送电子邮件。

电子邮件是通过配置的工作/学校电子邮件账户发送的。因此,总的来说,这些代码行安装必要的包,加载所需的库,检索工作/学校电子邮件账户,使用 blastula 包编写电子邮件,向电子邮件添加附件,并最终使用 Microsoft365R 包发送电子邮件。

你已经了解了 R 中的安排和电子邮件集成。现在,让我们看看如何在 Python 中实现相同的功能!

安排 Python 脚本

自动化不仅限于手动执行脚本;它还涉及在特定间隔或事件中安排它们运行。安排 Python 脚本允许你自动化重复性任务,执行定期数据更新,生成报告,以及执行系统维护,而无需人工干预。

在本节中,我们将探讨安排 Python 脚本的多种技术和工具,以实现高效和及时的执行。

到本节结束时,你将全面了解适用于 Python 脚本的多种安排技术和工具。你将具备有效安排 Python 脚本、自动化常规任务并最大化生产力的知识和技能。无论你是在 Windows 或类 Unix 系统上运行脚本,这一章节都将赋予你实施可靠且高效的 Python 脚本安排解决方案的能力。

Python 脚本安排简介

我们将首先讨论安排 Python 脚本的重要性及其在简化工作流程中的益处。你将了解为什么安排对于自动化任务至关重要,以及它如何节省时间和精力。我们还将强调 Python 脚本安排在实际场景中的常见应用。

安排 Python 脚本在自动化任务和提升工作流程效率方面发挥着至关重要的作用。通过安排脚本在特定间隔或事件中运行,你可以消除手动执行的需求,并确保及时准确的数据处理、报告生成和系统维护。

在本节中,我们将探讨 Python 脚本安排的重要性,并强调其在以下列出的各个领域的益处:

  • 自动化重复性任务:数据处理、分析和报告中的许多任务都涉及重复操作。安排 Python 脚本允许你自动化这些任务,减少手动执行所需的时间和精力。无论是从外部来源获取数据、执行计算、生成报告还是更新数据库,安排脚本都能确保一致可靠的自动化。

  • 定期数据更新:在许多应用中,数据需要定期从外部来源更新或从内部系统刷新。Python 脚本安排使您能够定义自动获取、转换和更新数据的计划。通过指定所需的频率,您可以确保数据保持最新,无需人工干预。

  • 生成报告:报告通常定期生成,如每日、每周或每月。使用 Python 脚本安排,您可以通过安排脚本在特定间隔运行来自动化报告的生成。这确保了报告的持续生成和准时交付,节省了宝贵的时间和精力。

  • 系统维护:Python 脚本安排不仅限于数据相关任务;它还可以用于系统维护活动。从执行备份和数据库维护到运行系统检查和执行常规清理任务,安排 Python 脚本使您能够在无需人工干预的情况下保持系统平稳运行。

  • 实际场景:Python 脚本安排在各个行业和领域都有应用。例如,在电子商务中,脚本可以安排更新产品库存、同步价格和生成销售报告。在金融领域,安排的脚本可以抓取股市数据、计算投资组合表现和生成财务报表。在 IT 运营中,脚本可以安排进行系统监控、日志分析和自动事件响应。这些只是 Python 脚本安排如何在不同领域提高生产力和效率的几个例子。

通过理解 Python 脚本安排的重要性及其益处,您可以识别自动化任务、简化工作流程和提高整体生产力的机会。

在接下来的章节中,我们将探讨用于安排 Python 脚本的不同方法和工具,为您提供实施有效且可靠的自动化解决方案的知识和技术。

内置安排选项

Python 在 Windows 和 Unix-like 系统上提供内置的安排选项,无需外部库。这些选项提供了一种方便且轻量级的方式来安排和执行您的 Python 脚本,在预定义的间隔内运行。在本节中,我们将探讨内置的安排选项,并讨论其特性、用法和限制。

我们将探讨 Windows 任务计划程序 和 Unix-like 系统上的 crontab。您将学习如何使用这些原生安排工具设置计划任务,指定执行频率,并配置各种选项以满足您的特定需求。

这里是内置选项及其关键特性的列表:

cron(Unix-like 系统)

以下列出的是 cron 的关键特性:

  • cron 是一种基于时间的作业安排程序,可在 Unix-like 操作系统上使用,包括 Linux 和 macOS

  • 它允许您通过指定时间、日期和频率使用 cron 表达式来安排重复的任务

  • cron 提供了定义计划的灵活性,例如在特定时间、特定周几或定期运行脚本

  • 它得到了广泛的支持,并且多年来一直是类 Unix 系统上调度任务的既定标准

  • 虽然 cron 不是 Python 特定的工具,但您可以通过指定适当的命令行调用来使用它来安排 Python 脚本的执行

Windows 任务计划程序(Windows 系统)

以下列出了 Windows 系统的特性:

  • Windows 任务计划程序是 Windows 操作系统提供的内置任务调度工具

  • 它允许您在 Windows 机器上安排在特定时间或事件运行的任务

  • 您可以通过图形用户界面或使用命令行工具schtasks创建计划任务

  • Windows 任务计划程序提供了一系列定义触发器的选项,例如特定时间、每日、每周或每月的计划,甚至基于系统事件

  • 它提供了一个用户友好的界面来管理计划任务,包括设置依赖关系、优先级设置和错误处理

Python 的time.sleep()函数

这是time.sleep()函数的关键特性列表:

  • 虽然 Python 的内置time模块并非专门设计用于调度任务,但它提供了一种简单的方法来在脚本执行之间引入延迟

  • time.sleep()函数暂停脚本指定的秒数,允许您控制脚本运行之间的时间间隔

  • 虽然此选项缺乏专用调度工具的复杂性和高级功能,但在需要固定延迟的简单情况下可能很有用

  • 然而,请注意,使用time.sleep()作为调度机制可能不适合精确或复杂的调度需求

重要的是要注意,这些内置的调度选项有其优点和局限性。它们适用于许多用例,但可能不提供复杂调度场景所需的先进功能和灵活性。在这种情况下,外部库和工具可以提供更稳健的解决方案。

在下一节中,我们将探讨一些流行的第三方库,用于调度 Python 脚本,提供额外的功能和定制选项。

第三方调度库

虽然 Python 的内置调度选项可以处理许多常见的调度任务,但还有几个第三方库可用,它们提供了更多高级功能和定制选项。这些库提供了更大的灵活性和对调度 Python 脚本的控件,使您能够轻松处理复杂的调度场景。

在本节中,我们将探讨一些流行的第三方调度库,并讨论它们的功能和优势。我们将涵盖使用类似 cron 的语法定义调度、处理时区和管理并发执行等主题。

schedule

下面是schedule库的功能和优势:

  • schedule库是一个轻量级的 Python 库,简化了任务调度的过程。

  • 它提供了一个直观且易于使用的 API,用于使用流畅的接口定义调度。

  • 该库支持各种调度选项,如特定时间、间隔和类似 cron 的表达式。

  • schedule允许您在定义的调度下执行函数、方法,甚至 shell 命令。

  • 它被设计得简单轻量,适合小型项目或需要最小化调度解决方案的情况。

下面是一个在 Python 中使用schedule的简单示例:

import schedule
import time
def job():
    print("This job is executed every day at 8:00 AM.")
# Schedule the job to run every day at 8:00 AM
schedule.every().day.at("08:00").do(job)
# Keep the program running
while True:
    schedule.run_pending()
    time.sleep(1)

在这个示例中,我们导入schedule库并定义一个名为job()的函数,该函数打印一条消息。然后,我们使用schedule.every().day.at(08:00).do(job)语法来安排job函数每天早上 8:00 运行。最后,我们使用一个while循环来持续检查待处理的计划任务并执行它们。请注意,这种解决方案意味着控制台被blocked,即运行这个无限循环的 Python 进程将无法执行其他任务。要停止调度器,只需中断内核/控制台或终止底层的 Python 进程。

您可以通过使用schedule库提供的不同方法来自定义调度行为,例如.every().day.at().every().monday.every().hour等。此外,您可以根据需求安排在特定间隔运行的任务,或者组合多个调度模式。

接下来,让我们看看APScheduler

高级 Python 调度器 (APScheduler)

下面是APScheduler的功能和优势:

  • 高级 Python 调度器APScheduler)是 Python 中调度任务的另一个流行选择。

  • 它提供了一套丰富的功能,包括各种触发类型,如间隔、cron 表达式和基于日期的触发器。

  • APScheduler 支持多种作业存储,包括内存、SQL 数据库和 Redis。

  • 它提供了高级调度选项,如作业合并、分布式调度和时间支持。

  • APScheduler 具有完善的文档,并被广泛应用于各种应用中,从简单的脚本到复杂的 Web 应用。

下面是一个使用APScheduler库安排任务的示例代码片段:

from apscheduler.schedulers.blocking import BlockingScheduler
# Create a scheduler instance
scheduler = BlockingScheduler()
# Define a task function
def send_email():
     # Code to send an email
     print("Email sent!")
# Schedule the task to run every hour
scheduler.add_job(send_email, 'interval', hours=1)
# Start the scheduler
scheduler.start()

从前面的示例中,我们可以理解以下内容:

  1. 我们首先从apscheduler.schedulers.blocking模块中导入BlockingScheduler类。然后,我们使用BlockingScheduler()创建调度器的一个实例。

  2. 接下来,我们定义一个名为send_email()的函数,它代表发送电子邮件的任务。在这个函数内部,您可以编写发送电子邮件或执行任何其他所需操作的代码。

  3. 要调度任务,我们使用调度器的add_job()方法。在这种情况下,我们将send_email函数指定为要执行的任务。我们还通过interval选项提供调度参数,该选项表示任务应定期执行。在这个例子中,我们将其设置为每小时运行一次(hours=1)。

  4. 最后,我们通过调用start()方法来启动调度器。这将初始化调度器并开始根据定义的日程执行任务。

APScheduler库提供了各种调度选项,例如固定间隔、cron 表达式、日期/时间触发器等。您可以通过查阅文档并使用 APScheduler 提供的适当调度选项来根据您的具体需求自定义调度行为。

接下来,为了完整性,让我们看一下 Celery 包。

Celery

以下是一些 Celery 的功能和好处:

  • Celery 是一个用于任务执行和调度的分布式任务队列库。

  • 它为在多个工作者或机器上跨多个 Python 任务提供了一种强大且可扩展的解决方案。

  • Celery 支持各种调度选项,包括间隔、类似 crontab 的表达式等。

  • 它提供了高级功能,如任务优先级、结果跟踪、重试和任务链。

  • Celery 与消息代理如RabbitMQRedisApache Kafka很好地集成,提供了可靠且可扩展的任务调度能力。

通过使用 Celery 调度器,您可以根据特定的日程自动化任务的执行,允许您在应用程序中执行周期性或基于时间的操作。不过,配置和部署 Celery 应用程序超出了本书的范围,所以这里仅为了完整性而提及。如果您想深入了解,可以查阅官方文档:docs.celeryq.dev/en/stable/userguide/periodic-tasks.html

这些第三方调度库为调度 Python 脚本提供了强大且灵活的解决方案。根据您的具体需求和调度任务的复杂性,您可以选择最适合您需求的库。每个库都有其自身的优势和功能,因此根据您项目的需求进行评估非常重要。

在下一节中,我们将探讨使用这些库来为各种用例调度 Python 脚本的实际示例。

适用于强大自动化方案的最佳实践和考虑因素

当与调度 Python 脚本一起工作时,遵循最佳实践并考虑各种因素对于确保高效和可靠的自动化至关重要。本节提供了关于有效调度 Python 脚本的最佳实践和考虑因素的见解。

这些最佳实践将帮助您创建强大且可维护的计划任务。让我们在以下章节中讨论这些最佳实践。

错误处理和日志记录

这里是错误处理和日志记录的最佳实践:

  • 实施强大的错误处理机制来处理脚本执行过程中可能发生的任何意外异常和错误

  • 使用日志框架来捕获有关脚本执行的详细信息,包括错误、警告和信息消息

  • 正确的错误处理和日志记录允许您诊断问题、跟踪脚本性能并确保计划任务按预期执行

资源管理

这里是资源管理的最佳实践:

  • 考虑您计划中的 Python 脚本所需的资源,例如 CPU、内存和磁盘空间

  • 通过识别和最小化任何资源密集型操作或瓶颈来优化资源使用

  • 确保您的脚本正确释放资源,以避免资源泄漏或冲突

安全考虑

这里是安全考虑的最佳实践:

  • 评估调度 Python 脚本的安全影响,特别是如果它们涉及敏感数据或与外部系统交互

  • 实施必要的安全措施,例如加密凭证、保护 API 端点以及遵守身份验证和授权协议

  • 定期审查和更新安全措施以减轻潜在的风险和漏洞

测试和验证

这里是测试和验证的最佳实践:

  • 仔细测试和验证您的计划 Python 脚本,以确保它们的正确性和可靠性

  • 执行单元测试、集成测试和端到端测试,以验证脚本按预期工作并处理各种场景

  • 考虑创建一个预演环境,在那里您可以测试计划任务,然后再将它们部署到生产环境

监控和警报

这里是监控和警报的最佳实践:

  • 建立监控和警报机制以跟踪计划任务的执行状态

  • 监控调度系统的性能和健康状况,包括脚本执行时间、资源使用以及任何潜在的错误或故障

  • 配置警报,以便在任务失败时通知您,以便进行快速干预和故障排除

文档和维护

这里是文档和维护的最佳实践:

  • 记录调度过程,包括配置、依赖关系以及管理计划任务的具体说明

  • 维护您计划中的 Python 脚本的最新日程安排,包括每个任务的频率和预期结果

  • 定期审查和更新你的计划设置、脚本和依赖项,以适应不断变化的需求和技术。

通过遵循这些最佳实践并考虑相关因素,你可以确保计划 Python 脚本的可靠性、效率和安全性。将这些考虑因素纳入你的计划工作流程将有助于任务的顺利执行,并帮助你维护一个结构良好且可持续的自动化系统。

在下一节中,我们将探讨实际示例和应用案例,说明这些最佳实践和考虑因素在现实场景中的应用。

通过完成本节关于安排 Python 脚本的内容,你获得了自动化和管理脚本执行的有价值知识和技能。让我们总结一下你所学到的内容:

  • 你探讨了不同操作系统中可用的各种内置计划选项,例如类 Unix 系统上的 cron 作业和 Windows 上的任务计划程序,使你能够安排在特定时间或间隔运行 Python 脚本。

  • 你发现了第三方计划库,如 APSchedulerSchedule,它们提供了更高级的计划功能,例如类似 cron 的表达式和基于间隔的计划。

  • 你了解了安排 Python 脚本的最佳实践,包括错误处理、资源管理、安全考虑、测试、验证、监控和警报,以及文档和维护。

  • 通过实际示例和应用案例,你获得了实施和管理计划 Python 脚本的实际经验,确保你的任务自动化高效且可靠。

通过掌握本节涵盖的概念和技术,你现在可以有效地安排 Python 脚本,自动化重复性任务,并简化你的工作流程。能够安排脚本为自动化各种流程、提高生产力和为更关键的任务节省宝贵时间打开了新的可能性。

在下一节中,我们将深入探讨令人兴奋的电子邮件通知领域,并探讨如何通过将电子邮件功能集成到你的 Python 脚本中,增强你的自动化工作流程。

使用 Python 进行电子邮件通知和自动化

与安排 Python 脚本类似,电子邮件通知和自动化可以使你的日常工作更加高效。本节将涵盖基础知识,例如使用 Python 发送电子邮件的动机,接着介绍设置环境和发送基本电子邮件,然后讨论一个实际应用案例:发送脚本状态电子邮件通知。

Python 中电子邮件通知简介

电子邮件通知在自动化中发挥着至关重要的作用,通过提供及时更新、警报和报告。在本节中,我们将探讨将电子邮件功能集成到您的 Python 脚本中的重要性。我们将讨论电子邮件通知可以带来益处的各种用例,并深入探讨它们在简化工作流程和增强沟通方面的优势。

让我们从最基本的考虑开始:你为什么要这样做?

集成电子邮件功能到您的脚本的使用案例和优势

电子邮件通知具有多功能性,可以应用于各种场景。以下是一些常见的用例:

  • 任务完成通知:这些通知发送给利益相关者,表明任务或过程的成功完成,有助于让他们了解一切进展顺利。

  • 错误和异常报告:这涉及到在脚本执行过程中发生错误或异常时向相关团队成员或管理员发出警报,以便进行及时的故障排除和问题解决。

  • 进度更新:这为利益相关者或客户提供定期的进度更新,确保透明度并保持开放的沟通渠道。

  • 数据分析报告:这些通过电子邮件自动生成和发送数据分析报告,通过消除手动报告创建和分发的需求来节省时间和精力。

  • 系统监控:这涉及到设置电子邮件通知以监控系统状态,例如服务器正常运行时间、磁盘空间使用情况或应用程序性能。即时警报可以帮助在问题影响操作之前解决潜在问题。

通过将电子邮件通知集成到您的 Python 脚本中,您可以享受到以下好处:

  • 实时更新:了解自动化任务的进度、状态和结果

  • 增强协作:通过提供及时的通知,促进团队成员之间的沟通和协作

  • 错误检测和解决:接收有关脚本中错误或异常的警报,使您能够快速识别和解决问题

  • 定制和个人化:根据您的具体要求定制电子邮件通知,包括内容、格式和收件人

  • 简化工作流程:自动化报告、更新和警报的交付,节省手动分发的时间和精力

在本节中,我们将探讨 Python 中电子邮件通知的各个方面,使您能够利用这一强大的通信工具在自动化工作流程中。

让我们深入探讨如何有效地设置和使用电子邮件功能。

设置电子邮件服务

在深入探讨从 Python 发送电子邮件通知之前,设置必要的电子邮件服务以在您的脚本和电子邮件服务器之间建立连接是至关重要的。

到本节结束时,您将清楚地了解如何为您的 Python 脚本设置电子邮件服务。您将具备选择合适的电子邮件服务提供商、获取所需的 SMTP 服务器凭据、配置安全连接以及测试连接的必要知识。一旦您的电子邮件服务就绪,您就可以继续从您的 Python 脚本中无缝发送电子邮件通知的下一步了。

让我们开始,有效地设置您的电子邮件服务。

在本节中,我们将介绍配置电子邮件服务所需的步骤,包括以下方面。

选择电子邮件服务提供商

可用的电子邮件服务提供商有多种,每个都提供不同的功能和选项。在本节中,我们将以 Gmail 为例,但代码可以轻松地适应其他提供商,例如 Microsoft Exchange 等。

获取 SMTP 服务器凭据

要以编程方式发送电子邮件,重要的是获取您的电子邮件服务提供商提供的 SMTP 服务器凭据。这些凭据对于与电子邮件服务器建立连接和发送安全电子邮件至关重要。

在本节中,我们将指导您获取配置电子邮件设置所需的信息。

  • smtp.example.commail.example.com。请确保您验证了您特定电子邮件服务的正确 SMTP 服务器地址。

  • 端口号:端口号指定了 SMTP 服务器的通信端点。SMTP 通信的常见端口号包括 25、465(用于 SSL/TLS 加密连接)和 587(用于 STARTTLS 加密连接)。您的电子邮件服务提供商将指定用于发送电子邮件的适当端口号。

  • 认证详情:为了通过 SMTP 服务器进行认证,您需要提供用户名和密码。这些凭据用于建立安全连接并确保只有授权用户可以发送电子邮件。您的电子邮件服务提供商将为您提供必要的认证详情。在某些情况下,可能需要 API 密钥或访问令牌而不是传统的用户名和密码进行认证。

需要注意的是,获取 SMTP 服务器凭据的过程可能因您的电子邮件服务提供商而异。一些提供商提供特定的说明或账户设置,您可以在其中找到所需信息。如果您不确定在哪里找到您的 SMTP 服务器凭据,建议您咨询您的电子邮件服务提供商提供的文档或支持资源。

通过获取 SMTP 服务器凭据,您将具备与电子邮件服务器建立连接和以编程方式发送电子邮件的必要信息。这使您能够利用 Python 的力量在您的应用程序或脚本中自动化电子邮件通知、更新和其他通信任务。

测试连接

为了确保成功设置,测试您的 Python 脚本与电子邮件服务器之间的连接是非常重要的。

在下一节中,我们将演示如何通过使用提供的 SMTP 服务器凭据发送测试电子邮件来执行连接测试。这将有助于验证连接是否正确建立,并且您的脚本可以与电子邮件服务器通信。

发送基本电子邮件

现在我们已经设置了电子邮件服务,我们可以继续下一步:从 Python 发送基本电子邮件。

到本节结束时,您将深入了解如何从 Python 发送基本电子邮件。您将了解如何导入所需的库、创建电子邮件消息、与电子邮件服务器建立连接以及使用 SMTP 协议发送电子邮件。有了这些知识,您将能够从您的 Python 脚本中发送基于文本的简单电子邮件,并为更高级的电子邮件通知打下基础。

在本节中,我们将探讨发送电子邮件的基本概念和技术。

导入所需的库

要从 Python 发送电子邮件,我们需要导入提供电子邮件相关功能的必要库。接下来,我们将讨论流行的库,如smtplibemail.mime,它们为创建和发送电子邮件提供了便利的功能。我们将指导您完成安装过程,并演示如何将这些库导入到您的 Python 脚本中。

创建电子邮件消息

在发送电子邮件之前,我们需要构建电子邮件消息,这包括发件人、收件人、主题和邮件正文。我们将向您展示如何使用email.mime库创建电子邮件消息,允许您自定义电子邮件的各个方面,例如添加附件或设置 HTML 内容。我们将提供代码示例和解释,以帮助您理解电子邮件消息的结构和组件。

建立连接

要发送电子邮件,我们需要使用 SMTP 协议与电子邮件服务器建立连接。我们将演示如何使用之前获得的 SMTP 服务器凭据建立连接。我们将指导您完成创建 SMTP 对象、设置连接和处理在建立连接过程中可能出现的任何潜在错误或异常的过程。

发送电子邮件

一旦建立连接,我们就可以继续发送电子邮件。我们将演示如何使用smtplib库发送电子邮件消息。我们将涵盖必要的步骤,包括通过电子邮件服务器进行身份验证、指定发件人和收件人地址以及调用sendmail()方法。我们还将讨论错误处理,并提供确保电子邮件成功投递的最佳实践。

前面的部分是以下代码示例中实现的步骤:

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# Define email server and credentials
smtp_server = 'your_smtp_server'
smtp_port = 587
smtp_username = 'your_username'
smtp_password = 'your_password'
# Create a MIME message
message = MIMEMultipart()
message['From'] = 'sender@example.com'
message['To'] = 'recipient@example.com'
message['Subject'] = 'Test Email'
# Add the email body
body = MIMEText('This is the email body.')
message.attach(body)
# Establish a connection with the email server
with smtplib.SMTP(smtp_server, smtp_port) as server:
    # Start the TLS encryption
    server.starttls()
    # Log in to the email server
    server.login(smtp_username, smtp_password)
    # Send the email
    server.send_message(message)

从此代码示例中,我们可以观察到以下内容:

  1. 我们首先导入smtplib库以建立 SMTP 连接,并从email.mime模块导入MIMETextMIMEMultipart类以创建电子邮件消息。

  2. 接下来,我们定义 SMTP 服务器详情,包括服务器地址、端口以及用于身份验证的凭据(用户名和密码)。

  3. 然后,我们创建一个名为 message 的MIMEMultipart对象,它代表电子邮件消息。我们设置发送者和接收者地址,以及电子邮件的主题。

  4. 接着,我们使用 SMTP 服务器对象的send_message()方法发送电子邮件,将消息作为参数传递。

  5. 记得替换占位符值(your_smtp_serveryour_username)。为了添加电子邮件正文,我们创建一个名为 body 的MIMEText对象并将其附加到消息中。

  6. 然后,我们使用smtplib.SMTP类通过传递服务器地址和端口作为参数与电子邮件服务器建立连接。我们使用starttls()方法启动 TLS 加密。

  7. 接下来,我们使用login()方法登录电子邮件服务器,并提供用户名和密码。

最后,使用your_passwordsender@example.comrecipient@example.com替换占位符值,并使用你实际的 SMTP 服务器详情和电子邮件地址。

通过遵循此代码示例,你将能够使用 Python 中的smtplibemail.mime库发送基本的电子邮件。

发送脚本状态电子邮件通知

在本节中,你将学习如何定义触发器、实现电子邮件通知逻辑、自定义电子邮件内容,以及有效地处理电子邮件投递和错误。掌握这些技能后,你将能够增强脚本的监控和报告功能,并了解自动化流程的进度和结果。

到本节结束时,你将清楚地了解如何将电子邮件通知集成到 Python 脚本中,以接收脚本执行和状态的更新。

Python 中电子邮件通知的一个关键用例是接收脚本或进程的状态更新。在本节中,我们将深入了解发送电子邮件通知以跟踪脚本执行和状态的过程。通过实现此功能,你可以在需要时了解自动化流程的进度和结果,并采取必要的行动。

首先,让我们探讨发送脚本状态电子邮件通知所涉及的步骤。

定义触发器

在我们能够发送电子邮件通知之前,我们需要定义触发器,以确定何时发送通知。触发器可以基于脚本执行期间发生的特定条件或事件。例如,你可能希望在脚本成功完成、遇到错误或达到特定里程碑时发送电子邮件通知。通过定义触发器,你可以完全控制电子邮件通知的发送时间和条件。

实现电子邮件通知逻辑

一旦定义了触发器,我们就可以继续实现发送电子邮件通知的逻辑。这需要在你的脚本中包含必要的代码来检查触发器并启动电子邮件发送过程。你需要导入所需的库,与电子邮件服务器建立连接,并自定义电子邮件内容。逻辑应该设计得能够高效地根据指定的触发器处理发送电子邮件通知。

自定义电子邮件内容

为了在电子邮件通知中提供相关和有价值的内容,你可以自定义电子邮件的各个方面,如主题、正文以及任何附加细节。内容可以包括有关脚本执行状态、错误消息、相关数据或统计信息以及任何其他对理解脚本进度重要的细节。通过自定义电子邮件内容,你可以确保收件人获得采取适当行动或做出明智决策所必需的信息。

处理电子邮件投递和错误

发送电子邮件涉及与电子邮件服务器的交互,各种因素都可能影响电子邮件的成功投递。处理潜在问题,如网络连接问题、电子邮件服务器错误或收件人电子邮件地址错误,非常重要。通过实施错误处理机制,你可以优雅地处理电子邮件投递问题,并确保通知可靠地发送。此外,日志记录和错误报告对于故障排除和诊断可能发生的任何电子邮件相关问题非常有用。

总结来说,通过实现脚本状态的电子邮件通知,你可以了解自动化过程的进度和结果。你可以灵活地定义触发器、自定义电子邮件内容,并有效地处理潜在的电子邮件投递问题。这种功能增强了脚本监控和报告能力,并使你能够根据脚本的状态及时采取行动。有了这些技术,你可以在保持对执行情况更新的同时,自信地自动化你的流程。

摘要

在 Python 的调度和电子邮件通知章节中,你已经对关键概念有了全面的理解。你学习了 Python 脚本的不同调度选项,包括内置选项和第三方库,如scheduleAPScheduler。本章还强调了遵循电子邮件通知最佳实践的重要性,例如错误处理、资源管理、安全考虑、测试、监控、文档和维护。

现在,您应该能够认识到电子邮件通知在提供自动化系统中流程状态和结果及时更新方面的价值。我们已经探讨了 Python 的强大库和模块,例如 smtplibemail.mime,它们能够创建和定制电子邮件消息。此外,您已经获得了通过配置 SMTP 服务器、认证凭证和其他相关设置来设置电子邮件服务所需的知识。我们还了解了 R 中的包,如 tasksheduleRblastulaMicrosoft365R,它们也将执行这些功能。它们具有坚实且简单的语法,这使得它们成为非常强大的工具。

在对基础知识有了坚实的理解之后,您已经学会了如何构建简单的电子邮件消息,包括必要的头信息和内容,以实现基本的电子邮件功能。您还发现了电子邮件通知在提供脚本执行更新方面的多功能性,包括成功、失败或特定事件。现在,您已经拥有了这些见解,读者将能够有效地将电子邮件通知集成到他们的 Python 项目中。

通过完成本章,您应该已经对在 Python 中安排脚本和电子邮件通知有了全面的理解。您已经学会了何时以及如何使用各种调度工具,设置电子邮件服务,并发送基本电子邮件。在下一章中,我们将学习如何使用 Python 和 R 格式化 Excel。

第二部分:美化效果 – 格式化、图表及其他

在本部分中,我们将深入了解增强 Excel 工作表的视觉吸引力和功能。您将学习如何使用 styledTablestablaxlsxexcelRbasictablertidyxl 等库在 R 中以及 pandasopenpyxl 在 Python 中优雅地格式化您的数据。您将发现将 ggplot2matplotlib 图表无缝插入 Excel 工作表中的技术,使您的数据生动起来。此外,您将掌握使用 R 中的 tidyquant、Python 中的 win32compypiwin32 创建数据透视表的艺术,以及使用 {gt} 创建高级汇总表。

本部分包含以下章节:

  • 第五章, 格式化您的 Excel 工作表

  • 第六章, 插入 ggplot2/matplotlib 图表

  • 第七章, 数据透视表和汇总表

第五章:格式化您的 Excel 工作表

本章中,我们将探讨 R 中的两个不同库以及 Python 中的一些库,这些库可以用来格式化 Excel 工作表中的表格和数据。

我们将讨论 R 中的几个包,包括以下内容:

  • styledTables

  • basictabler

我们将创建一些虚构数据,并使用 R 的一个内置数据集 Iris,然后我们将应用上述包中的样式。每个包都有自己的方法来应用这种样式,所以最好浏览一下它们,看看你更喜欢哪种工作流程。

在本章的 Python 部分,我们将探讨pandasopenpyxl在 Python 中创建美观的表格和交叉表的高级选项。特别是,我们将使用pandasopenpyxlpywin32

本章中,我们将了解以下主题:

  • 在 R 中安装和使用styledTables

  • 使用 Python 进行格式化的高级选项

到本章结束时,你将深入理解单元格格式化、条件格式化和交叉表。所以,无需进一步延迟,让我们开始吧。

技术要求

本章的代码可以在以下 GitHub 链接中找到:github.com/PacktPublishing/Extending-Excel-with-Python-and-R/tree/main/Chapter5

如前所述,在 R 部分,我们将使用几个不同的包。styledTables包只能通过devtools包从 GitHub 安装。

对于 Python 部分,你需要一个新包(特别是用于与pandas一起进行格式化任务的包):jinja2==3.1.2

在 R 中安装和使用 styledTables

如我们之前所做的那样,在使用它们之前,我们需要安装必要的包。在本节中,我们将安装styledTables包。因为styledTables不在 CRAN 上,我们不能使用install.packages()函数的典型方法来安装它,所以我们需要从 GitHub 安装此包。这将需要我们安装devtools包,它具有执行此类操作的功能。

这是您需要安装此包的完整代码:

install.packages("devtools")
# Install development version from GitHub
devtools::install_github(
'R-package/styledTables',
build_vignettes = TRUE
)

在运行前面的代码后,我们可以通过在控制台中发出library(styledtables)的典型方式将库调用到当前会话中。现在我们已经加载了库,我们可以继续创建我们的第一个脚本,该脚本将根据简单标准对表格进行样式化。让我们开始吧:

library(TidyDensity)
library(styledTables)
library(xlsx)
st <- tidy_normal() |>
  styled_table(keep_header = TRUE) |>
  set_border_position("all", row_id = 1) |>
  set_bold(row_id = 1) |>
  set_fill_color("#00FF00", col_id = 3,
                 condition = X >= 0.5)
# open new xlsx workbook and create a worksheet
wb <- createWorkbook()
sheet <- createSheet(wb, "tidy_normal")
# insert the styled table in the worksheet
write_excel(sheet, st)
# save the workbook
saveWorkbook(wb, "chapter5/styledTables_test.xlsx")

这段 R 代码使用了几个库(TidyDensitystyledTablesxlsx),从数据集创建样式化的表格,将其保存到 Excel 文件中,并对其应用一些格式。让我们一步一步地分解代码:

  1. 首先,我们加载所需的库——TidyDensity 用于从高斯分布创建随机数据表,styledTables 用于格式化表格,以及 xlsx 用于处理 Excel 文件。

  2. 然后,我们创建并格式化表格。此代码使用 tidy_normal() 函数的输出创建了一个样式化的表格 sttidy_normal() 函数从高斯分布生成一些数据,并以 tibble 格式呈现。然后,使用 styled_table() 函数并设置 keep_header = TRUE 来格式化表格,这意味着标题行将被保留并单独格式化。接下来的三行代码为表格的第一行(标题行)应用特定的样式。它为第一行的所有单元格设置边框,使第一行的文本加粗,并将第三列的单元格填充颜色(#00FF00,绿色)设置为对应列的值(用 X 表示)大于或等于 0.5 的情况。

  3. 然后,我们使用 xlsx 包通过创建一个新的工作簿并使用 createWorkbook() 函数来创建一个新的 Excel 工作簿和工作表。一旦创建了这个工作簿,我们使用 createSheet() 函数在具有 tidy_normal 名称的工作簿中创建工作表。

  4. 接下来,我们使用 styledTables 库中的 write_excel() 函数将样式化的表格插入到工作表中。这会将样式化的表格 st 放入 tidy_normal 工作表中。

  5. 最后,我们使用 saveWorkbook() XLSX 函数将工作簿保存为 Excel 文件,我们告诉它将 wb 工作簿保存到名为 styledTables_test.xlsx 的子目录中。

总结来说,这段 R 代码从一些数据(从 tidy_normal() 获取)生成一个样式化的表格,对标题行和第三列的单元格应用特定的格式化,将样式化的表格保存到 Excel 文件中,并将其放置在名为 tidy_normal 的工作表中。生成的 Excel 文件将包含具有指定格式的样式化表格。

在 R 中安装和使用 basictabler

basictabler R 包提供了一个简单的方法,可以从 DataFrame 或矩阵创建丰富的表格。这些表格可以渲染为 HTML、HTML 小部件或 Excel 工作表。

要创建一个 basictabler 对象,你需要创建一个 DataFrame 或矩阵。一旦你有数据,你可以通过调用 qhtbl() 函数来创建一个 basictabler 对象。qhtbl() 函数接受两个参数:DataFrame 或矩阵,以及一个格式化选项列表。我们将花费时间在 qhtbl() 函数和 BasicTable() 函数上。qhtbl() 函数是生成表格的一种快速方式,而 BasicTable() 函数是逐步构建表格的方式。首先,我们将使用 qhtbl() 函数创建一个非常基础的示例,如下所示:

# Load in the library
library(basictabler)
# Create a data frame
data <- data.frame(
  name = c("John Doe", "Jane Doe"),
  age = c(30, 25),
  salary = c(100000, 50000))
# Create a Plain table
table_plain <- qhtbl(data, theme = "largeplain")
table_plain

下面是代码的输出:

图 5.1 – 使用 basictabler 创建普通表格

图 5.1 – 使用 basictabler 创建一个普通表格

现在我们已经看到了它的样子,让我们回顾一下刚才发生了什么。首先,我们创建了一个名为data的数据集。这是一个简单的小数据集,纯粹是为了帮助说明basictabler包的使用。一旦数据创建完成,我们只需在数据上调用ghtbl()函数,给它一个largeplain的主题,并将其分配给table_plain变量。这仅仅创建了一个表格 – 它不会将其发送到 Excel。我们稍后会讨论这一点。

现在,让我们看看另一个稍微复杂一点的例子:

# Create a basictabler object
table <- qhtbl(data,
  theme = "largeplain",
  tableStyle = list("border-color" = "maroon"),
  headingStyle = list(
    "color" = "cornsilk", "background-color" = "maroon",
    "font-style" = "italic", "border-color" = "maroon"
  ),
  cellStyle = list(
    "color" = "maroon", "background-color" = "cornsilk",
    "border-color" = "maroon"
  )
)
# Render the table to HTML
table

这段代码将生成一个包含相同数据的表格。然而,这里的区别在于这个表格将有一些样式。让我们回顾一下我们使用的样式选项;然后,我们将看到最终的产品。

第一个区别在于我们使用了tableStyle选项。这个函数的参数接受一个 CSS 样式声明列表对象,这些样式将被应用到表格上。对于这个选项,我们提供了"border-color" = "maroon"的值。

我们使用的下一个选项是headingStyle,它也接受一个 CSS 样式声明列表对象,这些样式将被应用到表格的标题上。在先前的代码中,我们在列表中使用了四个不同的选项。首先,我们选择了使用color选项,其值为cornsilk,然后我们选择了background-color,其值为maroon。接下来的选项是我们选择了font-style用于italics,最后是border-color,其值为maroon。让我们看看这会是什么样子:

图 5.2 – 使用一些不同样式的第二个 basictabler 示例

图 5.2 – 使用一些不同样式的第二个 basictabler 示例

现在,让我们通过一个更长的例子来了解如何使用basictabler包的不同功能,根据我们指定的某种逻辑映射样式。参考以下代码:

# A longer example
library(TidyDensity)
tn <- tidy_normal(.n = 10)

library(TidyDensity)TidyDensity包导入 R 环境。这个包提供了可视化和总结分布的工具。我们特别使用它来生成一个包含 10 个点的正态分布的 tibble。我们不需要调用basictabler,因为此时它已经加载了。

接下来,我们分配tn <- tidy_normal(.n = 10)。这一行通过从标准正态分布中生成 10 个随机点来创建一个名为tn的数据集。该函数还创建了数据的密度(dxdy),以及pnormqnorm作为表格的列:

tbl <- BasicTable$new()
# formatting values (explained in the introduction vignette)
columnFormats <- list(
  NULL, NULL, "%.4f", "%.4f", "%.4f", "%.4f", "%.4f"
)

tbl <- BasicTable$new()创建了一个名为tblBasicTable对象的新实例。BasicTable类是来自basictabler包的R6类对象。这个函数与许多不同的公共方法相关联。这些方法帮助创建表格本身及其样式:

tbl$addData(tn,
  firstColumnAsRowHeaders = TRUE,
  explicitColumnHeaders = c(
"Simulation", "x", "y", "dx", "dy", "p", "q"
  ),
  columnFormats = columnFormats
)

从前面的代码片段中,我们理解到以下内容:

  • tbl$addData(tn, ...): 这一行将 tn 数据集中的数据添加到 tbl 表格对象中。它还设置了一些数据应如何显示的选项,例如使用第一列作为行标题,并显式设置列标题。

  • columnFormats <- list(...): 在这里,创建了一个名为 columnFormats 的列表,其中包含表格每一列的格式。指定的格式是针对第二列到第七列(索引 1 到 6),并使用 strings.tbl$renderTable() 表示。在这里,我们使用了 %.4f

  • tbl$renderTable(): 这一行根据之前提供的数据和格式渲染表格,并在 R 环境中显示它。这为我们提供了必要的预样式表格,以便我们可以看到基本表格与我们对其所做的修改。

接下来,我们有以下代码:

# Add some conditional formatting
cells <- tbl$getCells(
rowNumbers = 2:11,
columnNumbers = 3:7,
matchMode = "combinations"
)

在这里,cells <- tbl$getCells(...) 行从 tbl 表格对象中检索一个子集的单元格。它使用 getCells() 方法从第 2 行到第 11 行和第 3 列到第 7 列(ydxdypq)选择单元格:

tbl$mapStyling(
  cells = cells,
  styleProperty = "background-color",
  valueType = "color",
  mapType = "logic",
  mappings = list(
    "v<=-3", "red",
    "-3<v<=-2", "orange",
    "-2<v<=-1", "pink",
    "-1<v<= 0", "white",
    "0<v<=1", "white",
    "1<v<=2", "lightgreen",
    "2<v<=3", "lightblue",
    "3<v", "green"
  )
)

tbl$mapStyling(...) 行对所选单元格应用条件格式化。mapStyling() 方法用于根据某些条件将样式(如背景颜色)映射到单元格值:

tbl$renderTable()

在应用条件格式化后,tbl$renderTable() 行渲染了带有格式化单元格的更新后的表格,并将其再次显示在 R 环境中。

总结一下,前面的 R 代码导入了一个包,创建了一个随机数字的数据集,生成了一个带有格式化数据的表格,显示了表格,对特定单元格应用了条件格式化,并最终再次显示带有格式化单元格的表格。条件格式化根据指定列中的值将不同的背景颜色分配给单元格。

现在,让我们看看我们创建了什么。请记住,由于值是随机的,您得到的数据可能与我不同。首先,我们将查看普通表格,然后是样式化表格:

图 5.3 – BasicTable R6 普通表格

图 5.3 – BasicTable R6 普通表格

下面的表格是根据 mapStyling() 函数中创建的逻辑样式化的:

图 5.4 – BasicTable R6 样式化表格

图 5.4 – BasicTable R6 样式化表格

现在我们已经创建了表格,让我们看看如何使用 basictabler 包将它们保存到 Excel 文件中。首先,我们将依赖于之前介绍过的包:openxlsx

下面是我们将要使用的脚本;您会注意到使用了 chapter5 目录,因为它是最先创建的:

# Write styled table out to Excel
library(openxlsx)
# Create Workbook
wb <- createWorkbook()
# Add a sheet called Data
addWorksheet(wb, "Data")
# Use basictabler to write the tbl to excel
tbl$writeToExcelWorksheet(
  wb = wb,
  wsName = "Data",
  topRowNumber = 1,
  leftMostColumnNumber = 1,
  applyStyles = TRUE
  )
# Use openxlsx to save the file
saveWorkbook(
  wb,
  file="chapter5/basictabler_excel.xlsx",
  overwrite = TRUE
)

在这里,我们使用了 basictabler 包的 writeToExcelWorksheet() 的公共方法。虽然它不会直接写入 Excel 文件,但它将对象格式化为可以使用 openxlsx 等包写入 Excel 的格式。

现在,您已经了解了在 R 中编写的一些可能性,让我们来看看 Python 中的类似工具。我们将再次回顾如何为 Excel 格式化单元格和表格。有关更多详细信息,您可以查看一些额外的包,如 gtgtextras

使用 Python 的格式化高级选项

本章的 Python 部分分为以下三个部分:

  • 单元格格式化:单元格格式化对于以视觉吸引力和组织化的方式展示数据至关重要。我们将演示如何将各种格式化样式应用于单元格,例如设置字体属性(例如,大小、颜色、粗体和斜体)、调整单元格背景颜色以及调整单元格内的文本对齐。您将学习如何创建具有良好格式化单元格的专业表格,从而增强数据的可读性。

  • 条件格式化:条件格式化允许您根据特定条件动态地格式化单元格。我们将向您介绍如何应用条件格式化来突出显示重要数据点、可视化趋势和识别异常值。您将了解如何使用 pandasopenpyxl 实现各种条件格式化规则,例如颜色刻度、数据条和图标集,使您的数据在 Excel 工作表中更加突出。

  • 数据透视表:数据透视表是 Excel 中用于汇总和分析数据的强大工具。我们将向您展示如何使用 pywin32 创建数据透视表,以及如何调整小计和总计、自定义标签和样式。

在本章中,我们将提供实际示例和详细解释,指导您有效地格式化 Excel 工作表。通过掌握单元格格式化、条件格式化和数据透视表,您将能够专业地展示您的数据,使其视觉上引人注目,从而促进更好的洞察力和数据分析。

让我们开始单元格格式化!

单元格格式化

单元格格式化是有效地在 Excel 中展示数据的关键方面。使用 pandasopenpyxl,您拥有强大的工具来自定义单元格的外观。您可以应用广泛的各种格式化样式,使您的表格视觉上吸引人并增强数据的可读性。

要开始单元格格式化,您将学习如何设置各种字体属性,例如字体大小、颜色、粗体和斜体。这些调整允许您强调某些数据点,并在您的表格中创建一致的视觉层次结构。

此外,您还可以控制单元格的背景颜色以分组相关数据或突出特定值。通过设置单元格背景颜色,您可以在表格的不同部分之间创建清晰的界限,使读者更容易理解数据。

在单元格内对齐文本是另一种重要的格式化技术。使用pandasopenpyxl,您可以水平垂直地对齐文本,确保您的数据以整洁有序的方式呈现。

在本节中,我们将通过使用pandasopenpyxl的单元格格式化实际示例来引导您。您将学习如何应用不同的格式化样式、调整字体属性、更改单元格背景颜色以及在单元格内对齐文本。掌握这些技能后,您将能够创建专业外观的表格,有效地传达您数据的信息和洞察。

设置字体属性

让我们先探讨如何使用pandasopenpyxl设置单元格的字体属性。

pandas中,为了进行更高级的样式设置,包括自定义 CSS 样式,我们可以使用Styler.apply方法,结合自定义函数来格式化单元格,以应用字体属性以符合我们的偏好,如下所示:

# import pandas
import pandas as pd
data = {'Name': ['John', 'Alice', 'Michael'],
        'Age': [25, 30, 22],
        'City': ['New York', 'London', 'Paris']}
df = pd.DataFrame(data)
# Define a function to apply font properties
def apply_font_properties(value):
    return 'font-weight: bold; font-size: 14px; font-style: italic; color: blue'
# Applying font properties
styled_df = df.style.applymap(apply_font_properties, subset='Name')
# Save the styled DataFrame to an Excel file
styled_df.to_excel('styled_table_pandas.xlsx', index=False)

本章的 GitHub 仓库中提供了生成的 Excel 工作表。

openpyxl中,您可以使用Font类来设置字体属性。例如,要使文本加粗,可以将字体对象的bold属性设置为True。您还可以调整其他字体属性,如sizecolor,以实现所需的格式。请参考以下示例:

# OpenPyXL example for setting font properties
from openpyxl import Workbook
from openpyxl.styles import Font
wb = Workbook()
ws = wb.active
# Applying font properties
font = Font(size=14, bold=True, italic=True, color='0000FF')
ws['A1'].font = font
ws['A1'] = 'Name'
ws['B1'] = 'Age'
ws['C1'] = 'City'
wb.save('styled_table_openpyxl.xlsx')

单元格背景颜色

更改单元格的背景颜色是另一种有助于在表格中视觉区分不同部分的格式化技术。在pandas中,您可以使用Styler对象设置background-color CSS 样式,如下所示:

# Pandas example for cell background colors
import pandas as pd
data = {'Name': ['John', 'Alice', 'Michael'],
        'Age': [25, 30, 22],
        'City': ['New York', 'London', 'Paris']}
df = pd.DataFrame(data)
# Create a styler object
styled_df = df.style
# Define the style for the cells
styled_df = styled_df.applymap( \
    lambda _: 'background-color: yellow', \
    subset=pd.IndexSlice[0, ['Name', 'Age']])
# Save the styled DataFrame to an Excel file
styled_df.to_excel('colored_table_pandas.xlsx', index=False)

之前的代码演示了如何使用pandas创建包含一些样本数据的DataFrame,然后应用DataFrame中特定单元格的背景颜色。该DataFrame包含有关个人姓名、年龄和城市的信息。通过使用pandasStyler对象,我们可以为特定单元格定义背景颜色。在此示例中,第一行的NameAge列使用黄色背景颜色突出显示。最后,将格式化的DataFrame保存到名为colored_table_pandas.xlsx的 Excel 文件中。这种技术允许在从 Python 导出到 Excel 时轻松灵活地格式化单元格。

现在,让我们看看如何使用openpyxl实现类似的效果!

openpyxl中,您可以使用Fill类设置单元格的背景颜色,如下所示:

# openpyxl example for cell background colors
from openpyxl import Workbook
from openpyxl.styles import PatternFill
wb = Workbook()
ws = wb.active
# Applying cell background colors
yellow_fill = PatternFill(start_color='FFFF00', end_color='FFFF00', fill_type='solid')
ws['A1'].fill = yellow_fill
ws['A1'] = 'Name'
ws['B1'] = 'Age'
ws['C1'] = 'City'
wb.save('colored_table_openpyxl.xlsx')

在单元格内对齐文本

正确地在单元格内对齐文本可以显著提高表格的视觉表现。在pandas中,您可以使用Styler对象应用文本对齐样式:

# Pandas example for aligning text within cells
import pandas as pd
data = {'Name': ['John', 'Alice', 'Michael'],
        'Age': [25, 30, 22],
        'City': ['New York', 'London', 'Paris']}
df = pd.DataFrame(data)
# Applying text alignment
alignment_styles = {'text-align': 'center'}
styled_df = df.style.set_properties( \
    subset=['Name', 'Age', 'City'], **alignment_styles)
styled_df.to_excel('aligned_table_pandas.xlsx', index=False)

使用此代码,DataFrame中指定列的文本将居中对齐。此代码使用set_properties方法将文本对齐应用于指定列。然后,将生成的DataFrame保存到名为aligned_table_pandas.xlsx的 Excel 文件中。

openpyxl中,你可以使用Alignment类设置文本对齐,如下所示:

# OpenPyXL example for aligning text within cells
from openpyxl import Workbook
from openpyxl.styles import Alignment
wb = Workbook()
ws = wb.active
# Applying text alignment
alignment = Alignment(horizontal='center', vertical='center')
ws['A1'].alignment = alignment
ws['A1'] = 'Name'
ws['B1'] = 'Age'
ws['C1'] = 'City'
wb.save('aligned_table_openpyxl.xlsx')

通过这些示例,你已经学会了如何使用pandasopenpyxl自定义单元格格式,设置字体属性,更改单元格背景颜色,并在单元格内对齐文本。通过利用这些格式化选项,你可以创建视觉上吸引人且信息丰富的表格,有效地在 Excel 中展示你的数据。

现在,我们继续深入探讨条件格式化。

条件格式化

条件格式化是 Excel 中的一个强大功能,允许你根据特定条件自动应用单元格格式。它使你能够视觉上突出重要数据,识别趋势,并使你的 Excel 表更具交互性。在本章中,我们将探讨如何使用openpyxl实现条件格式化。我们将涵盖各种场景,例如根据值范围、文本和日期标准突出显示单元格。此外,我们还将演示如何创建定制的条件格式化规则以满足你的特定需求。

到本章结束时,你将具备直接从 Python 中为 Excel 表添加动态和视觉上吸引人的条件格式的技能。让我们深入探讨,学习如何通过条件格式化让你的数据脱颖而出!

使用条件格式化可视化数据

通过对你的 Excel 表应用条件格式化,你可以有效地可视化你的数据,并一眼获得宝贵的洞察。例如,你可以突出显示列中的最高和最低值,根据特定类别着色单元格,或强调随时间的变化。

条件格式化在处理大型数据集时特别有用,因为它允许你快速识别关键信息并做出基于数据的决策。

openpyxl提供了在 Excel 表中实现条件格式化的功能。该库提供了一系列选项,可以根据特定条件应用不同的格式化样式。使用openpyxl进行条件格式化的过程涉及以下步骤:

  1. openpyxl导入所需的模块并将你的数据加载到工作簿对象中。

  2. 使用openpyxl.formatting.rule创建一个条件格式化规则。

  3. 定义规则的条件,例如根据单元格值、文本或日期标准应用样式。

  4. 使用openpyxl.worksheet.conditional.ConditionalFormatting.add()将规则应用于所需的单元格范围。

使用openpyxl,你可以轻松实现条件格式化规则并为你的 Excel 表添加视觉提示,增强数据的展示并便于数据分析。

让我们看看一些实现上述概念的代码示例:

import pandas as pd
import openpyxl
from openpyxl.formatting.rule import ColorScaleRule, CellIsRule
# Create some sample data
data = {'Name': ['John', 'Alice', 'Michael', 'Emily'],
        'Age': [25, 30, 22, 28],
        'City': ['New York', 'London', 'Paris', 'Sydney'],
        'Sales': [1000, 800, 1200, 900]}
df = pd.DataFrame(data)
# Write the DataFrame to a worksheet
df.to_excel("conditional_formatting.xlsx", index=False)
# Load the workbook
wb = openpyxl.load_workbook('conditional_formatting.xlsx')
ws = wb.active
# Define conditional formatting rule for red text
red_text_rule = CellIsRule( \
    operator="lessThan", formula=["1000"], stopIfTrue=True, \
    font=openpyxl.styles.Font(color="FF0000"))
ws.conditional_formatting.add(f"D2:D{len(df)+1}", red_text_rule)
# Define the condition for the green fill color scale
min_sales = min(df['Age'])
max_sales = max(df['Age'])
green_fill_rule = ColorScaleRule( \
    start_type='num', start_value=min_sales, start_color='0000FF00', \
    end_type='num', end_value=max_sales, end_color='00FFFF00')
ws.conditional_formatting.add(f"B2:B{len(df)+1}", green_fill_rule)
# Save the Excel workbook
wb.save('conditional_formatting.xlsx')

在此代码中,我们从一个pandas DataFrame创建一个 Excel 工作簿。然后,我们定义两个条件格式化规则:如果Sales值小于1000,则使用红色文本,而green_fill_rule使用Age列的最小和最大年龄值来设置颜色刻度条件。这样,Age列中的单元格将根据它们在最小和最大值之间的相对值填充绿色。这些规则被添加到工作表的conditional_formatting属性中。最后,我们保存 Excel 工作簿,当您使用 Microsoft Excel 打开 Excel 文件时,将应用条件格式化。

自定义条件格式化规则为您提供对数据显示方式的精确控制,使您更容易在 Excel 表格中识别模式、趋势和异常。

接下来,我们将介绍一个条件格式化可以真正大放异彩的案例研究:一个动态热力图!

案例研究 - 使用条件格式化动态热力图

为了进一步展示条件格式的强大功能,我们将通过一个案例研究来展示如何使用 Python 和 Excel 创建一个动态热力图。我们将使用条件格式化根据数据的幅度来着色热力图中的单元格,使我们能够有效地可视化数据的强度和模式。由于表中除了热力图的颜色外,还有注释(数字),因此这里创建的也被称为高亮表

让我们来看看这样一个热力图的实现:

import pandas as pd
import openpyxl
from openpyxl.utils.dataframe import dataframe_to_rows
from openpyxl.formatting.rule import ColorScaleRule
# Sample data for the heatmap
data = {
    'Category': ['A', 'B', 'C', 'D'],
    'Jan': [10, 20, 30, 40],
    'Feb': [15, 25, 35, 45],
    'Mar': [12, 22, 32, 42],
    'Apr': [18, 28, 38, 48]
}
# Convert data to a pandas DataFrame
df = pd.DataFrame(data)
# Write the DataFrame to a worksheet
df.to_excel("heatmap_with_conditional_formatting.xlsx", index=False)
# Load the workbook
wb = openpyxl.load_workbook( \
    'heatmap_with_conditional_formatting.xlsx')
ws = wb.active
# Define the range for conditional formatting (excluding the 'Category' column)
data_range = f'B2:E{len(df) + 1}'  # Adjust the range based on the DataFrame size
# Apply color scale conditional formatting to the range
color_scale_rule = ColorScaleRule(start_type='min', \
    start_color='FFFFFF', end_type='max', end_color='FF0000')
ws.conditional_formatting.add(data_range, color_scale_rule)
# Save the workbook
wb.save('heatmap_with_conditional_formatting.xlsx')

条件格式化是增强 Excel 中数据视觉表示的有价值工具。无论您是使用pandas还是openpyxl,都可以轻松实现条件格式化规则,根据指定的条件动态格式化单元格。通过将条件格式化纳入您的 Excel 表格中,您可以创建引人入胜的视觉图表,更好地理解您的数据,使数据分析和管理决策更加高效和有效。

交叉表

交叉表是 Excel 中强大的工具,允许您快速总结和分析大量数据集。它们提供了一种灵活的方式来聚合、分组和计算数据,只需几点击就能从您的数据中获得有价值的见解。在本节中,我们将探讨如何使用pywin32从 Python 创建和操作交叉表。此外,我们还将介绍一些调整小计和总计以及自定义标签和样式的技术。

使用 pywin32 创建交叉表

pywin32允许您通过 COM 接口与 Microsoft Excel 交互。使用这个库,您可以控制 Excel 的功能,包括创建交叉表。

要在 Python 中使用win32com.client创建交叉表,您可以使用本节提供的代码片段。

首先,通过导入所需的模块、启动 Excel 实例(就像我们在第三章中所做的那样)以及获取我们可以操作的工作表来设置一切:

# Import the required modules from the `win32com.client` package:
import win32com.client as win32
import os.path
# Create a new instance of Excel and make it visible:
excel = win32.Dispatch('Excel.Application')
excel.Visible = True
# Create a new workbook or open an existing one:
workbook = excel.Workbooks.Add()  # Create a new workbook
# Or to open an existing workbook:
# workbook = excel.Workbooks.Open('path/to/your/workbook.xlsx')
# Get the reference to the sheet where you want to create the Pivot Table:
sheet = workbook.ActiveSheet  # Get the active sheet
# Or specify the sheet by its name:
# sheet = workbook.Sheets('Sheet1')

接下来,生成一些示例数据并将其写入工作表(这是可选的;也就是说,只有当您有要分析的数据时才这样做):

# Sample data
data = [
    ['Product', 'Category', 'Sales'],
    ['Product A', 'Category 1', 100],
    ['Product B', 'Category 2', 200],
    ['Product C', 'Category 1', 150],
    ['Product D', 'Category 2', 50],
    # Add more data rows here...
]
# Write the data to the sheet
for row_index, row in enumerate(data, start=1):
    for col_index, value in enumerate(row, start=1):
        sheet.Cells(row_index, col_index).Value = value

有趣的事实

当这个嵌套的 for 循环运行时,您可以看到工作簿填充值!

现在,我们可以开始实际的透视表了!我们将从创建一个新工作表开始,该工作表将用于放置透视表:

# Add a new worksheet to the workbook to hold the Pivot Table:
pivot_table_sheet = workbook.Worksheets.Add()
pivot_table_sheet.Name = 'Pivot Table'

接下来,我们可以通过使用工作簿的 PivotCaches 属性的 Create() 方法然后调用 CreatePivotTable() 来创建数据透视表本身:

# Create a Pivot Cache using the data range (UsedRange highlights the whole used range in the sheet):
pivot_cache = workbook.PivotCaches().Create(SourceType=1, \
    SourceData=sheet.UsedRange)
# Create the Pivot Table on the new sheet using the Pivot Cache:
pivot_table = pivot_cache.CreatePivotTable( \
    TableDestination=pivot_table_sheet.Cells(3, 1), \
    TableName='MyPivotTable')

在定义了数据透视表之后,我们可以添加我们想要用作行、列和数据字段的字段:

# Add fields to the Pivot Table, specifying their orientation (rows, columns, data, etc.):
pivot_table.PivotFields('Product').Orientation = 1 # row field
pivot_table.PivotFields('Category').Orientation = 2 # column field
pivot_table.PivotFields('Sales').Orientation = 4 # data field

我们几乎完成了!我们现在有一个工作表,但我们可能想要开关总计数和子计数:

# Control row and column grandtotals
pivot_table.ColumnGrand = False
pivot_table.RowGrand = False
# Decide which fields have Subtotals
pivot_table.PivotFields('Sales').Subtotals = [False]*12
pivot_table.PivotFields('Product').Subtotals = [False]*12
pivot_table.PivotFields('Category').Subtotals = [True]*12

最后,我们可以自定义标签和样式:

# Customize labels and styles
pivot_table.ShowTableStyleRowStripes = True
pivot_table.PivotFields('Product').Caption = 'Product Name'
pivot_table.PivotFields('Sales').NumberFormat = '#,##0'
pivot_table.PivotFields('Sales').Caption = 'Total Sales'
# Note: labels change the Pivot Table wizard available when clicking into the Pivot Table, not the table itself.
# Save the workbook and close Excel:
 # Note: you will want to change the path to a path that exists on your computer.
file_path = os.path.join('C:' + os.sep, 'Users', 'david_1q5aypk', 'Extending-Excel-with-Python-and-R')
workbook.SaveAs(os.path.join(file_path, 'pivot_table.xlsx'))
workbook.Close()
excel.Quit()

这样,您就学会了如何使用 win32com.client 在 Excel 中创建数据透视表,这使您能够有效地分析和总结数据。该库允许您完全控制 Excel,包括根据您特定的数据分析需求创建和自定义数据透视表。

摘要

在本章中,我们深入探讨了格式化 Excel 工作表的艺术,以以视觉上吸引人和有组织的方式展示数据。分为三个部分,我们涵盖了将原始数据转换为专业外观表格的基本技术,这些表格增强了数据的可读性。

第一部分专注于单元格格式化,我们展示了如何将各种样式应用于单元格,例如调整字体属性、单元格背景和文本对齐。通过掌握单元格格式化,您可以创建组织良好且视觉上吸引人的表格。

接下来,我们探讨了条件格式化,这是一个强大的功能,允许您根据特定条件动态格式化单元格。我们提供了使用 styledTablesbasictabler 为 R 以及使用 pandasopenpyxl 为 Python 实现各种条件格式化规则的实用示例,例如颜色刻度、数据条和图标集,使您的数据脱颖而出并揭示关键见解。

最后,我们发掘了数据透视表潜力,这些是总结和分析数据的不可或缺的工具。使用 pywin32,我们创建了数据透视表,并学习了如何调整子计数和总计数,以及自定义标签和样式。

在本章中,您已经通过使用 styledTablesbasictablerpandasopenpyxlpywin32 在 Excel 操作中获得了宝贵的技能,从而能够专业地展示您的数据,使其视觉上引人注目,并为更明智的决策揭示有意义的见解。有了这些技术,您在数据分析与可视化方面已经准备充分,可以将您的 Excel 熟练程度提升到新的高度。

请期待下一章,插入 ggplot2/matplotlib 图表!在那里,您将学习如何使用 R 和 Python 将美丽的数据可视化添加到您的 Excel 工作表中。

第六章:插入 ggplot2/matplotlib 图表

作为程序员,数据可视化是分析并以更易于访问和直观的方式呈现复杂信息的不可或缺的工具。它们在各个领域都发挥着至关重要的作用,从数据分析和企业智能到科学研究甚至日常决策。可视化对决策有益的一个原因是它们帮助分析师理解数据,以帮助传达有助于决策过程的项目。以下是一些其他原因:

  • 增强理解:可视化提供了清晰简洁的数据表示,使得技术和非技术利益相关者都能更容易地把握复杂的关系、趋势和模式。它们有助于识别异常值、相关性以及可能在原始数据中被忽视的见解。

  • 有效沟通:可视化是一种超越语言障碍的强大沟通工具,它简化了复杂的概念。在会议、演示和报告中以图表、图形和交互式仪表板的形式呈现数据,可以使叙事更具吸引力和说服力。当数据以视觉形式呈现时,它变得更容易消化和理解。例如,桑基图有助于使从起点到终点的数据流可视化变得易于消化。

  • 地理空间分析:地理数据可视化使得更深入的探索成为可能。

流行数据可视化的例子包括用于时间序列分析的折线图、用于分类数据比较的条形图和饼图、用于相关性分析的散点图、用于多元比较的气泡图以及用于地理空间数据表示的等值线图。

总结来说,数据可视化对于程序员来说是不可或缺的,因为它们促进了数据理解、沟通、决策和探索,使它们成为当今数据驱动世界中的基本工具。

在接下来的章节中,我们将探讨使用 ggplot2cowplot 构建一些可视化,例如直方图、有序条形图和哑铃图。

在本章中,我们将学习以下主题:

  • 使用 ggplot2 可视化数据

  • 使用 plotnine2matplotlibplotly 图表增强你的 Excel 报告

  • 使用可视化增强 Excel 报告

  • 数据可视化库简介

  • 使用 plotnine(Python 的 ggplot2)创建图表

  • 其他可视化库

  • 在 Excel 中嵌入可视化

技术要求

对于本章,你需要确保安装了几个不同的 R 包。这些包括以下内容:

  • ggplot2 3.4.4

  • cowplot 1.1.3

本章的代码可以在以下链接的 GitHub 上找到:github.com/PacktPublishing/Extending-Excel-with-Python-and-R/tree/main/chapter

一些基础知识

在我们深入本章的核心内容之前,这里有一些事情将有助于我们理解:

  • 有效沟通:可视化是一种强大的沟通工具,它超越了语言障碍并简化了复杂的概念。在会议、演示和报告中以图表、图形和交互式仪表板的形式呈现数据,可以在会议、演示和报告中提供更有说服力和有说服力的叙述。

  • 数据驱动决策:可视化使决策者能够基于数据证据做出判断。当数据以视觉形式呈现时,更容易识别潜在的机会、风险和改进领域,从而做出更明智和有效的决策。

  • 识别趋势和异常:可视化工具使程序员能够快速发现数据中的趋势、变化和异常。这在金融等需要及时识别异常以防止重大财务损失的行业中尤其有价值。

  • 探索性数据分析EDA):在数据分析的探索阶段,数据可视化至关重要。通过创建散点图、直方图、箱线图和热图,程序员可以在进行更深入的分析之前探索数据的分布和关系。

  • 实时监控:在处理不断变化的数据的应用程序中,实时可视化提供了一种动态的方式来监控关键指标并迅速对新兴情况做出反应。

  • 地理空间分析:地理数据可视化,如地图和热图,对于分析基于位置的信息(如客户分布、疾病爆发或环境变化)非常有价值。

  • 预测和预测分析:可视化有助于展示预测模型的结果和趋势,使利益相关者更容易理解潜在的情景并做出主动决策。

  • 交互式报告:交互式可视化允许最终用户自定义和交互数据,创造更个性化的体验并允许更深入的探索。

让我们现在深入了解这些基础知识。

使用 ggplot2 可视化数据

ggplot2 是 R 编程语言中一个强大且广泛使用的可视化包。由 Hadley Wickham 开发,它是 tidyverse 生态系统的一部分。通过 ggplot2,用户可以通过声明式方法创建高质量和可定制的图形,其中图表是通过指定数据、将美学映射到变量以及添加几何形状、统计和主题层来构建的。其图形语法范式允许您轻松创建复杂的可视化,使其成为探索性数据分析和信息展示的热门选择。

在本节中,我们将使用 ggplot2 库和随 R 一起提供的 iris 数据集制作几个图表。我们首先需要做的是安装它并将其加载到当前环境中:

install.packages("ggplot2")
library(ggplot2)

现在我们已经安装并加载了库,我们可以首先看看使用hist()函数并通过循环鸢尾花数据集中Species列的Sepal.Width数据,基础 R 中的图形会是什么样子。

让我们带着解释来看一下剩下的脚本:

hist(iris$Sepal.Width)
par(mfrow = c(2,2))
for (species in unique(iris$Species)) {
  hist(iris$Sepal.Width[iris$Species == species], main = species,
         xlab = species)
}
hist(iris$Sepal.Width, main = "All Species")
par(mfrow = c(1,1))

第一行代码,hist(iris$Sepal.Width),为所有鸢尾花种类的花瓣宽度绘制直方图。鸢尾花数据集内置在 R 中,因此我们不需要使用data()函数来加载它。鸢尾花数据集的Sepal.Width列包含每个花朵的花瓣宽度测量值。hist()函数在指定的列中绘制数据的直方图。

第二行代码,par(mfrow = c(2,2)),告诉 R 将绘图区域分成四个象限。这将允许我们并排绘制四个直方图。

第三行代码,for (species in unique(iris$Species)) {,开始一个for循环。这个for循环将遍历鸢尾花数据集中Species列的唯一值。unique()函数返回一个包含列中所有唯一值的向量。

for循环的主体,hist(iris$Sepal.Width[iris$Species == species], main = species, xlab = species),为当前种类的花瓣宽度绘制直方图。表达式iris$Sepal.Width[iris$Species == species]选择当前种类的花瓣宽度测量值。main参数指定直方图的标题,xlab参数指定 x 轴的标签。

第四行代码,hist(iris$Sepal.Width, main = "All Species"),为所有种类的花瓣宽度绘制直方图。这个直方图绘制在绘图区域的最后一个象限。

第五行代码,par(mfrow = c(1,1)),告诉 R 将绘图区域重置为单个象限。现在我们已经看过了代码,让我们看看输出是什么样子:

f

图 6.1 – 基础 R 直方图

图 6.1 – 基础 R 直方图

现在我们已经完成了基础 R 版本,让我们看看在ggplot2中它会是什么样子:

# Make a histogram of the sepal width for all species
iris |>
ggplot(aes(x = Sepal.Width)) +
  geom_histogram(alpha = 0.328) +
  theme_minimal()
# Make a histogram of the sepal width for each species
iris |>
ggplot(aes(x = Sepal.Width, fill = Species)) +
  geom_histogram(alpha = 0.328) +
  theme_minimal()

第一行代码,iris |> ggplot(aes(x = Sepal.Width)) + geom_histogram(alpha = 0.328) + theme_minimal(),为所有鸢尾花种类的花瓣宽度绘制直方图。鸢尾花数据集内置在 R 中,因此我们不需要使用data()函数来加载它。ggplot()函数是 R 中的一个强大绘图函数,允许我们创建自定义的可视化。aes()函数指定了绘图的美学映射。在这种情况下,我们将花瓣宽度映射到x轴。geom_histogram()函数在指定的列中绘制数据的直方图。alpha 参数指定了直方图中柱子的透明度。theme_minimal()函数将最小主题应用到绘图上。

第二行代码,iris |> ggplot(aes(x = Sepal.Width, fill = Species)) + geom_histogram(alpha = 0.328) + theme_minimal(),为每个物种绘制了花瓣宽度的直方图。aes() 函数中的 fill 参数指定了直方图中条形的填充颜色。在这种情况下,我们使用 Species 列来为直方图中的条形着色。这将使我们能够看到每个物种花瓣宽度的分布。现在我们已经看过了代码,让我们看看输出结果。

这将分为两个图表,因为 ggplot2 对象不是使用 par() 函数以类似的方式绘制的。

这里是第一个图表:

图 6.2 – 所有物种的 Sepal.Width ggplot2 直方图

图 6.2 – 所有物种的 Sepal.Width ggplot2 直方图

这是第二个图表:

图 6.3 – Sepal.Width 的 ggplot2 直方图,按物种填充

图 6.3 – Sepal.Width 的 ggplot2 直方图,按物种填充

现在,在 ggplot2 中并排查看直方图的一种方法是使用 facet_wrap() 函数:

iris |>
  ggplot(aes(x = Sepal.Width, fill = Species)) +
  geom_histogram(alpha = 0.328) +
  facet_wrap(~ Species, scales = "free") +
  theme_minimal()

aes() 函数指定了图表的美学映射。在这种情况下,我们将花瓣宽度映射到 x 轴,将物种映射到条形的填充颜色。geom_histogram() 函数在指定的列中绘制数据的直方图。alpha 参数指定了直方图中条形的透明度。facet_wrap() 函数为 Species 列的每个值创建一个单独的图表。scales = "free" 参数告诉 facet_wrap() 函数允许每个图表的 x 轴和 y 轴比例变化。theme_minimal() 函数将最小主题应用到图表上。代码的输出是一系列三个直方图,每个直方图对应于一种鸢尾花物种。直方图显示了每个物种花瓣宽度的分布。条形的颜色差异使我们能够轻松地看到每个物种花瓣宽度的分布。以下是结果:

图 6.4 – 使用 facet_wrap 的 Sepal.Width ggplot2 直方图

图 6.4 – 使用 facet_wrap 的 Sepal.Width ggplot2 直方图

在本节中,我们学习了如何使用基础 R 和 ggplot2 绘制一些简单的直方图。我们还学习了如何在两种情况下通过物种对直方图进行分面。

我们已经完成了在 ggplot 中的工作,现在是时候看看我们如何通过使用 cowplot 来扩展图表,这可以帮助我们构建更复杂且适合发表的图形。

使用 cowplot 包可视化数据

R 的 cowplot 包提供了许多用于绘制高质量数据的函数。cowplot 包是一个 R 库,它提供了各种功能来帮助创建发表质量的图形。它可以用于以下方面:

  • plot_grid() 函数可以用来将多个图表排列成一个网格,并带有标签和注释

  • align_plots() 函数可以用来对多个绘图的对齐轴和其他元素,使它们看起来一致

  • plot_grid() 函数可以用来混合来自不同绘图框架的绘图,例如 ggplot2 和基础图形

  • ggdraw()draw_*() 函数可以用来向绘图添加注释,例如文本、图像和形状

  • cowplot 包包含几个专为出版物质量图形设计的主题

既然我们已经了解了什么是 cowplot,那么让我们深入第一个例子:

# Install Libraries
install.packages("ggplot2")
install.packages("cowplot")
# Load required libraries
library(ggplot2)
library(cowplot)
# Load the Iris dataset
data(iris)

在前面的代码中,我们安装了 ggplot2cowplot 库;即使它们已经安装,这也会正常工作,但我们将会安装最新版本。

现在,让我们使用一个 for 循环为 iris 数据集中的每个物种创建一个绘图:

# Create separate histograms for each species
histograms <- list()
for (species in unique(iris$Species)) {
  data_subset <- iris[iris$Species == species, ]
  histogram <- ggplot(data_subset, aes(x = Sepal.Width)) +
     geom_histogram(binwidth = 0.1, fill = "lightblue", color = "black") +
     labs(title = paste("Sepal Width Histogram for", species)) +
     labs(x = "", y = "") +
     theme_minimal()
  histograms[[species]] <- histogram
}

让我们一步步简单地分解代码。

histograms <- list() 行创建了一个名为 histograms 的空列表,我们将在这里存储每个物种的直方图。

在下一行,对于 (species in unique(iris$Species)) { ... },循环遍历 Iris 数据集中的每个独特的物种,并对每个物种执行以下步骤。接下来是 data_subset <- iris[iris$Species == species, ];这一行创建了一个 Iris 数据集的子集,只包括与循环中当前物种匹配的行。这有助于我们一次关注一个物种的数据。

histogram <- ggplot(data_subset, aes(x = Sepal.Width)) + ... 这一行是魔法发生的地方。我们正在使用 ggplot2 库创建一个直方图。这就像绘制一个显示有多少花朵具有特定花瓣宽度的图表。aes(x = Sepal.Width) 选项告诉 R 我们对在 x-轴上绘制 Sepal.Width 感兴趣。

第五行,geom_histogram(binwidth = 0.1, fill = "lightblue", color = "black"),向直方图中添加条形。它指定了条形的外观,例如它们的宽度和颜色。这就像构建直方图的列。

labs(title = paste("Sepal Width Histogram for", species)) 这一行向直方图添加了一个标题,告诉我们它是什么。标题根据循环中的当前物种而变化。这就像为每个直方图写一个标签。下一行,labs(x = "", y = ""),移除了 x- 和 y-轴标签,使直方图看起来更干净。然后我们使用 theme_minimal() 添加一个主题到绘图上,这使得直方图的背景简单且干净。最后,histograms[[species]] <- histogram 这一行将当前物种的直方图取出,并将其存储在 histograms 列表中。我们使用物种名称来访问这个直方图。接下来的代码略有不同,但会产生完全相同的绘图:

histograms <- lapply(unique(iris$Species), function(species) {
  data_subset <- iris[iris$Species == species, ]
  histogram <- ggplot(data_subset, aes(x = Sepal.Width)) +
     geom_histogram(binwidth = 0.1, fill = "lightblue", color = "black") +
     labs(title = paste("Sepal Width Histogram for", species)) +
     labs(x = "", y = "") +
     theme_minimal()
  return(histogram)
})

因此,总的来说,这段代码为 iris 数据集中不同物种的萼片宽度创建了直方图。它是通过循环每个物种,为该物种创建数据子集,然后创建具有适当格式和标签的直方图来实现的。所有直方图都存储在一个名为histograms的列表中,因此我们可以稍后使用它们。在这个列表中,每个物种都是一个直方图对象,并且对象是以它所可视化的物种命名的。现在,我们将创建并解释在完整数据集上创建的直方图,然后使用 cowplot 的plot_grid()函数将它们全部组合。以下是代码:

# Create histogram for all species combined
all_species_hist <- ggplot(iris, aes(x = Sepal.Width)) +
  geom_histogram(binwidth = 0.1, fill = "lightblue", color = "black") +
  labs(title = "Sepal Width Histogram for All Species") +
  theme_minimal()
# Arrange histograms using cowplot
plot_grid(
  histograms[["setosa"]],
  histograms[["versicolor"]],
  histograms[["virginica"]],
  all_species_hist,
  ncol = 2,
  align = "hv"
  )

创建all_species_hist变量的第一行代码为所有物种的Sepal.Width列创建直方图。直方图的 binwidth 为0.1,填充颜色为浅蓝色。边框颜色为黑色。直方图的标题为所有物种的萼片宽度直方图。直方图的样式为theme_minimal()

下一条代码,plot_grid(histograms[["setosa"]], histograms[["versicolor"]], histograms[["virginica"]], all_species_hist, ncol = 2, align = "hv"),使用cowplot包将每个物种的直方图排列成网格。直方图以两列排列,并且水平垂直对齐。

plot_grid()函数接受一个包含图表的列表作为其参数。图表根据ncolnrow参数指定的列数和行数排列成网格。align参数指定图表如何相互对齐。在这种情况下,图表通过align = "hv"参数水平垂直对齐。

plot_grid()函数的输出是一个可以保存到文件或显示在 R 控制台中的图表网格。现在,让我们看看最终的输出:

图 6.5 – 使用 cowplot 绘制四个直方图

图 6.5 – 使用 cowplot 绘制四个直方图

现在我们已经看到了如何有效地使用cowplot来组合图表和控制图形的其他部分,我们可以继续到下一种图表类型,条形图和哑铃图。

条形图和哑铃图

条形图和哑铃图都是用于表示数据的可视化类型。以下是每种类型的描述及其优缺点。首先是条形图。条形图,也称为条形图,使用矩形条来比较不同类别的数据。每根条的长度或高度代表特定类别的值。条形图可以垂直或水平绘制,最常见的类型是垂直。条形图的一些优点如下:

  • 易于阅读和理解:条形图简单直观,即使没有统计学或数据可视化背景的人也能轻松理解。

  • 有效的比较工具:条形图允许快速轻松地比较不同类别,这使得它们在识别模式或趋势时非常有用

  • 适用于分类数据:条形图非常适合表示分类或离散变量

这里有一些缺点:

  • 连续数据受限:条形图在表示连续变量或具有许多不同值的 数据方面不如有效

  • 潜在的阅读问题:当条形数量较多或数值接近时,可能难以在图表上准确读取数值

哑铃图,也称为连接点图或范围条形图,比较两个类别或组的数值。它由两个通过线连接的点或标记组成,每个点代表一个值,线表示它们之间的范围。以下是它的优点:

  • 突出差异和比较:哑铃图在强调两个类别或组之间的差异或比较方面非常有效

  • 显示范围和方差:哑铃图中连接点的线代表数值之间的范围或方差,提供了额外的信息

  • 适用于分类或连续数据:哑铃图可以用于有序变量和连续变量

这里有一些缺点:

  • 多比较受限:哑铃图最适合比较两个类别或组。如果有超过两个组,图表可能会变得杂乱且难以理解。

  • 不如条形图或时间序列图常见或熟悉:哑铃图不像条形图或时间序列图那样被广泛使用或认可,这可能会使一些观众感到不熟悉。

总结来说,条形图适用于比较组间数值,而哑铃图适合比较两个类别或组。每种可视化都有其优势和局限性,选择取决于数据的性质和您想要传达的具体见解。

现在我们对不同的图表类型及其优缺点有了些了解,是时候深入探讨如何创建它们并查看输出结果了。

使用 ggplot2 的条形图

条形图可以垂直或水平绘制,其中最常见的类型是垂直。条形图左侧或右侧的垂直轴称为 y 轴,而图表底部的水平轴称为 x 轴。每个条形的高度或长度代表特定数据类别的值。条形图可以轻松地比较不同组之间的不同数据集,并且可以展示一段时间内数据的重要变化。在解释复杂数据的意义时,它们非常有用,因为它们允许快速轻松地比较不同类别。条形图特别适用于展示信息片段,并且常用于以视觉方式展示涉及数据的数据或概念。条形图的一些关键特性包括以下内容:

  • 条形是矩形且宽度相等,高度不同

  • 一个条形与另一个条形之间的间隙应保持均匀

  • 它可以是水平的或垂直的

总体来说,条形图是一种在视觉上快速传达关系信息的有效工具,可以轻松地比较不同组之间的不同数据集。现在我们已基本了解了条形图及其用途,让我们通过使用 ggplot2 库的示例来学习。

首先,让我们加载所需的库,其中 healthyRhealthyR.data 可能需要在您的机器上安装,因为它们可能尚未安装:

library(healthyR.data)
library(healthyR)
library(ggplot2)
library(dplyr)
library(forcats)
library(purrr)

在这里,我们加载了几个提供数据操作函数和工具(dplyrforcatspurrr)以及可视化工具(ggplot2)的包。这些包扩展了 R 处理数据和创建图表的能力。我们加载了 healthyR.data 库以便使用数据集,以及 healthyR 库以便使用 category_counts_tbl() 函数。

下一段代码用于创建我们将要绘制的数据集:

df <- healthyR_data |>
  filter(payer_grouping != '?') |>
  category_counts_tbl(
     .count_col = payer_grouping
     , .arrange = TRUE
     , ip_op_flag
  ) |>
  group_by(ip_op_flag) |>
  mutate(order_var = paste0(
     sprintf("%02i", as.integer(rank(n))),
     " - ",
     payer_grouping
     )) |>
  ungroup()

在这一步,使用管道(|>)对数据进行一系列操作:

  • healthyR_data 是由 healthyR.data 包提供的数据集。

  • filter() 函数删除了 payer_grouping 列不等于 '?`’’ 的行。

  • category_counts_tbl() 函数被应用,该函数计算每个唯一的值在 payer_grouping 列中每个 ip_op_flag 值组合中的出现次数。.count_col 参数指定要计数的列,.arrange 按降序排序计数,而 ip_op_flag 则按此列对数据进行分组。

  • 数据使用 group_by() 函数按 ip_op_flag 列进行分组。

  • mutate() 函数添加了一个名为 order_var 的新列,其中包含基于计数列 n 的格式化排名值。这是通过使用 sprintf() 函数将排名格式化为两位整数来完成的。然后我们取消分组,因为组不再必要。

现在,让我们制作这个图表:

ggplot(df, aes(x = order_var, y = n)) +
  geom_col(alpha = 0.328) +
  labs(x = "", y = "") +
  theme(legend.position = "none") +
  facet_wrap(~ ip_op_flag, scale = "free") +
  scale_x_discrete(
     labels =  with(df, as.character(payer_grouping) |>
                              set_names(order_var))) +
  xlab(NULL) +
  theme(axis.text.x = element_text(
     angle = 90, hjust=1, vjust=.5)) +
  coord_flip() +
  theme_minimal()

本节使用 ggplot2 创建条形图:

  • ggplot() 初始化图表,aes() 指定美学(例如 x 轴和 y 轴上放置的内容)。

  • geom_col() 向图表中添加条形,其中每个条形的高度代表 n 的值。alpha 参数控制条形的透明度。

  • labs() 将轴标签设置为空。

  • theme() 允许进行主题调整,例如移除图例和使用简约主题。

  • facet_wrap() 用于为 ip_op_flag 的每个唯一值创建单独的面板。

  • scale_x_discrete() 用于使用 payer_grouping 值自定义 x 轴标签,按 order_var 索引。

  • xlab(NULL) 移除 x 轴标签。

  • theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = .5)) 调整了 x 轴文本的外观,使其垂直。

  • coord_flip() 翻转 xy 轴。

  • theme_minimal() 将简约主题应用到图表上。

总结来说,这段代码首先对数据集进行筛选和处理,然后创建一个具有多个维度的条形图,每个维度显示基于分类变量计数的条形。图表的外观通过各种 ggplot2 函数和设置进行定制。现在,在完成所有这些之后,让我们看看最终的输出结果:

图 6.6 – 使用 ggplot2 创建条形图

图 6.6 – 使用 ggplot2 创建条形图

在本节中,我们学习了如何制作一个相当复杂的水平条形图。我们创建了一个有序的图表,允许我们按相同的因素列查看两个不同组的信息。它显示了住院和门诊维度的保险支付者组体积。现在,我们将转向双杠图。

ggplot2 的双杠图

双杠图,也称为点线图,是一种显示不同类别之间两点变化的可视化图表。它通常使用点(代表类别)通过线连接来显示变化。在 R 中,你可以使用 ggplot2 等库创建双杠图。下面是如何做到这一点的方法。

首先,请确保你已经安装并加载了 ggplot2dplyr 包。如果需要,你可以使用 install.packages("ggplot2")install.packages("dplyr") 安装它们。

让我们创建一个数据框;我们将使用两列来表示初始值和最终值,以及一个分类变量来对它们进行分组。你的数据可能看起来像这样:

# Sample data
data <- data.frame(
  Category = c("A", "B", "C", "D"),
  Initial = c(10, 15, 8, 12),
  Final = c(18, 22, 14, 16)
)

现在,在我们制作实际图表之前,让我们先创建数据的中点:

data <- data |>
  mutate(Midpoint = (Initial + Final)/2)

现在,我们可以继续创建图表:

# Create the dumbbell plot using ggplot2
dumbbell_plot <- ggplot(data, aes(x = Category, xend = Category, 
    y = Initial, yend = Final)) +
  geom_segment(color = "gray50") +  # Lines connecting dots
  geom_point(color = "blue", size = 3) +  # Initial values
  geom_point(aes(y = Final),
                  color = "orange", size = 3) +  # Final values
  geom_text(aes(label = Midpoint),
                 vjust = -0.5, size = 3) +  # Midpoint labels
  labs(title = "Dumbbell Plot",
         x = "Category",
         y = "Values") +
  theme_minimal()
# Print the plot
dumbbell_plot

此示例假设你的数据框中有一个 Category 列,它定义了组/类别。图表将显示初始值(蓝色点)、最终值(红色点)、连接它们的线以及线上的中点标签。你可以根据你的喜好自定义外观、颜色、标签和其他元素。现在,让我们看看我们创建了什么。

图 6.7 – 使用 ggplot2 创建的双杠图

图 6.7 – 使用 ggplot2 创建的双杠图

请记住,这只是一个基本示例。根据您的数据和需求,您可能需要调整代码以适应您的需求。现在是时候制作一些时间序列图表了。

使用 plotnine2、matplotlib 和 plotly 图表增强您的 Excel 报告

本章的 Python 部分探讨了如何使用 Python 将流行的数据可视化库,如 plotninematplotlibplotly,与 Microsoft Excel 集成。

您将学习如何利用每个库的优势来有效地可视化数据并增强您的 Excel 报告。

本章的这一部分组织如下:

  • 使用可视化增强 Excel 报告:我们将提供有关如何有效地使用可视化来传达洞察力和模式的指导。

  • 可视化库简介:我们将概述关键的可视化库 – plotninematplotlibplotly。了解这些库及其用例对于选择满足您需求的正确库至关重要。

  • 使用 plotnine 创建图表:本节将深入探讨如何使用 plotnine 库制作复杂的图表。您将学习如何生成各种图表类型,自定义视觉元素,并添加额外的层以增强清晰度。

  • 使用 matplotlib 创建图表matplotlib 是一个用于创建静态可视化的多功能库。我们将向您介绍使用 matplotlib 生成不同类型图表的过程,然后将它们转移到 Excel 中以包含在您的报告中。

  • 将可视化嵌入到 Excel 中:本节涵盖了将使用 Python 库生成的图表和图表插入到 Excel 工作表中的实际操作。

到本章结束时,您将具备无缝连接 Python 数据可视化和 Excel 报告的技能。无论您是创建静态图表还是交互式可视化,您都将能够以视觉吸引力和洞察力在 Excel 中展示数据,从而促进更具吸引力和影响力的报告。

让我们开始绘图吧!(现在您可以想象自己发出邪恶的笑声!)

使用可视化增强 Excel 报告

在本章的这一部分,我们深入探讨使用可视化来增强 Excel 报告的实际应用。除了从 Python 生成和嵌入可视化的技术方面之外,我们还将探讨这些辅助工具在数据驱动决策背景下的更广泛意义。Excel 中的可视化不仅仅是关于美观;它们是有效传达隐藏在数据中的洞察力、模式和趋势的强大工具。无论您是为利益相关者、同事还是客户准备报告,掌握融入可视化艺术的技巧都将提升您数据驱动的叙述,并促进更明智的决策。

接下来的部分将提供指导,说明如何在 Excel 报告中战略性地使用可视化以最大化其影响力。你不仅将学习如何创建引人入胜的图表和图形,还将学习如何有效地解释和展示它们,以传达数据的故事。

将可视化集成到 Excel 报告中不仅关乎美观——它关乎将数据转化为能够驱动明智决策的洞察。我们将深入探讨各种策略,通过有效利用可视化来增强报告的影响力。

可视化的力量不仅在于其美学,还在于它们用数据讲述引人入胜故事的能力。通过掌握选择正确可视化类型、利用注释、简化复杂数据以及遵循设计原则的艺术,你将充分准备,将 Excel 报告提升到新的影响力和清晰度水平。

数据可视化库简介

数据可视化是数据分析的基本方面,Python 提供了一套丰富的库来创建引人入胜且信息丰富的可视化。在本节中,我们将向您介绍三个突出的数据可视化库——plotninematplotlibplotly。了解每个库的优势和应用对于在 Excel 报告中有效地传达数据的故事至关重要。

Plotnine – 优雅的图形语法

ggplot2库是 R 编程语言中流行的数据可视化库,以其表达性和声明性语法而闻名。Python 的适配版本称为plotnine

它基于plotnine在创建复杂、出版物质量图表方面表现出色。它提供了对美学的精细控制,使你能够自定义可视化的每一个方面。

Plotly – 交互式可视化

plotly是一个多功能的 Python 库,专注于创建交互式、基于网络的可视化。它允许你构建交互式仪表板、散点图、折线图等。用户可以在数据点上悬停、放大或筛选数据,以实现动态的用户体验。

plotly与 Jupyter 笔记本无缝集成,使其成为数据科学家和分析师的首选。它非常适合为网络应用程序、报告和数据探索生成交互式可视化。

Matplotlib – 经典且可定制的图表

matplotlib是创建 Python 中静态、高质量可视化的基础库。它提供了一系列绘图函数,使其适用于各种图表类型,如折线图、条形图和散点图。

matplotlib高度可定制,允许你控制图表的每一个细节,从颜色和标签到字体和网格线。它是生成用于研究论文、演示文稿和 Excel 报告的定制静态图表的首选选择。

理解这些库的功能和最佳用例将赋予你选择适合你数据可视化需求正确工具的能力。无论你想要使用 plotnine 创建优雅的静态图表,还是使用 plotly 创建交互式仪表板,或者使用 matplotlib 创建高度定制的可视化,你都将拥有选择与你的目标相符的库的知识。

在接下来的章节中,我们将更深入地探讨每个库,提供实际示例和见解,帮助你掌握在 Python 中进行数据可视化的艺术,以便为 Excel 报告制作。

让我们先深入了解 plotnine

使用 plotnine 创建图表(Python 的 ggplot2)

在本节中,我们将探索 Python 中 plotnine 库的强大功能,该库从 R 的 ggplot2 中汲取灵感,如本章 R 部分所述。你会发现(除了 R 和 Python 之间语法差异的考虑之外)代码和功能极其相似——plotnineggplot2 真的是姐妹包。

到本节结束时,你将熟练掌握生成各种可视化、自定义每个细节以及添加额外层以增强清晰度的技能。

理解图形语法

在我们深入探讨使用 plotnine 创建令人印象深刻的图表之前,了解图形语法至关重要。这种结构化的数据可视化方法构成了 plotnine 的核心,并使你能够通过组合数据、美学和几何对象来构建复杂的图表。

让我们分解一些关键概念:

  • plotnine 将数据与图表中的视觉元素相连接。你需要指定哪些变量代表 xy 轴、颜色、形状、大小等。

  • 美学:美学控制数据属性如何以视觉方式表示。你可以使用美学来编码诸如颜色、形状和大小等信息。

  • plotnine 鼓励分层方法。每一层都会为你的图表添加一个新元素,例如点、线或标签。这允许创建复杂且信息丰富的可视化。

生成各种图表类型

plotnine 库的一个优势是其多功能性。你可以创建多种图表类型,满足不同的数据可视化需求。

在本节中,我们将使用 plotnine 展示各种图表类型的构建。

  • 散点图:简单而有效,散点图有助于可视化两个数值变量之间的关系:

    from plotnine import ggplot, aes, geom_point, geom_bar, geom_histogram, geom_boxplot, geom_tile, geom_violin, theme_minimal, labs
    import pandas
    # Sample data
    data = pandas.DataFrame({'x': [1, 2, 3, 4, 5],
                             'y': [2, 4, 1, 3, 5]})
    # Create a scatter plot
    gg = ggplot(aes(x='x', y='y'), data) + geom_point()
    print(gg)
    

    这是前面代码生成的图表:

图 6.8 – 基本散点图

图 6.8 – 基本散点图

  • 条形图:非常适合显示分类数据,条形图在比较方面表现优秀:

    # Sample data
    data = pandas.DataFrame({'category': ['A', 'B', 'C', 'D'],
                             'value': [10, 25, 15, 30]})
    # Create a bar chart
    gg = ggplot(aes(x='category', y='value'), 
        data) + geom_bar(stat='identity')
    print(gg)
    

    这是它的图表:

img/B19142_06_9.jpg

图 6.9 – 基本条形图

  • 直方图:这些用于探索单个变量的分布:

    # Sample data
    data = pandas.DataFrame({'values': [1, 2, 2, 3, 3, 3, 4, 4, 5]})
    # Create a histogram
    gg = ggplot(aes(x='values'), data) + geom_histogram(binwidth=1,
        fill='blue', color='black', alpha = 0.5)
    print(gg)
    

    这是它的图表:

img/B19142_06_10.jpg

图 6.10 – 基本直方图

注意我们如何使用与 R ggplot2 语法完全类似,包括 alpha 参数来控制透明度的语法。这表明 R 和 Python 在某些包中实际上是相似的工具,具有相似的语法!

  • 箱线图:箱线图提供了数据集分布的摘要,包括中位数、四分位数和潜在的异常值:

    # Sample data
    data = pandas.DataFrame({'category': ['A', 'A', 'B', 'B', 'C', 'C'],
                             'value': [10, 15, 20, 25, 30, 35]})
    # Create a box plot
    gg = ggplot(aes(x='category', y='value'), data) + geom_boxplot()
    print(gg)
    

    这是相应的图表:

图 6.11 – 一个基本的箱线图

  • 使用 geom_tile() 来实现这一点:

    data = {
            'x': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'D', 'D', 'D', 'D'],
            'y': ['W', 'X', 'Y', 'Z', 'W', 'X', 'Y', 'Z', 'W', 'X', 'Y', 'Z', 'W', 'X', 'Y', 'Z'],
            'value': [10, 15, 5, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80]
    }
    # Convert data to a DataFrame
    data = pandas.DataFrame(data)
    # Create a heatmap
    gg = (ggplot(data, aes(x='x', y='y', fill='value'))
                + geom_tile()
                + theme_minimal()
                + labs(title='Heatmap Example', x='X-Axis', y='Y-Axis', fill='Values'))
    print(gg)
    

    这是相应的图表:

图 6.12 – 一个基本的热图

图 6.12 – 一个基本的热图

  • 小提琴图:结合箱线图和核密度估计,小提琴图展示了具有丰富细节的数据分布:

    # Sample data
    data = {
            'Category': ['A', 'A', 'B', 'B', 'B', 'C', 'C', 'D', 'D', 'D'],
            'Value': [10, 15, 25, 30, 35, 45, 50, 65, 70, 75]
    }
    # Convert data to a DataFrame
    df = pandas.DataFrame(data)
    # Create a violin plot
    gg = (ggplot(df, aes(x='Category', y='Value', fill='Category'))
                + geom_violin()
                + theme_minimal()
                + labs(title='Violin Plot Example', x='Category', y='Value', fill='Category'))
    print(gg)
    

    这是相应的图表:

图 6.13 – 一个基本的提琴图

现在基础知识已经介绍完毕,让我们看看是什么让 plotnine 如此特别——所有的自定义可能性!

自定义 plotnine 图表的视觉元素

plotnine 库的优势也体现在自定义上。你可以定制视觉呈现的各个方面以满足特定需求。以下是关于如何自定义视觉呈现各个方面的详细说明:

  • 使用 plotnine,你可以使用 xlab()ylab() 函数分别自定义 xy 轴的标签。要为你的图表添加标题和副标题,请使用 ggtitle()labs() 函数:

    # Customize labels and titles
    gg = gg + xlab("Custom X Label") + ylab("Custom Y Label")
    gg = gg + ggtitle("Custom Plot Title") + labs(subtitle="Custom Subtitle")
    
  • scale_x_continuous()scale_y_continuous() 用于自定义刻度和图例:

    # Customize axes and legends
    gg = gg + scale_x_continuous(breaks=[1, 2, 3, 4, 5],
        labels=["One", "Two", "Three", "Four", "Five"])
    gg = gg + scale_y_continuous(limits=(0, 10))
    gg = gg + scale_color_manual(values={'A': 'red', 'B': 'blue'})
    
  • 使用 theme_minimal()theme_light() 来保持报告或演示文稿的整体整洁外观。

    # Apply themes
    # gg = gg + theme_minimal()
    gg = gg + theme_light()
    
  • 使用 theme() 函数调整参数,如 texttext_sizetext_familytext_align 以实现所需的文本格式:

    # Control text formatting
    gg = gg + theme(text=element_text(size=12, family="Arial",
        face="bold", color="black"),
        axis_text_x=element_text(angle=45, hjust=1)
    

    上述自定义设置产生了以下图表:

图 6.14 – 自定义视觉元素

通过自定义这些元素,你可以创建视觉上吸引人且高度定制的视觉呈现,以有效地传达你的数据洞察。

除了自定义之外,plotnine 还有一个绝招——图层!在下一节中,我们将探讨图层是什么以及如何使用它们来呈现最佳的视觉呈现。

添加额外的图层

层叠是 plotnine 中的一个强大概念。它允许你在单个图表上叠加多个图层,每个图层传达数据的不同方面。在本节中,我们将探讨一些常见的图层:

  • 趋势线:添加趋势线以揭示数据中的潜在模式

  • 误差线:通过包含误差线来可视化变异性和不确定性

  • 注释:使用文本标签或几何形状突出显示特定的数据点或区域

要添加误差线,你可以使用以下代码:

from plotnine import (
    ggplot, aes, geom_line, geom_point, geom_errorbar, 
    position_dodge, geom_text, labs, geom_smooth
    )
import pandas
import numpy
# Sample data
data = pandas.DataFrame({
        'x': [1, 2, 3, 4, 5],
        'y': [10, 15, 8, 12, 18],
        'group': ['A', 'A', 'B', 'B', 'C'],
        'error': [1, 2, 1.5, 1, 2.5],
        'label_x': [2, 4, 3, 1, 5],
        'label_y': [16, 11, 6, 13, 17],
        'annotation_text': ['Peak', 'Valley', 'Low', 'High', 'Bottom']
})
# Create a ggplot object
gg = ggplot(data, aes(x='x', y='y', group='group')) + \
        geom_line() + \
        geom_point() + \
        geom_errorbar(aes(ymin='y - error', ymax='y + error'), 
        width=0.1, size=0.5, 
        position=position_dodge(width=0.2)) + \
        geom_text(aes(x='label_x', y='label_y', 
        label='annotation_text'), size=10)
# Draw the plot
print(gg)

这产生了以下图表:

图 6.15 – 添加了误差线

图 6.15 – 添加了误差线

对于趋势线,你可以使用以下方法:

# Sample data
data = pandas.DataFrame({
        'X': numpy.arange(1, 21),
        'Y': numpy.random.randint(1, 101, size=20)
})
# Create a base plot
gg = (ggplot(data, aes(x='X', y='Y')) +
            geom_point() +
            labs(title='Scatter Plot with Trendline')
         )
# Add a trendline
gg = gg + geom_smooth(method='lm', se=False, linetype='dashed',
    color='red', size=1)
print(gg)

这将在图表中添加趋势线:

图 6.16 – 带趋势线的散点图

最后,对于注释,我们有以下内容:

# Sample data
data = pandas.DataFrame({
        'X': numpy.arange(1, 11),
        'Y': numpy.random.randint(1, 101, size=10)
})
# Create a base plot
gg = (ggplot(data, aes(x='X', y='Y')) +
            geom_point() +
            labs(title='Scatter Plot with Annotations')
         )
# Add an annotation and adjust the position of the labels along the y-axis using nudge_y by 5 units
gg = gg + geom_text(aes(label='Y'), nudge_y=5, color='blue')
print(gg)

这会产生以下图表:

图 6.17 – 带注释的散点图

图 6.17 – 带注释的散点图

无论您是传达洞察力、比较数据集还是探索趋势,plotnine都将赋予您为 Excel 报告创建引人入胜且数据驱动的叙述的能力。

接下来,让我们看看使用matplotlib的类似图表!

使用 matplotlib 生成图表

在本节中,我们将深入探讨matplotlib的灵活世界,它是 Python 中最广泛使用的可视化库之一。使用matplotlib,您有权创建一系列静态可视化,精细调整其外观,并按您的特定需求定制。无论您是想制作散点图、条形图、直方图或其他数据图形表示,matplotlib都提供了将您的数据转化为引人入胜的视觉洞察力的工具。

使用 matplotlib 创建多种图表类型

matplotlib因其多功能性而受到赞誉,提供了广泛的图表类型以满足不同的数据可视化需求。在本节中,我们将深入研究使用matplotlib构建各种图表类型,让您能够制作散点图、条形图、直方图、箱线图、热图和小提琴图。无论您是寻求探索变量之间的关系、显示分类数据还是分析数据分布,matplotlib都为您提供了创建所需可视化的工具:

  • 散点图:以下是它们的代码:

    import numpy
    import pandas
    import matplotlib.pyplot as plt
    ### scatter plot
    data = {
            'Height': [155, 162, 168, 173, 179],
            'Weight': [50, 56, 61, 65, 72]
    }
    df = pandas.DataFrame(data)
    # Create a scatter plot
    df.plot.scatter(x='Height', y='Weight', 
        title='Scatter Plot of Height vs. Weight')
    # Save the plot to a file (e.g., .png) in your working directory
    plt.savefig('matplotlib_scatter_plot.png')
    # Show the plot
    plt.show()()
    

    此代码将创建身高与体重的关系散点图,并将其保存为.png图像。您可以根据需要进一步自定义图表。结果如下所示:

图 6.18 – 使用 matplotlib 的基本散点图

图 6.18 – 使用 matplotlib 的基本散点图

  • 条形图:以下是它们的代码:

    data = {'Category': ['A', 'B', 'C', 'D', 'E'],
                    'Values': [15, 28, 24, 20, 32]}
    df = pandas.DataFrame(data)
    # Create a basic bar chart
    plt.figure(figsize=(8, 6))
    plt.bar(df['Category'], df['Values'], color='skyblue')
    plt.xlabel('Categories')
    plt.ylabel('Values')
    plt.title('Basic Bar Chart')
    # Save the plot to a file (e.g., .png)
    plt.savefig('matplotlib_bar_chart.png')
    plt.show()
    

    此代码创建了一个简单的条形图,类别在x轴上,相应的值在y轴上,结果如下:

图 6.19 – 使用 matplotlib 的基本条形图

图 6.19 – 使用 matplotlib 的基本条形图

  • 直方图:以下是它们的代码:

    # Generate some random data for the histogram
    data = numpy.random.normal(0, 1, 1000)
    # Create a basic histogram
    plt.figure(figsize=(8, 6))
    plt.hist(data, bins=20, color='lightblue', edgecolor='black')
    plt.xlabel('Values')
    plt.ylabel('Frequency')
    plt.title('Basic Histogram')
    # Save the plot to a file (e.g., .png)
    plt.savefig('matplotlib_histogram.png')
    plt.show()
    

    此代码从随机数据生成直方图,展示了值的频率分布。您可以调整箱数、颜色、标签和其他属性以根据需要自定义直方图。生成的直方图如下所示:

图 6.20 – 使用 matplotlib 的基本直方图

图 6.20 – 使用 matplotlib 的基本直方图

  • 箱线图:以下是它们的代码:

    # Generate some random data for the box plot
    data = [numpy.random.normal(0, 1, 100) for _ in range(3)]  # Three sets of random data
    # Create a basic box plot
    plt.figure(figsize=(8, 6))
    plt.boxplot(data, vert=False, 
        labels=['Set 1', 'Set 2', 'Set 3'])
    plt.xlabel('Values')
    plt.ylabel('Data Sets')
    plt.title('Basic Box Plot')
    # Save the plot to a file (e.g., .png)
    plt.savefig('matplotlib_boxplot.png')
    plt.show()
    

    此代码从随机数据生成基本箱线图,比较三个不同的数据集。您可以调整各种参数以根据需要自定义箱线图的外观。前面的代码产生以下可视化:

图 6.21 – 使用 matplotlib 的基本箱线图

图 6.21 – 使用 matplotlib 的基本箱线图

  • 热图:以下是它们的代码:

    # Generate some random data for the heatmap
    numpy.random.seed(42)
    data = numpy.random.rand(5, 5)  # Create a 5x5 matrix of random values
    # Create a heatmap
    plt.figure(figsize=(8, 6))
    heatmap = plt.imshow(data, cmap='viridis', 
        interpolation='nearest')
    plt.colorbar(heatmap)
    plt.title('Heatmap Example')
    # Save the plot to a file (e.g., .png)
    plt.savefig('matplotlib_heatmap.png')
    plt.show()
    

    在此代码中,我们生成一个随机的 5x5 矩阵值并从中创建一个热图。我们将使用 viridis 色彩映射,但您可以从各种色彩映射中选择以调整颜色方案。此示例演示了如何创建基本热图;您可以根据数据和偏好进一步自定义它。结果热图如下所示:

图 6.22 – 使用 matplotlib 的基本热图

图 6.22 – 使用 matplotlib 的基本热图

  • 小提琴图:以下是它们的代码:

    # Generate some random data for the violin plot
    numpy.random.seed(42)
    data = [numpy.random.normal(0, std, 100) for std in range(1, 4)]
    # Create a violin plot
    plt.figure(figsize=(8, 6))
    plt.violinplot(data, showmedians=True)
    plt.title('Violin Plot Example')
    plt.xticks([1, 2, 3], ['Group 1', 'Group 2', 'Group 3'])
    plt.xlabel('Groups')
    plt.ylabel('Values')
    # Save the plot to a file (e.g., .png)
    plt.savefig('matplotlib_violinplot.png')
    plt.show()
    

    在此代码中,我们生成三组随机数据并创建小提琴图来可视化它们的分布。showmedians=True 参数在每把小提琴内显示中值。您可以根据特定数据集和需求调整数据、标签和其他图表属性。让我们看看生成的图表:

图 6.23 – 使用 matplotlib 的基本小提琴图

图 6.23 – 使用 matplotlib 的基本小提琴图

接下来,让我们看看如何自定义 matplotlib 图表中的视觉元素。

自定义 matplotlib 图表的可视元素

matplotlib 创建的图表当然可以以多种方式自定义,就像使用 plotly 生成的图表一样。在本节中,我们将探讨最重要的方面,并在过程中提供一些示例。

标签和标题

matplotlib 允许您轻松自定义坐标轴标签、图表标题和副标题。您可以为 xy 轴设置标签,为图表添加上下文标题,甚至添加副标题以提供额外信息或背景。以下是如何在 matplotlib 中自定义标签和标题的示例:

# Sample data
x = [1, 2, 3, 4, 5]
y = [10, 20, 25, 30, 35]
# Create a scatter plot
plt.scatter(x, y)
# Customize labels and titles
plt.xlabel('X-axis Label')
plt.ylabel('Y-axis Label')
plt.title('Custom Title')
plt.suptitle('Subtitle for Additional Context')
# Display the plot
plt.show()

这是它的图表:

图 6.24 – 使用 matplotlib 自定义标签

图 6.24 – 使用 matplotlib 自定义标签

坐标轴和图例

matplotlib 允许您调整坐标轴刻度,添加坐标轴断点,并微调图例。您可以在 xy 轴上更改范围、刻度和小数点位置。此外,您还可以自定义图例以更好地表示数据系列或类别。

下面是一个自定义坐标轴和图例的示例:

import matplotlib.pyplot as plt
# Sample data
x = [1, 2, 3, 4, 5]
y = [10, 20, 25, 30, 35]
# Create a line plot
plt.plot(x, y, label='Data Series A')
# Customize axes and legend
plt.xlim(0, 6)
plt.ylim(0, 40)
plt.xticks([1, 2, 3, 4, 5])
plt.yticks([0, 10, 20, 30, 40])
plt.legend()
# Display the plot
plt.show()

这是它的图表:

图 6.25 – 使用 matplotlib 自定义坐标轴和图例

图 6.25 – 使用 matplotlib 自定义坐标轴和图例

主题

matplotlib 提供了各种主题,以保持可视化的一致性。您可以从不同的预定义样式中选择,以匹配您的报告或演示文稿的美学。以下是如何应用不同主题的方法。作为一个例子,我们将应用您在本章早期熟悉的 ggplot 主题:

import matplotlib.pyplot as plt
# Apply a different theme
plt.style.use('ggplot')
# Sample data and plot
x = [1, 2, 3, 4, 5]
y = [10, 20, 25, 30, 35]
plt.plot(x, y)
# Display the plot
plt.show()

这是图表:

图 6.26 – 在 matplotlib 中使用主题

图 6.26 – 在 matplotlib 中使用主题

文本格式化

matplotlib 允许你控制文本大小、样式和对齐,以获得精美的外观。你可以调整字体大小,使用粗体或斜体样式,并指定标题、标签和注释等文本元素的对齐方式。以下是一个文本格式化的示例:

import matplotlib.pyplot as plt
# Sample data and plot
x = [1, 2, 3, 4, 5]
y = [10, 20, 25, 30, 35]
plt.plot(x, y)
# Customize text formatting
plt.title('Custom Title', fontsize=16, fontweight='bold', 
    color='blue')
plt.xlabel('X-axis Label', fontsize=12, fontstyle='italic', 
    color='green')
plt.ylabel('Y-axis Label', fontsize=12, fontweight='bold', 
    color='red')
# Display the plot
plt.show()

这是相应的图表:

图 6.27 – 使用 matplotlib 进行文本格式化

图 6.27 – 使用 matplotlib 进行文本格式化

这些示例展示了你如何在 matplotlib 可视化中实现各种定制方面。

这就结束了我们对 Python 中最受欢迎和功能强大的可视化库的概述。下一节将涵盖其他可选方案的简要描述。

其他可视化库

为了完整性,这里简要描述其他流行的库。

plotly

plotly 是一个流行的 Python 库,以其创建交互式和视觉上吸引人的数据可视化而闻名。它在生成动态图表、仪表板和交互式图表方面表现出色。不幸的是,由于微软引入的安全考虑,plotly 库的交互功能与 Excel 的最新版本无法无缝工作。这种限制可能会阻碍依赖最新 Excel 特性和功能的用户将其集成到 Excel 中。鉴于本书的重点是增强你的 Excel 工作流程,我们将不会详细介绍 plotly

seaborn

seaborn 是另一个专为统计数据可视化设计的 Python 库。虽然它提供了广泛的定制选项和创建复杂图表的能力,但与 matplotlibplotnine 等库相比,通常需要更多的代码来实现相同的结果。鉴于本章的重点是简单性和易用性,我们选择强调提供更直接和简洁的数据可视化方法的库。

在本节中,我们主要关注 matplotlibplotnine,因为它们简单且与 Excel 兼容,确保你可以快速生成并集成可视化到 Excel 报告中,而无需不必要的复杂性。

现在我们已经介绍了你可以用来创建可视化的最受欢迎的库,我们可以继续讨论图表的分布:将它们嵌入到 Excel 中!

将可视化嵌入到 Excel 中

当使用 matplotlibplotnine 等 Python 库创建可视化时,你可能希望将这些可视化无缝集成到你的 Excel 报告或电子表格中。将这些图表和图表嵌入到 Excel 中可以成为你的数据分析工具包中的一个宝贵补充。在本节中,我们将探讨将 matplotlibplotnine 可视化嵌入到 Excel 的基础知识,帮助你利用 Python 数据可视化库的强大功能以及 Excel 的报告功能。

基本嵌入过程

matplotlibplotnine可视化嵌入到 Excel 中的过程通常涉及将你的图表或图形导出为图像文件(如 PNG 或 JPEG),然后将这些图像导入到你的 Excel 表中。虽然这种方法不提供与其他一些方法相同级别的交互性,但它是一种简单直接的方法,可以将 Python 生成的数据可视化添加到 Excel 报告中。

这里是基本步骤:

  1. 在你的 Python 脚本或 Jupyter 笔记本中,使用matplotlibplotnine进行可视化。根据你的数据分析和要求进行自定义。

  2. 使用matplotlibplotnine将你的可视化保存为图像文件。常见的图像格式,如 PNG 或 JPEG,适用于此目的。确保你将图像保存到可以从你的 Excel 表中访问的位置。

  3. pywin32

    import win32com.client as win32
    # Initialize Excel
    excel = win32.gencache.EnsureDispatch('Excel.Application')
    excel.Visible = True
    # Create a new workbook
    workbook = excel.Workbooks.Add()
    # Define the (absolute) image path
    image_path = 'path\\to\\your\\image.png'
    # Insert the image into a specific sheet and cell
    sheet = workbook.ActiveSheet
    cell = sheet.Range("A1")  # You can specify the cell where you want to insert the image
    # Add the image to the worksheet (note that Width and Height might need to be adjusted)
    sheet.Shapes.AddPicture(image_path, LinkToFile=False,
        SaveWithDocument=True, Left=cell.Left, 
        Top=cell.Top, Width=300, Height=200)
    # Save the workbook
    workbook.SaveAs('your_excel_with_image.xlsx')
    # Close Excel
    excel.Application.Quit()
    
  4. 安排脚本更新(可选):如果你的数据经常变化,你可能需要考虑使用前一个选项 2中的方法来安排在 Excel 中生成图像的脚本,并将其插入。这样,你的可视化将定期自动更新。你可以使用你在第四章中学到的知识来做这件事。

虽然这种方法提供了你可视化的静态表示,但它是用 Python 生成的图表和图形来增强 Excel 报告的实用方法。

摘要

在 Excel 报告中嵌入可视化提供了一种实用的方法来增强数据展示、自定义和自动化。无论你是在处理销售数据、财务报告还是任何其他数据集,这种方法都能让你创建出能够有效传达数据驱动洞察力的有洞察力的报告。

在本章中,你了解了数据可视化技术的一般知识,如何使用这些技术扩展你的 Excel 工作流程和报告,以及如何在 R 和 Python 中实现它们。

我们详细介绍了最受欢迎和最强大的 R 包和 Python 库。你了解了执行分析时使用的典型图表,以及如何传达你的发现,包括使用案例和示例,说明这些数据可视化可以在哪些情况下使用。

下次你准备 Excel 报告时,你将能够用最美丽、最有洞察力的可视化来惊艳你的观众!

在下一章中,我们将探讨另一种方法来向那些对原始数据细节过多的观众传达你的发现:自动化数据透视表。

第七章:数据透视表与汇总表

在数据分析和电子表格操作领域,数据透视表是一种强大的工具,使用户能够将大型数据集转换和汇总为更易于管理和有洞察力的格式。通过提供一种有组织和动态的数据分析方法,数据透视表已成为各个领域专业人士不可或缺的资产。

那么,什么是数据透视表?数据透视表是一种在电子表格软件(如 Microsoft Excel 或 Google Sheets)中使用的数据处理技术,用于分析和提取复杂数据集的有意义见解。它允许用户重新结构和压缩大量信息,以简洁、易懂的格式呈现,从而促进更好的决策和数据探索。

在数据分析的世界里,数据透视表作为多功能的工具,赋予用户将原始数据转化为可操作见解的能力。通过以用户友好的格式组织、汇总和展示数据,数据透视表简化了决策过程,并促进了对于复杂数据集的深入理解。它们的适应性、交互性和简单性使它们成为各行各业和数据分析任务中的宝贵资产。

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

  • 使用 Base R 的 xtabs 函数创建表格

  • 使用 gt 包创建表格

  • 使用 tidyquant 创建数据透视表

  • 使用 win32compypiwin32 在 Python 中创建和管理数据透视表

  • 使用 Python 基础创建数据透视表

技术要求

对于本章,你可以在以下链接中找到使用的代码:github.com/PacktPublishing/Extending-Excel-with-Python-and-R/tree/main/Chapter7

对于 R 语言,我们将涵盖以下一些包:

  • tidyquant >= 1.0.6

  • gt >- 0.10.0

使用 Base R 的 xtabs 函数创建表格

在我们进入主题的核心之前,让我们了解一些重要组件。

下面是一些数据透视表的关键组件列表:

  • 行和列:数据透视表通常涉及两个主要组件——行和列。数据行包含单个记录或观察值,而列包含定义这些记录的属性或变量。

  • :数据透视表允许用户通过基于特定指标(如总和、平均值、计数或百分比)计算值来汇总和总结数据。

  • 过滤器与切片器:过滤器和切片器使用户能够聚焦于数据透视表中的特定数据子集,增强了分析的粒度。这些工具在处理大型数据集时特别有用。

  • 行和列标签:数据透视表允许用户将属性拖放到行和列标签中,动态定义表格的布局和结构。

交叉表的核心功能是围绕用户定义的标准重新排列和汇总数据。通过“旋转”数据,表格生成一个多维度的汇总,提供在原始数据集中可能不明显的信息。以下将详细说明交叉表的工作原理:

  • 选择: 用户选择他们想要分析的数据集,并标识包含相关属性和度量的列。

  • 排列: 用户将这些属性和度量放置在交叉表布局的特定区域,例如行、列、值和过滤器。

  • 计算: 交叉表自动计算所选属性的各种组合的指定度量。例如,它可以显示不同地区每个产品类别的总销售额。

  • 交互性: 交叉表是交互式的;用户可以通过拖放属性轻松修改布局,从而实时探索数据。

交叉表提供了一些优势,使它们成为数据分析中不可或缺的工具:

  • 数据汇总: 交叉表允许快速有效地汇总数据,帮助用户理解大型数据集中的模式、趋势和异常。

  • 快速洞察: 用户可以迅速生成洞察,而无需复杂的编码或复杂的公式。

  • 灵活分析: 交叉表允许用户通过重新排列属性来尝试不同的视角,从而帮助识别相关性和发展趋势。

  • 报告生成: 交叉表在创建全面和有信息量的报告、仪表板和可视化中起着关键作用。

  • 数据清洗: 在分析数据之前,可以使用交叉表来识别缺失值、异常值或不一致性。

R 中的 xtabs() 函数用于从数据框中的因子列创建列联表。您可以使用熟悉的公式输入:x ~ y。列联表是一个显示两个或多个分类变量频率分布的表格。在这种情况下,我们将使用 UCBAdmissions 数据集来演示如何使用 xtabs() 函数。

xtabs() 函数的语法如下:

xtabs(formula, data, subset, sparse, na.action, addNA, exclude, drop.unused.levels)

每个选项的含义如下:

  • formula: 一个公式对象,包含交叉分类变量(由 ~ 分隔)

  • data: 包含公式中变量的数据框

  • subset: 一个可选的表达式,用于指定要使用的观测值子集

  • sparse: 一个逻辑值,指示是否返回稀疏矩阵

  • na.action: 一个用于处理缺失值的函数

  • addNA: 一个逻辑值,指示是否为缺失值添加行和列

  • exclude: 一个要排除表中的值的向量

  • drop.unused.levels: 一个逻辑值,指示是否删除未使用的因子级别

要使用 xtabs() 函数和 UCBAdmissions 数据集,我们首先需要使用 as.data.frame() 函数将其转换为数据框。UCBAdmissions 数据集包含男性和女性申请者的数量以及被录取或拒绝的男性和女性申请者的数量。我们可以使用 xtabs() 函数创建一个展示性别和录取状态频率分布的列联表。以下是相应的代码:

# Convert the dataset to a data frame
df <- as.data.frame(UCBAdmissions)
# Create a contingency table using xtabs()
xtabs(Freq ~ Gender + Admit, df)
        Admit
Gender   Admitted Rejected
  Male       1198     1493
  Female      557     1278

xtabs() 函数的输出将是一个展示性别和录取状态频率分布的表格。表格的行代表性别,列代表录取状态。表格中的值代表性别和录取状态组合的频率。

总结来说,xtabs() 函数的语法包括几个参数,允许对输出进行定制。要使用 xtabs() 函数和 UCBAdmissions 数据集,我们首先需要使用 as.data.frame() 函数将其转换为数据框。然后,我们可以使用 xtabs() 函数创建一个展示性别和录取状态的频率分布的列联表。

现在我们已经在基础 R 中生成了一个列联表,我们可以继续使用 gt 包,这将使我们能够制作更熟悉的内容:交叉表,正如我们所知。

使用 gt 包制作表格

R 中的 gt 包允许用户创建美观且可定制的表格。gt 包的主要优点之一是易用性。该包旨在易于使用,具有简单的语法,使得快速创建表格变得容易。此外,该包提供了广泛的定制选项,允许用户创建符合其特定需求的表格。

gt 包的另一个优点是它能够处理大型数据集。该包针对性能进行了优化,这意味着它可以处理大型数据集而不会减慢速度。这对于需要从大型数据集中创建表格的用户尤其有用,因为它允许他们快速高效地完成。

gt 包还提供了广泛的美化选项,使用户能够创建视觉上吸引人且易于阅读的表格。用户可以自定义表格的字体、颜色和格式,从而轻松创建符合其品牌或设计偏好的表格。

最后,gt 包是开源的,这意味着它正不断地由 R 社区进行更新和改进。这确保了该包始终保持最新和相关性,并且定期添加新功能和改进。

总结来说,gt 包是 R 中创建表格的强大工具。其易用性、性能、定制选项以及开源特性使其成为需要快速高效创建表格的 R 用户的首选。让我们通过使用 gt 包和 mtcars 数据集来查看一个示例。

在本节中,我们正在检查gt包是否已安装。如果尚未安装,我们使用install.packages函数来安装它。gt包是一个用于在 R 中创建格式优美的表格的包:

# The gt package
if (!require(gt)) {
  install.packages("gt", dependencies = TRUE)
}

在这里,我们加载了两个额外的包:dplyrtibble。这些包为 R 中的数据处理和分析提供了有用的函数和数据结构:

library(dplyr)
library(tibble)

在本节中,我们对mtcars数据集执行几个操作:

tab <- mtcars |>
  rownames_to_column() |>
  arrange(factor(cyl), mpg) |>
  group_by(cyl) |>
  slice(1:3) |>
  gt()

操作如下:

  • rownames_to_column(): 我们将数据集的行名转换为常规列,以便我们可以处理它。这是一个来自tibble包的函数。

  • arrange(factor(cyl), mpg): 我们首先按cyl列的升序排序数据集,然后按mpg列的升序排序。这,连同group_byslice,是来自dplyr的一个函数。

  • group_by(cyl): 我们正在按cyl列对数据集进行分组。

  • slice(1:3): 我们正在选择每个组中的前三行。

  • gt(): 我们使用gt包创建一个表格来显示结果数据。

在下一节中,我们向表格中添加一个Performance横杆(一组列的标签)。我们指定我们想要包含在此横杆下的列:mpgdisphpdratwtqsec。这些列与汽车的性能相关:

tab <- tab |>
  tab_spanner(
    label = "Performance",
    columns = c(mpg, disp, hp, drat, wt, qsec)
  )

类似地,在本节中,我们向表格中添加一个Specs横杆(用于包含列的标签),并指定要包含在此横杆下的列:vsamgearcarb。这些列包含有关汽车的规格信息:

tab <- tab |>
  tab_spanner(
    label = "Specs",
    columns = c(vs, am, gear, carb)
  )

在最后一节中,我们使用标题和副标题设置表格标题。标题是mtcars 的汽车,带有一些 Markdown 格式,副标题是这些是一些 优秀的汽车

tab <- tab |>
  tab_header(
    title = md("The Cars of **mtcars**"),
    subtitle = "These are some fine automobiles"
  )
tab

因此,总的来说,这段 R 代码加载必要的包,操作mtcars数据集以创建一个包含性能和规格信息的自定义表格,并为表格设置标题。现在我们已经走过了所有代码,让我们看看它的输出。如果您想自己尝试,只需在控制台中调用标签页。表格如下所示:

图 7.1 – mtcars 和 gt 包

图 7.1 – mtcars 和 gt 包

现在我们已经看到了如何通过创建不同的横杆和标题使用gt包创建交叉表,我们可以继续到tidyquant包,它将为用户在 R 中创建交叉表提供更加熟悉的感觉。

使用 tidyquant 创建交叉表

tidyquant库中的pivot_table()函数是创建 R 中数据框的汇总表的有用工具。它允许您指定表格的行、列、值和聚合函数,并使用其他选项,如排序、格式化和筛选。

要使用 pivot_table() 函数,您需要首先通过使用 library(tidyquant) 命令加载 tidyquant 库。然后,您可以将数据框作为函数的第一个参数传递,然后是定义您的表的其它参数。例如,如果您想创建一个显示不同鸢尾花物种的平均萼片长度和萼片宽度的表格,可以使用以下代码:

# Load the tidyquant library
library(tidyquant)
library(purrr)
# Create a pivot table
pivot_table(.data = iris,
            .rows = ~ Species,
            .values = c(~ mean(Sepal.Length),
                   ~ mean(Sepal.Width))) |>
set_names("Species","Mean_Sepal_Length","Mean_Sepal_Width")

此代码的输出如下:

# A tibble: 3 × 3
  Species    Mean_Sepal_Length Mean_Sepal_Width
  <fct>                  <dbl>            <dbl>
1 setosa                  5.01             3.43
2 versicolor              5.94             2.77
3 virginica               6.59             2.97

下面是对代码的简单解释:

  • tidyquantpurrr。这些库提供了数据操作和分析的函数和工具。

  • pivot_table 函数用于重塑鸢尾花数据集中的数据。它接受三个主要参数:

    • .data:这是您想要工作的数据集,在本例中是鸢尾花数据集。

    • .rows:此参数指定您想要如何分组或分类您的数据。在这段代码中,它根据代表不同品种的鸢尾花物种的 Species 列对数据进行分组。

    • .values:此参数指定您想要计算和显示值的列。在这里,它计算了两个列——Sepal.LengthSepal.Width——对于每个物种的平均值(平均值)。

  • set_names 函数用于重命名结果表的列。列名设置为 SpeciesMean_Sepal_LengthMean_Sepal_Width

因此,总结来说,此代码将鸢尾花数据集按物种分组,计算每个物种的平均萼片长度和平均萼片宽度,然后将结果表的列重命名以使其更易于理解。结果是显示每个鸢尾花物种的平均萼片长度和平均萼片宽度的新的表格。

现在我们已经讨论了 R 中的材料,让我们继续学习 Python!

使用 win32com 和 pypiwin32 在 Python 中创建和管理交叉表

交叉表是数据分析中的强大工具,允许您快速有效地总结和探索大型数据集。虽然它们是电子表格软件(如 Microsoft Excel)的标准功能,但您也可以使用 Python 编程方式创建和操作交叉表。在本章的这一部分,我们将深入研究交叉表的世界,并学习如何利用 win32compywin32 库来发挥其潜力。

使用 Python 创建交叉表:基础知识

交叉表是数据分析领域不可或缺的工具。它们提供了一种动态的方式来总结、探索并从复杂的数据集中获得洞察。然而,当处理大量数据时,设置和自定义交叉表可能是一个耗时且容易出错的过程,通常需要手动干预。

在本章中,我们将探讨 Python 如何与 win32compywin32 库结合使用,以简化和管理交叉表的创建和管理。这种强大的组合使数据分析师和专业人员能够高效地处理大量数据,而无需重复的手动任务。

想象一下,只需几行 Python 代码就能创建数据透视表、应用高级计算和刷新数据。这正是我们本节的目标。我们将为您提供知识和工具,以充分利用数据透视表的全功能,同时消除手动设置中的繁琐部分。

设置 Python 环境

在我们深入创建数据透视表之前,您需要设置您的 Python 环境,并安装所需的库。win32compywin32 对于与 Microsoft Excel 交互是必不可少的,因此请确保它们已安装在您的系统上。我们已经在 第三章 中介绍了安装过程,并提供了如何将 Python 与 Excel 连接的基本示例。请参阅 使用 pywin32 将 VBA 与 Python 集成 部分,特别是 设置环境子部分。如果您尚未设置 pywin32,请参阅该章节。

创建数据透视表

与数据透视表一起工作的基础当然是创建它们。我们将从基础知识开始,教您如何从头开始构建数据透视表。以下是一步一步的指南,帮助您开始:

  1. 连接到 Excel:创建一个 Excel 实例并打开一个工作簿。如果工作簿不存在,您可以按照以下方式创建一个新的工作簿:

    import win32com.client as win32
    # Create an Excel workbook and add a sheet
    excel = win32.gencache.EnsureDispatch('Excel.Application')
    workbook = excel.Workbooks.Add()
    worksheet = workbook.Worksheets(1)
    
  2. 向工作表添加数据:您需要数据来创建数据透视表。通常,这些数据已经存在,但为了本例的目的,您可以将示例数据添加到工作表中,如下所示:

    worksheet.Cells(1, 1).Value = 'Name'
    worksheet.Cells(1, 2).Value = 'Category'
    worksheet.Cells(1, 3).Value = 'Sales'
    worksheet.Cells(2, 1).Value = 'John'
    worksheet.Cells(2, 2).Value = 'Electronics'
    worksheet.Cells(2, 3).Value = 1000
    worksheet.Cells(3, 1).Value = 'Alice'
    worksheet.Cells(3, 2).Value = 'Clothing'
    worksheet.Cells(3, 3).Value = 800
    worksheet.Cells(4, 1).Value = 'John'
    worksheet.Cells(4, 2).Value = 'Clothing'
    worksheet.Cells(4, 3).Value = 300
    # Add more data as needed
    
  3. 选择数据范围:定义您想要用于数据透视表的数据范围。您可以通过指定数据的起始和结束单元格来完成此操作:

    data_range = worksheet.Range('A1:C4')  # Adjust the range as needed
    
  4. 创建数据透视表:现在,您可以根据所选的数据范围创建数据透视表。指定您希望数据透视表所在的位置以及您在数据透视表中用于行、列和值的列:

    # Add a new worksheet to the workbook to hold the Pivot Table:
    pivot_table_sheet = workbook.Worksheets.Add()
    pivot_table_sheet.Name = 'Pivot Table'
    # Create a Pivot Cache using the data range:
    pivot_cache = workbook.PivotCaches().Create(SourceType=1, SourceData=data_range)
    # Create the Pivot Table on the new sheet using the Pivot Cache:
    pivot_table = pivot_cache.CreatePivotTable(
        TableDestination=pivot_table_sheet.Cells(3, 1),
        TableName='MyPivotTable')
    # Add the row, column and data fields
    pivot_table.PivotFields('Name').Orientation = 1 # row field
    pivot_table.PivotFields('Category').Orientation = 2 # column field
    pivot_table.PivotFields('Sales').Orientation = 4 # data field
    # Add the calculated fields
    calculated_field = pivot_table.CalculatedFields().Add(
        "Total Sales", "=SUM(Sales)")
    # Refresh the PivotTable to apply changes
    pivot_table.RefreshTable()
    

    在本例中,SourceType 参数指定了 PivotTable 的数据源类型。在这种情况下,SourceType = 1 表示数据源是一个 Excel 工作表。SourceType 参数可以取以下值之一(或代表它们的 1 到 3 之间的数字):

    • xlDatabase:这表示数据源是一个 Excel 工作表或外部数据库。它是数据透视表中最常见的数据源类型。

    • xlExternal:这表示数据源是一个 OLAP 立方体或不是直接从 Excel 可访问的外部数据源。

    • xlConsolidation:这表示数据源是一个合并。合并是从多个工作表或工作簿中聚合数据的透视表。

  5. 保存工作簿并关闭 Excel:别忘了保存您带有新创建的数据透视表的 Excel 工作簿:

    workbook.SaveAs('PivotTableExample.xlsx')
    workbook.Close()
    excel.Quit()
    

    当保存 Excel 工作表时,如果您不想将工作表保存到 Python 的工作目录,您可以提供完整路径。

就这样!你已经使用 Python 中的 pywin32 创建了一个交叉表。你可以调整数据、交叉表位置和格式化选项,以满足你的特定需求。

现在你已经准备好了一个基本的交叉表,让我们看看如何将其修改以适应你的需求。

操作交叉表

一旦你有了交叉表,你可能想要对它们执行各种操作,例如过滤、排序和刷新数据。以下是这些步骤:

  1. 首先,打开上一节中的 Excel 文件并选择创建的交叉表:

    import win32com.client as win32
    # Connect to Excel
    excel = win32.gencache.EnsureDispatch('Excel.Application')
    # Open the workbook with the pivot table
    workbook = excel.Workbooks.Open('PivotTableExample.xlsx')  # Replace with your workbook path
    worksheet = workbook.Worksheets(1)
    # Access the Pivot Table
    pivot_table = worksheet.PivotTables('MyPivotTable')  # Use the name of your pivot table
    
  2. 你可以根据值在交叉表中过滤数据。在这个例子中,我们将过滤 类别 字段,只显示 电子产品

    # Filter by value (need to make the field a Page field instaed of a column field)
    category_field = pivot_table.PivotFields('Category')
    category_field.Orientation = 3 # page field
    category_field.CurrentPage = "Electronics"
    
  3. 你可能需要排序交叉表中的行或列。在这个例子中,我们将按升序排序 名称 字段:

    # Sort Rows or Columns
    name_field = pivot_table.PivotFields('Name')
    name_field.AutoSort(1, "Name")
    
  4. 如果你的源数据已更改,你可以刷新交叉表以更新它:

    # Define the new source data range
    new_source_data_range = 'Sheet1!A1:C2'
    # Update the SourceData property of the pivot table's Table object
    pivot_table.TableRange2(workbook.Sheets('Sheet1').Range(
        new_source_data_range))
    # Refresh data
    pivot_table.RefreshTable()
    
  5. 在操作交叉表后,保存你的更改并关闭工作簿:

    workbook.Save()
    workbook.Close()
    excel.Quit()
    

注意

在使用 Python 访问或操作它时,请不要打开电子表格(在 Excel 中),因为这会导致难以调试的 com_errors 实例。

这些步骤应该能帮助你开始使用 pywin32 操作交叉表。你可以调整过滤器、排序标准和刷新频率,以满足你的特定需求并自动化涉及交叉表的各项任务。

一旦你的交叉表按照你的要求设置好,你可能需要通过分组一些(或全部)类别来进一步改进它,以更好地反映你试图传达的信息。在下一小节中,我们将详细介绍如何做到这一点。

交叉表中的分组

在交叉表中分组数据可以帮助你创建一个更有组织和洞察力的数据集视图。你可以根据特定的标准,如日期范围、数值区间或自定义类别来分组数据。在本节中,我们将探讨如何使用 Python 和 pywin32 库将分组应用于你的交叉表。

创建日期分组

分组的一个常见用例是按日期范围聚合数据。例如,你可能希望将销售数据分组到月度或季度间隔。为此,你可以在交叉表中创建日期分组。

我们将首先生成一些示例数据:

# Sample Data Generation
import pandas as pd
import random
from datetime import datetime, timedelta
import win32com.client as win32
import os
import numpy as np
data = {
    'Date': [datetime(2023, 1, 1) + timedelta(days=i) for i in range(365)],
    'Sales': [random.randint(100, 1000) for _ in range(365)]
}
df = pd.DataFrame(data)
# Create an ExcelWriter object and write the DataFrame to the Excel worksheet
df.to_excel("GroupingExample.xlsx", sheet_name='Sheet1', index=False)

将数据保存在 Excel 表格中(默认情况下在 Python 工作目录中,但也可以指定其他位置),我们可以遵循通常的步骤打开 Excel 表格,为交叉表添加一个专用标签,并创建交叉表。之前已涵盖的步骤在此省略(但可在 GitHub 上找到)。步骤如下:

# Connect to Excel
# Open the Excel workbook and add a sheet
# Add a new worksheet to the workbook to hold the Pivot Table:
# Define the range of data to be used as input for the pivot table
# Create a Pivot Cache using the data range:
# Create the Pivot Table on the new sheet using the Pivot Cache:
# Add the 'Date' field to Rows and define the date_field variable as done with name_field in the example above.
# Add the calculated fields
calculated_field = pivot_table.CalculatedFields().Add("Total Sales", "=SUM(Sales)")
# Group by months
date_field.Subtotals = [False]*12
date_field.NumberFormat = 'MMMM YYYY'
# Sort Rows
date_field.AutoSort(1, "Date")

在这个例子中,我们创建了一个交叉表,并将 日期 字段添加到行中,以及一个用于 总销售额 的计算字段。然后我们指定了希望以月-年格式格式化日期。最后,格式化后的日期被排序。

要将分组字段添加到数据透视表中,我们需要知道哪些值属于一组(注意,这些值已被格式化为不显示确切的日期,但它们仍然有所不同):

# count the unique values for each value of the date column in the pivot
date_values = pd.DataFrame([item.Value for item in date_field.PivotItems()], columns = ['date'])
unique_values = pd.DataFrame(np.transpose(np.unique(date_values, return_counts=True)), columns=['date', 'count'])
date_values_count = date_values.merge(unique_values).drop_duplicates()
# Group by months
# Set the GroupOn property
date_range = pivot_table_sheet.Range(f"A4:A{starting_row + date_values_count['count'].iloc[0]}")
date_range.Group()
# You can use the above method to group the other months as well if you want to
# Note: the pivot is now changed, the second group starts at row starting_row + 2, instead of starting_row + 32

这创建了一个名为Date2的分组数据透视字段。在Date2字段中,属于一月的日期被分组到Group1value中,而其他日期则被分组到只包含单个日期的组中。使用前面的示例,您现在可以遍历月-年日期的其他唯一值,并将其他日期也进行分组。请注意,总销售额的计算字段现在是在这些组上计算的。

最后,我们将新分组字段的格式更改为月-年格式,将日期字段中的原始数据改回显示完整日期,并隐藏组细节以提高清晰度。最后,刷新数据透视表,保存并关闭 Excel 文件:

# change the formatting of the grouped column to show only month and year and change back the original date column to show the full date
# change the formatting of the grouped column to show only month and year and change back the original date column to show the full date
pivot_table.PivotFields('Date2').NumberFormat = 'MMMM YYYY'
date_field.NumberFormat = 'DD MMMM YYYY'
# hide the details of the grouped values
for item in pivot_table.PivotFields('Date2').PivotItems():
    item.ShowDetail = False
# Refresh data
pivot_table.RefreshTable()
#pivot_table.PivotFields('Date2').Orientation = 2
# Save and close
workbook.Save()
workbook.Close()
excel.Quit()

这只是一个例子,说明了您如何使用分组来更有效地分析数据。根据您的数据集和分析目标,您可以自定义分组以适应您的特定需求。

本节涵盖了您需要从 Python 直接创建和操作数据透视表的步骤。我们介绍了将数据透视表插入 Excel 表格以及添加数据透视表所需的各种类型字段作为基础。然后,我们深入到更复杂的领域,包括计算字段、格式化和最终分组值。通过本节学到的技能,您现在可以创建出适合您分析的数据透视表,而无需打开 Excel!

摘要

在本章中,我们通过 R 和 Python 的功能开始了利用数据透视表力量的旅程。数据透视表——数据分析中不可或缺的工具——提供了一种动态的方式来总结和探索大量数据集。通过掌握本章中概述的技术,您已经解锁了数据透视表的全部潜力,使您能够自动化其创建、操作和增强。

我们首先介绍了数据透视表在数据分析中的重要性,并为我们探索奠定了基础。我们侧重于实用性,指导您安装必要的库,确保您的 R 或 Python 环境为处理 Excel 的复杂性做好了充分准备。

从零开始构建数据透视表是我们的第一次尝试,为您提供了选择数据源、排列行和列以及自定义表格外观的基本知识。我们在揭秘创建过程方面没有留下任何疑问。

操作数据透视表打开了一个全新的世界。您学习了如何动态地筛选、排序和刷新数据,这些技能使您能够根据不断变化的需求定制数据透视表。

此外,我们还探讨了高级数据透视表功能,如计算字段和分组,展示了您新获得的专业知识的多样性和深度。这些高级技术是深入了解数据并增强分析能力的宝贵工具。

总之,您通过 R 和 Python 学习数据透视表的经历,使您拥有了全面的技术技能,能够高效有效地应对数据分析挑战。凭借这些知识,您可以将数据转化为可操作的见解,简化工作流程,并自信地进行数据驱动决策。能够通过 R 和 Python 自动化和操作数据透视表,在当今数据驱动世界中是一种宝贵的资产,您现在已准备好充分利用这一力量。

在下一章中,我们将了解数据探索分析EDA)是如何在数据分析中工作的。

第三部分:EDA、统计分析与时间序列分析

深入 R 和 Python 的数据探索分析EDA)世界,揭示 Excel 数据中的洞察力和模式。探索统计分析的基础,包括线性回归和逻辑回归技术。深入研究时间序列分析领域,掌握统计、图表和预测方法,以获得对时间数据趋势和模式的宝贵洞察。

本部分包含以下章节:

  • 第八章, 使用 R 和 Python 进行数据探索分析

  • 第九章, 统计分析:线性回归和逻辑回归

  • 第十章, 时间序列分析:统计、图表和预测

第八章:使用 R 和 Python 进行探索性数据分析

探索性数据分析EDA)是数据科学家在数据分析过程中的一个关键初始步骤。它涉及系统地检查和可视化数据集,以揭示其潜在的规律、趋势和见解。EDA 的主要目标是更深入地了解数据,识别潜在的问题或异常,并指导后续的分析和建模决策。

EDA 通常从一系列数据汇总技术开始,例如计算基本统计量(均值、中位数和标准差)、生成频率分布以及检查数据类型和缺失值。这些初步步骤提供了数据集结构和质量的概述。

可视化在 EDA 中扮演着核心角色。数据科学家创建各种图表和图形,包括直方图、箱线图、散点图和热图,以可视化数据中的分布和关联。这些可视化有助于揭示数据中的异常值、偏度、相关性和聚类,有助于识别有趣的模式。

探索分类变量涉及生成条形图、饼图或堆叠条形图,以了解不同类别的分布及其关系。这对于客户细分或市场分析等任务非常有价值。

EDA 还涉及评估变量之间的关系。数据科学家使用相关矩阵、散点图和回归分析来揭示联系和依赖关系。理解这些关联可以指导模型中的特征选择,并帮助识别潜在的共线性问题。

数据转换和清洗通常在 EDA(探索性数据分析)过程中执行,以解决诸如异常值、缺失数据和偏度等问题。关于数据插补、缩放或编码分类变量的决策可能基于在探索过程中获得的见解。

总体而言,EDA 是数据科学工作流程中的一个关键阶段,因为它为后续的数据建模、假设检验和决策奠定了基础。它通过提供对数据集特征和细微差别的全面理解,使数据科学家能够就数据预处理、特征工程和建模技术做出明智的选择。EDA 有助于确保基于数据的见解和决策建立在坚实的数据理解和探索基础上。

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

  • 探索数据分布

  • 数据结构和完整性

  • 使用各种包进行 EDA

技术要求

对于本章,所有脚本和文件都可以在以下链接的 GitHub 上找到:github.com/PacktPublishing/Extending-Excel-with-Python-and-R/tree/main/Chapter%208

对于 R 部分,我们将涵盖以下库:

  • skimr 2.1.5

  • GGally 2.2.0

  • DataExplorer 0.8.3

使用 skimr 理解数据

作为 R 语言程序员,skimr 包是一个有用的工具,可以提供关于变量(如数据框和向量)的汇总统计信息。该包提供了一组更丰富的统计信息,以便与基础 R 的 summary() 函数相比,为最终用户提供更稳健的信息集。

要使用 skimr 包,首先必须使用 install.packages("skimr") 命令从 CRAN 安装它。一旦安装,就可以使用 library(skimr) 命令加载包。然后使用 skim() 函数来汇总整个数据集。例如,skim(iris) 将提供 iris 数据集的汇总统计信息。skim() 的输出是水平打印的,每个变量类型一个部分,每个变量一个行。

该包还提供了 skim_to_wide() 函数,它将 skim() 的输出转换为宽格式。这可以用于将汇总统计信息导出到电子表格或其他外部工具。

总体而言,skimr 包是一个有用的工具,可以快速轻松地获取 R 中变量的汇总统计信息。它提供的统计信息比 R 基础函数 summary() 更丰富,且易于使用和定制。该包特别适用于数据探索和数据清洗任务,因为它允许用户快速识别数据中的潜在问题。现在,我们已经对 skimr 包有了基本的了解,让我们看看它的实际应用。

这段 R 代码用于使用 skimr 包生成 iris 数据集的汇总。skimr 包提供了一种方便的方式来快速汇总和可视化数据集的关键统计信息。

下面是对每一行代码的解释以及预期的输出:

  • if(!require(skimr)){install.packages("skimr")}:这一行检查 skimr 包是否已经安装。如果没有安装,它将使用 install.packages("skimr") 安装包。这确保了 skimr 包在后续代码中使用时可用。

  • library(skimr):这一行将 skimr 包加载到 R 会话中。一旦包被加载,就可以使用其函数和特性。

  • skim(iris):这一行调用 skim() 函数,来自 skimr 包,并应用于 iris 数据集。skim() 函数生成数据集的汇总,包括每个变量(列)的统计信息和相关信息。

现在,让我们讨论预期的输出。当你运行 skim(iris) 命令时,你应该在 R 控制台中看到 iris 数据集的汇总。输出将包括如下统计信息和相关信息:

  • 计数:每个变量的非缺失值数量

  • 缺失:每个变量的缺失值数量(如果有)

  • 唯一值:每个变量的唯一值数量

  • 平均值:每个数值变量的平均值

  • 最小值:每个数值变量的最小值

  • 最大值:每个数值变量的最大值

  • 标准差:每个数值变量的标准差

  • 其他汇总统计数据

输出将类似于以下内容,但包含更详细的统计数据:

> skim(iris)
── Data Summary ────────────────────────
                           Values
Name                       iris
Number of rows             150
Number of columns          5
_______________________
Column type frequency:
  factor                   1
  numeric                  4
________________________
Group variables            None
── Variable type: factor ─────────────────────────────────────────────────────────────────────────
  skim_variable n_missing complete_rate ordered n_unique top_counts
1 Species               0             1 FALSE          3 set: 50, ver: 50, vir: 50
── Variable type: numeric ────────────────────────────────────────────────────────────────────────
  skim_variable n_missing complete_rate mean    sd  p0 p25  p50 p75 p100 hist
1 Sepal.Length          0             1 5.84  0.828  4.3  5.1  5.8  6.4  7.9 ▆▇▇▅▂
2 Sepal.Width           0             1 3.06  0.436  2   2.8  3    3.3  4.4 ▁▆▇▂▁
3 Petal.Length          0             1 3.76  1.77  1   1.6  4.35  5.1  6.9  ▇▁▆▇▂
4 Petal.Width           0             1 1.20  0.762 0.1 0.3  1.3  1.8  2.5  ▇▁▇▅▃

此输出提供了对iris数据集的全面总结,帮助您快速了解其结构和关键统计数据。您还可以将分组后的tibble传递给skim()函数,并以此方式获得结果。

现在我们已经通过一个简单的示例了解了如何使用skimr包来探索我们的数据,我们现在可以继续了解GGally包。

在 R 中使用 GGally 包

在其核心,GGally是 R 中广受欢迎的ggplot2包的扩展。它将ggplot2的优雅和灵活性提升到一个令人眼花缭乱的函数集合,释放您的创造力,以惊人的方式可视化数据。

使用GGally,您可以轻松创建美丽的散点图、直方图、条形图等等。它有什么独特之处?GGally简化了创建复杂多元图表的过程,为您节省时间和精力。想要探索相关性、可视化回归模型或制作出色的生存曲线吗?GGally会支持你。

GGally不仅仅关乎美观;它关乎洞察。它使您能够通过视觉探索揭示数据中的隐藏关系。直观的语法和用户友好的界面使其既适合新手也适合经验丰富的数据科学家。

更好的是,GGally鼓励协作。其易于分享的可视化可以成为向更广泛的受众传达您发现的有力工具,从同事到客户。

因此,如果您想提升您的数据可视化技能,不妨试试GGally。它是您在数据可视化领域的可靠盟友,帮助您将数字转化为引人入胜的故事。释放数据的真正潜力,让GGally成为您的创意伙伴。您的数据从未如此出色!现在,让我们通过一个简单的用例来了解如何使用它:

if(!require(GGally)){install.packages("GGally")}
If(!require(TidyDensity)){install.packages("TidyDensity")}
library(GGally)
library(TidyDensity)
tidy_normal(.n = 200) |>
  ggpairs(columns = c("y","p","q","dx","dy"))

让我们一步步来分析:

  • if(!require(GGally)){install.packages("GGally")}: 此行检查GGally包是否已安装在你的 R 环境中。如果没有安装,它将使用install.packages("GGally")继续安装。

  • library(GGally): 在确保Ggally已安装后,此代码将GGally包加载到当前的 R 会话中。此包提供创建各种类型图表和可视化的工具,包括散点图矩阵。

  • library(TidyDensity): 类似地,此行加载了TidyDensity包,用于创建整洁密度图。整洁密度图是一种以整洁和有序的方式可视化数据分布的方法。

  • tidy_normal(.n = 200):在此,代码生成一个包含 200 个随机数据点的数据集。这些数据点被假定为遵循正态分布(钟形曲线)。tidy_normal 函数用于创建此数据集。

  • ggpairs(columns = c("y","p","q","dx","dy")):这里发生了魔法。GGally 软件包中的 ggpairs 函数被调用,使用之前生成的数据集。它创建了一个散点图矩阵,其中每个变量的组合都相互绘制。ypqdxdy 变量是用于创建散点图的数据集列。

总结来说,此代码首先安装并加载必要的 R 软件包(GGallyTidyDensity)。然后,它生成一个包含 200 个随机点的数据集,并使用 ggpairs 函数创建一个散点图矩阵。散点图矩阵可视化数据集中指定列之间的关系,让您探索数据的模式和相关性。让我们看看生成的结果图:

图 8.1 – 使用 GGally 在 tidy_normal() 生成的 200 个点上进行操作

图 8.1 – 使用 GGally 在 tidy_normal() 生成的 200 个点上进行操作

这里生成的是随机数据,因此您可能不会得到完全相同的结果。现在我们已经用一个简单的例子介绍了 GGally 软件包,我们可以继续介绍 DataExplorer 软件包,看看它如何与之比较。

使用 DataExplorer 软件包

DataExplorer R 软件包的创建是为了在 EDA 过程中简化大部分数据管理和可视化的责任。EDA 是数据分析中的一个关键和初级阶段,在此阶段,分析师对数据进行初步观察,以形成有意义的假设并确定后续行动。

DataExplorer 提供了各种函数来完成以下任务:

  • 扫描和分析数据变量:该软件包可以自动扫描和分析数据集中的每个变量,识别其类型、数据分布、异常值和缺失值。

  • DataExplorer 提供了各种可视化函数,以帮助分析师理解变量之间的关系并识别数据中的模式。这些函数包括直方图、散点图、箱线图、热图和相关性矩阵。

  • DataExplorer 还提供了转换数据的函数,例如将分类变量转换为数值变量、填充缺失值以及缩放数值变量。

DataExplorer 可以用于各种 EDA 任务,例如以下内容:

  • DataExplorer 可以用于识别数据集中的不同类型变量、它们的分布以及它们之间的关系

  • DataExplorer 可以帮助分析师识别数据中的异常值和缺失值,这在构建预测模型之前解决可能很重要。

  • DataExplorer可以通过识别变量之间的模式和关系来帮助分析师生成关于数据的假设

这里有一些如何使用该包的示例:

install.packages("DataExplorer")
library(DataExplorer)
library(TidyDensity)
library(dplyr)
df <- tidy_normal(.n = 200)
df |>
  introduce() |>
  glimpse()

首先,我们检查DataExplorer包是否已安装。如果没有,我们就安装它。然后,我们加载DataExplorer包,以及TidyDensitydplyr包。

接下来,我们创建一个包含 200 个观测值的正态分布数据集。我们使用tidy_normal()函数来做这件事,因为它是在 R 中创建正态分布数据集的一种方便方式。通常,人们最有可能只使用tidy_normal()输出的y列。

一旦我们有了数据集,我们就使用DataExplorer包中的introduce()函数来生成数据的摘要。这个摘要包括关于观测数和变量类型的详细信息。

最后,我们使用dplyr包中的glimpse()函数来显示转置后的数据。这是一种快速了解数据并确保其看起来符合预期的好方法。

换句话说,这段代码是探索 R 中正态分布数据集的一种快速简单的方法。它非常适合学生和初学者,也适合需要快速开始工作的经验丰富的数据科学家。现在,让我们看看输出:

> df |>
+   introduce() |>
+   glimpse()
Rows: 1
Columns: 9
$ rows                 <int> 200
$ columns              <int> 7
$ discrete_columns     <int> 1
$ continuous_columns   <int> 6
$ all_missing_columns  <int> 0
$ total_missing_values <int> 0
$ complete_rows        <int> 200
$ total_observations   <int> 1400
$ memory_usage         <dbl> 12344

接下来,让我们看一下plot_intro()函数,并查看使用简单调用df |> plot_intro()在相同数据上的输出:

图 8.2 – 函数

图 8.2 – plot_intro()函数

最后,我们将查看plot_qq()函数的输出:

图 8.3 – 包含所有数据的函数

图 8.3 – 包含所有数据的plot_qq()函数

我们现在将看到一个只包含两个变量的分位数-分位数Q-Q)图,这两个变量分别是qy列。以下是代码:

df[c("q","y")] |>
  plot_qq()

这是它的图表:

图 8.4 – 只包含 y 和 q 列的函数

图 8.4 – 只包含 y 和 q 列的plot_qq()函数

我们的意图是让您理解 Q-Q 图,但如果不是这样,简单的谷歌搜索也会得到许多好的结果。另一个从未讨论过的问题是如何在 R 中处理缺失数据。有许多函数可以用来捕获、清理和了解它们,例如all()any()is.na()na.omit()。在这里,我建议您在网上探索这些,所有这些都已经广泛讨论过。现在我们已经讨论了 R 中不同包中一些函数的几个不同示例,是时候探索 Python 中的相同内容了。

开始使用 Python 进行 EDA

如前所述,EDA(探索性数据分析)是视觉和统计上探索数据集以揭示模式、关系和洞察的过程。这是深入更复杂的数据分析任务之前的一个关键步骤。在本节中,我们将向您介绍 EDA 的基础知识,并展示如何为 EDA 准备您的 Python 环境。

EDA 是数据分析的初始阶段,您在此阶段检查和总结您的数据集。EDA 的主要目标如下:

  • 了解数据:深入了解数据的结构、内容和质量

  • 识别模式:在数据中发现模式、趋势和关系

  • 检测异常:找到可能需要特别关注的异常值和异常

  • 生成假设:对您的数据提出初始假设

  • 为建模做准备:预处理数据以进行高级建模和分析

在您能够执行 EDA 之前,您需要设置您的 Python 环境以处理 Excel 数据。我们已在之前的章节中介绍了第一步:即安装必要的库并从 Excel 加载数据。

接下来,我们将介绍 EDA 最重要的基础知识:数据清洗和数据探索。

数据清洗是准备您的 Excel 数据以在 Python 中进行 EDA 的一个关键步骤。它涉及识别和纠正可能影响您分析准确性和可靠性的各种数据质量问题。

让我们从数据清洗的复杂性开始,没有它,您无法对 EDA 的结果有信心。我们将关注通用的数据清洗挑战以及来自 Excel 的数据特有的挑战。

Python 中处理 Excel 数据的数据清洗

在 Python 处理 Excel 数据时,数据清洗是一个关键过程。它确保您的数据处于正确的格式且无错误,从而使您能够进行准确的 EDA。

我们将以生成一些脏数据作为示例:

import pandas as pd
import numpy as np
# Create a DataFrame with missing data, duplicates, and mixed data types
data = {
    'ID': [1, 2, 3, 4, 5, 6],
    'Name': ['Alice', 'Bob', 'Charlie', 'Alice', 'Eva', 'Eva'],
    'Age': [25, np.nan, 30, 28, 22, 23],
    'Salary': ['$50,000', '$60,000', 'Missing', '$65,000', '$55,000',
    '$75,000']
}
df = pd.DataFrame(data)
# Introduce some missing data
df.loc[1, 'Age'] = np.nan
df.loc[3, 'Salary'] = np.nan
# Introduce duplicates
df = pd.concat([df, df.iloc[1:3]], ignore_index=True)
# Save the sample data in present working directory
df.to_excel('dirty_data.xlsx')

创建的数据框看起来如下:

图 8.5 – 使用 GGally 对 tidy_normal()生成的 200 个点进行操作

图 8.5 – 使用 GGally 对 tidy_normal()生成的 200 个点进行操作

脏数据准备就绪后,我们可以开始清洗它,这包括处理缺失数据、重复数据和在清洗 Excel 数据时进行数据类型转换。让我们看看如何做这件事。

处理缺失数据

首先识别有缺失数据的单元格或列。在 Python 中,缺失值通常表示为NaN(代表Not a Number)或None

根据上下文,您可以选择替换缺失值。常见的技术包括以下:

  • 使用均值、中位数或众数填充缺失的数值。请注意,如果进行回归分析,这将会人为地降低标准误差测量值。在为建模目的清洗数据时请记住这一点!

  • 使用众数(最频繁的类别)替换缺失的类别数据。

  • 使用前向填充或后向填充来传播前一个或下一个有效值。

  • 根据数据中的趋势插值缺失值。

Python 提供了几种高效且统计上稳健的解决方案来完成这项任务,从基本的pandas方法到具有更稳健的插补方法的专用包,如fancyimpute。然而,插补不应盲目应用,因为缺失数据本身也可以是信息,而插补的值可能会导致分析结果不正确。正如往常一样,领域知识是获胜的关键。

区分三种类型的缺失数据非常重要:

  • 完全随机缺失MCAR):

    • 在这种情况下,数据的缺失是完全随机的,与任何观察到的或未观察到的变量无关。

    • 数据点缺失的概率对所有观测值都是相同的。

    • 缺失值和非缺失值之间没有系统性差异。

    • 以下是一个例子:受访者意外跳过一些问题的调查。

  • 随机缺失MAR):

    • 缺失性取决于观察到的数据,但不取决于未观察到的数据。

    • 数据点缺失的概率与数据集中其他观察到的变量相关。

    • 一旦考虑到其他观察到的变量,数据的缺失性就是随机的。

    • 以下是一个例子:在一份调查中,男性可能比女性更不愿意透露他们的收入。在这种情况下,收入数据在性别条件下是随机缺失的。

  • 非随机缺失MNAR):

    • 缺失性取决于未观察到的数据或缺失值本身。

    • 数据点缺失的概率与缺失值或其他未观察到的变量相关。

    • 即使考虑到观察到的变量,缺失性也不是随机的。

    • 以下是一个例子:在关于收入的调查中,高收入者可能不太愿意透露他们的收入。

如果一行或一列中有很大一部分包含缺失数据,你可能考虑完全删除该行或列。在这样做时要小心,因为这不应导致信息的大量丢失:

import pandas as pd
import numpy as np
# Load Excel data into a pandas DataFrame
df = pd.read_excel('dirty_data.xlsx', index_col=0)
# Handling Missing Data
# Identify missing values
missing_values = df.isnull().sum()
# Replace missing values with the mean (for numeric columns)
df['Age'].fillna(df['Age'].mean(), inplace=True)
# Replace missing values with the mode (for categorical columns)
df['Salary'].fillna(df['Salary'].mode()[0], inplace=True)
# Forward-fill or backward-fill missing values
# This line is a placeholder to show you what's possible
# df['ColumnWithMissingValues'].fillna(method='ffill', inplace=True)
# Interpolate missing values based on trends
# This line is a placeholder to show you what's possible
# df['NumericColumn'].interpolate(method='linear', inplace=True)
# Remove rows or columns with missing data
df.dropna(axis=0, inplace=True)  # Remove rows with missing data
df.dropna(axis=1, inplace=True)  # Remove columns with missing data
df.to_excel('cleaned_data.xlsx')

处理重复数据

从检测重复行开始。Python 库,如pandas,提供了检测和处理重复行的函数。要识别重复项,可以使用duplicated()方法。如果适用,继续删除重复行:在检测到重复项后,你可以选择使用drop_duplicates()方法来删除它们。在删除重复项时要小心,特别是在预期存在重复项的情况下:

# Handling Duplicates
# Detect and display duplicate rows
duplicate_rows = df[df.duplicated()]
print("Duplicate Rows:")
print(duplicate_rows)
# Remove duplicate rows
df.drop_duplicates(inplace=True)

处理数据类型转换

从 Excel 读取数据,虽然高度自动化,但可能导致数据类型识别错误。在 Python 中,当使用pandas等库读取 Excel 数据时,数据类型通常会自动分配。然而,验证每列是否分配了正确的数据类型(例如,数值、文本、日期等)是至关重要的。

这种影响从过大的内存占用到实际的语义错误。例如,如果布尔值存储为浮点数,它们将被正确处理,但将占用更多的内存(而不是 64 字节的单个位),而尝试将字符串转换为浮点数可能会破坏你的代码。为了减轻这种风险,首先确定加载的数据中的数据类型。然后,将数据类型转换为适当的类型。要在 Python 中转换数据类型,可以使用pandas中的astype()方法。例如,要将列转换为数值数据类型,可以使用df['Column Name'] = df['Column Name'].astype(float)

这里有一个如何做到这一点的例子:

# Handling Data Type Conversion
# Check data types
print(df.dtypes)
# Convert a column to a different data type (e.g., float)
df.loc[df['Salary']=='Missing', 'Salary'] = np.NaN
df.loc[:, 'Salary'] = df['Salary'].str.replace("$", "")
df.loc[:, 'Salary'] = df['Salary'].str.replace(",", "")
df['Salary'] = df['Salary'].astype(float)
print(df)
# Now that Salary is a numeric column, we can fill the missing values with mean
df['Salary'].fillna(df['Salary'].mean(), inplace=True)

Excel 特定的数据问题

让我们看看特定于从 Excel 加载数据的问题:

  • 合并单元格:当 Excel 文件中的合并单元格导入 Python 时,可能会导致数据集出现不规则性。建议在导入前在 Excel 中取消合并单元格。如果取消合并不可行,考虑在 Python 中对这些单元格进行预处理。

  • 读取 Excel 文件时使用pandasna_values参数来指定在导入时应被视为缺失值(NaN)的值

  • 在导入前手动调整 Excel 文件以删除不必要的空单元格

通过在 Python 中解决这些常见的 Excel 数据处理问题,你可以确保你的数据以干净和可用的格式用于你的探索性数据分析(EDA)。干净的数据在探索阶段可以带来更准确和有意义的洞察,这一点我们将在下一部分进行讨论。

在 Python 中执行 EDA

在数据加载和清理完成后,你可以开始你的初步数据探索之旅。这一阶段对于深入理解你的数据集、揭示其潜在模式以及确定潜在的感兴趣或关注领域至关重要。

这些初步步骤不仅为你的 EDA 提供了一个坚实的基础,还帮助你发现数据中的隐藏模式和关系。有了这种初步理解,你可以继续进行更高级的数据探索技术,并更深入地研究 Excel 数据集。

在接下来的章节中,我们将深入探讨具体的数据探索和可视化技术,以进一步增强你对数据集的洞察力。有了这些知识,让我们继续到下一部分,我们将探讨更详细地理解数据分布和关系的技巧。

汇总统计信息

首先为你的数据集生成汇总统计信息。这包括基本指标,如数值特征的均值、中位数、标准差和分位数。对于分类特征,你可以计算频率计数和百分比。这些统计信息为你提供了数据集中趋势和分布的初步概述。

摘要统计信息提供了对数据集中趋势、分布和分布的简洁且信息丰富的概述。这一步骤对于理解数据集的基本特征至关重要,无论它包含数值特征还是分类特征。以下部分将更详细地探讨生成摘要统计信息。

数值特征

对于数值特征,以下统计信息是一个良好的起点:

  • 平均值:平均值(平均数)是集中趋势的度量,表示所有数值的总和除以数据点的总数。它提供了对数据典型值的洞察。

  • 中位数:中位数是当所有数据点按升序或降序排序时的中间值。它是一个稳健的集中趋势度量,受极端值(异常值)的影响较小。

  • 标准差:标准差量化了数据中变化或分散的程度。标准差越高,数据分布越广。

  • 百分位数:百分位数表示特定数据值,以下哪个百分比的数据点落在该值以下。例如,第 25 百分位数(Q1)表示 25%的数据点位于其以下。百分位数有助于识别数据分布特征。

分类特征

分类特征有其自己的摘要统计信息,这将为您提供洞察:

  • 频率:对于分类特征,计算每个唯一类别的频率计数。这显示了每个类别在数据集中出现的频率。

  • 百分比:将频率计数表示为相对于观察总数百分比,可以提供对每个类别相对普遍性的洞察。

生成摘要统计信息具有多个目的:

  • 了解您的数据:摘要统计信息有助于您了解数值数据的典型值和分布。对于分类数据,它显示了类别的分布。

  • 识别异常值:异常值,即与正常值显著不同的数据点,通常可以通过摘要统计信息检测到。异常高的或低的平均值可能表明存在异常值。

  • 数据质量评估:摘要统计信息可以揭示缺失值,这些值可能在您的数据集中以 NaN 的形式出现。识别缺失数据对于数据清理至关重要。

  • 初步洞察:这些统计信息提供了对数据结构的初步洞察,这可以指导后续分析和可视化选择。

在 Python 中,如pandas之类的库使计算摘要统计信息变得简单直接。对于数值数据,您可以使用如.mean().median().std().describe()之类的函数。对于分类数据,.value_counts()和自定义函数可以计算频率计数和百分比。

以下是一个示例,说明您如何使用 Python 和pandas生成数值和分类数据的摘要统计信息。我们将为演示目的创建样本数据:

import pandas as pd
import random
# Create a sample DataFrame
data = {
    'Age': [random.randint(18, 60) for _ in range(100)],
    'Gender': ['Male', 'Female'] * 50,
    'Income': [random.randint(20000, 100000) for _ in range(100)],
    'Region': ['North', 'South', 'East', 'West'] * 25
}
df = pd.DataFrame(data)
# Calculate summary statistics for numerical features
numerical_summary = df.describe()
# Calculate frequency counts and percentages for categorical features
categorical_summary = df['Gender'].value_counts(normalize=True)
print("Summary Statistics for Numerical Features:")
print(numerical_summary)
print("\nFrequency Counts and Percentages for Categorical Features (Gender):")
print(categorical_summary)

在这个例子中,我们创建了一个包含Age(年龄)、Gender(性别)、Income(收入)和Region(地区)列的样本DataFrame,命名为df。我们使用df.describe()计算数值特征(AgeIncome)的摘要统计(均值、标准差、最小值、最大值、四分位数等)。然后我们使用df['Gender'].value_counts(normalize=True)计算Gender分类特征的频率计数和百分比。normalize=True参数将计数表示为百分比。如果设置为Falsevalue_counts()命令将返回一个包含Gender列中每个唯一值原始计数的序列。

你可以通过将数据加载到pandas DataFrame中,然后应用这些摘要统计函数来调整此代码以适应你的 Excel 数据集。

一旦你生成了摘要统计,你将为你的数据探索之旅打下坚实的基础。这些统计提供了进一步分析和可视化的起点,帮助你发现 Excel 数据集中的宝贵见解。

数据分布

理解你数据的分布是基础性的。它是正态分布、偏斜,还是遵循其他分布?识别数据的分布有助于后续的统计分析模型选择。

在深入挖掘你的数据之前,了解其分布是至关重要的。数据的分布指的是数据值是如何分布或排列的。了解数据分布有助于你在统计分析建模方面做出更好的决策。以下是一些与数据分布相关的关键概念:

  • 正态分布:在正态分布中,数据对称地分布在均值周围,形成一个钟形曲线。当数据遵循正态分布时,许多统计技术都很容易应用。你可以使用直方图和 Q-Q 图等可视化方法或 Shapiro-Wilk 测试等统计测试来检查正态性。

  • 偏度:偏度衡量数据分布的不对称性。正偏表示分布的尾部延伸到右侧,而负偏则表示延伸到左侧。识别偏度很重要,因为它可能影响某些统计测试的有效性。

  • 峰度:峰度衡量分布的“重尾性”或“尖峰性”。高峰度值表示重尾,而低值表示轻尾。理解峰度有助于选择合适的统计模型。

  • 其他分布:数据可以遵循各种分布,如指数分布、对数正态分布、泊松分布或均匀分布。计数通常遵循泊松分布,降雨量是对数正态分布的,这些分布无处不在!在选择统计模型和进行预测时,识别正确的分布是至关重要的。

要使用 Python 分析数据分布,你可以创建诸如直方图、核密度图和箱线图等可视化图表。此外,统计测试和 SciPy 等库可以帮助你识别和量化与正态性的偏差。

让我们看看一个示例代码片段,该代码片段从lognormal分布生成样本数据,执行 Shapiro-Wilk 测试,创建具有Normallognormal分布的 Q-Q 图,并计算偏度和峰度统计量!

首先,让我们生成一些样本数据:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
import statsmodels.api as sm
# Generate sample data from a lognormal distribution
np.random.seed(0)
data = np.random.lognormal(mean=0, sigma=1, size=1000)
# Create a Pandas DataFrame
df = pd.DataFrame({'Data': data})
# Next, we can plot a histogram of the data to get visual insights into the distribution:
# Plot a histogram of the data
plt.hist(data, bins=30, color='skyblue', edgecolor='black')
plt.title('Histogram of Data')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.show()

结果直方图显示了一个非常明显的偏斜,这使得Normal分布不太可能,而对数正态分布很可能是最佳选择(考虑到样本数据的生成方式,这一点并不令人惊讶):

图 8.6 – 数据的直方图

图 8.6 – 数据的直方图

接下来,我们可以进行一些基本的统计分析来确认从直方图产生的怀疑——首先进行正态性的 Shapiro-Wilk 检验,然后绘制Normal分布的 Q-Q 图,最后绘制与疑似lognormal分布的 Q-Q 图:

# Perform the Shapiro-Wilk test for normality
shapiro_stat, shapiro_p = stats.shapiro(data)
is_normal = shapiro_p > 0.05  # Check if data is normally distributed
print(f'Shapiro-Wilk p-value: {shapiro_p}')
print(f'Is data normally distributed? {is_normal}')
# Create Q-Q plot with a Normal distribution
sm.qqplot(data, line='s', color='skyblue')
plt.title('Q-Q Plot (Normal)')
plt.xlabel('Theoretical Quantiles')
plt.ylabel('Sample Quantiles')
plt.show()
# Create Q-Q plot with a lognormal distribution
log_data = np.log(data)
sm.qqplot(log_data, line='s', color='skyblue')
plt.title('Q-Q Plot (Lognormal)')
plt.xlabel('Theoretical Quantiles')
plt.ylabel('Sample Quantiles')
plt.show()

第一个 Q-Q 图显示,Normal分布对数据是一个非常差的拟合:

图 8.7 – 正态分布的 Q-Q 图

图 8.7 – 正态分布的 Q-Q 图

下一个 Q-Q 图,这次是对lognormal分布的,显示了几乎完美的拟合,另一方面:

图 8.8 – 对数正态分布的 Q-Q 图

图 8.8 – 对数正态分布的 Q-Q 图

最后,我们计算偏度和峰度以确保我们走在正确的道路上,并打印出所有结果:

# Calculate skewness and kurtosis
skewness = stats.skew(data)
kurtosis = stats.kurtosis(data)
print(f'Skewness: {skewness}')
print(f'Kurtosis: {kurtosis}')

从直方图、Shapiro-Wilk 测试拒绝normal分布的假设、两个 Q-Q 图和偏度与峰度估计量来看,我们可以合理地得出结论,数据确实是从lognormal分布生成的!

现在是时候从单变量分析转向多个变量之间的关系了。

变量之间的关联

通过散点图和相关性矩阵探索变量之间的关系。识别特征之间的任何强相关性或依赖性。这一步可以在分析的后期阶段引导特征选择或工程。在本节中,我们将深入探讨使用 Python 研究这些关系的方法。

我们将使用以下库和样本数据集:

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import ppscore as pps
# Generate test data with three variables
np.random.seed(0)
data = {
    'Feature1': np.random.randn(100),
    'Feature2': np.random.randn(100) * 2,
}
# Create a linear Target variable based on Feature1 and a non-linear function of Feature2
data['Target'] = data['Feature1'] * 2 + np.sin(data['Feature2']) + np.random.randn(100) * 0.5
# Create a DataFrame
df = pd.DataFrame(data)

你可以将此代码改编为分析你在前几章中学到的 Excel 数据中变量之间的关系。

相关性热图

评估关系最常见的方法之一是通过绘制相关性热图。这个热图提供了数据集中数值变量之间相关性的视觉表示。使用Seaborn等库,你可以创建一个信息丰富的热图,该热图通过颜色编码相关性,使识别强和弱关系变得容易。

让我们看看如何做到这一点:

# Calculate and plot the correlation heatmap
corr_matrix = df.corr()
plt.figure(figsize=(8, 6))
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', fmt=".2f",
    linewidths=.5)
plt.title('Correlation Heatmap')
plt.show()

在此代码中,我们创建了一个相关性热图来可视化这些变量之间的关系。生成的热图提供了很好的见解:

图 8.9 – 相关性热图

图 8.9 – 相关性热图

预测能力分数 (PPS)

除了传统的相关性度量之外,PPS 还提供了关于变量之间非线性关系和预测能力的见解。PPS 量化了一个变量如何预测另一个变量。

现在,我们将演示如何使用 ppscore 库计算和可视化 PPS 矩阵,这将使你对数据的预测潜力有更深入的了解:

# Calculate the Predictive Power Score (PPS)
plt.figure(figsize=(8, 6))
matrix_df = pps.matrix(df)[['x', 'y', 'ppscore']].pivot(columns='x',
    index='y', values='ppscore')
sns.heatmap(matrix_df, vmin=0, vmax=1, cmap="Blues", linewidths=0.5,
    annot=True)
plt.title("Predictive Power Score (PPS) Heatmap")
plt.show()
# Additional insights
correlation_target = df['Feature1'].corr(df['Target'])
pps_target = pps.score(df, 'Feature1', 'Target') ['ppscore']
print(f'Correlation between Feature1 and Target: {correlation_target:.2f}')
print(f'Predictive Power Score (PPS) between Feature1 and Target: {pps_target:.2f}')

在这个代码片段中,我们计算了 PPS 矩阵,该矩阵衡量了每个特征相对于 目标 变量的预测能力。最后,我们计算了 特征 1目标 变量之间的相关性和 PPS。PPS 热图的结果有助于进一步了解变量之间的关系:

图 8.10 – PPS 热图

图 8.10 – PPS 热图

散点图

散点图是另一种用于可视化关系的宝贵工具。它们允许你通过在二维平面上绘制数据点来探索两个数值变量之间的交互。我们在 第六章 中介绍了创建散点图的方法。

可视化关键属性

可视化是理解数据的有力工具。你可以创建各种图表来可视化数据集的关键属性。对于数值数据,直方图、箱线图和散点图可以揭示数据分布、异常值和潜在的关联。分类数据可以通过条形图和饼图来探索,显示频率分布和比例。这些可视化提供了在仅汇总统计数据中可能不明显的信息。我们在 第六章 中介绍了这些方法。

摘要

在本章中,我们深入探讨了两个关键过程:使用 R 和 Python 进行数据清洗和 EDA,特别关注 Excel 数据。

数据清洗是一个基本步骤。我们学习了如何处理缺失数据,无论是通过插补、删除还是插值。处理重复数据也是另一个关键焦点,因为 Excel 数据通常来自多个地方,可能会受到冗余的困扰。强调正确分配数据类型,以防止由数据类型问题引起的分析错误。

在 EDA 领域,我们首先从汇总统计开始。这些指标,如数值特征的均值、中位数、标准差和百分位数,为我们提供了对数据集中趋势和变异性的初步了解。然后,我们探讨了数据分布,这对于后续的分析和建模决策至关重要。最后,我们深入研究了变量之间的关系,通过散点图和相关性矩阵来揭示特征之间的相关性依赖。

通过掌握这些技术,你将能够应对 Excel 数据的复杂性。你可以确保数据质量并利用其潜力为明智的决策提供支持。随后的章节将在此基础上构建,使你能够执行高级分析和可视化,从而从你的 Excel 数据集中提取可操作的见解。

在下一章中,我们将把清洗和探索后的数据充分利用起来:我们将从统计分析开始,特别是线性回归和逻辑回归。

第九章:统计分析:线性与逻辑回归

欢迎阅读我们关于使用 R 和 Python 进行线性与逻辑回归的全面指南,我们将使用两个流行的框架:tidymodels和基础 R 与 Python 来探索这些重要的统计技术。无论您是数据科学爱好者还是希望提升技能的专业人士,本教程都将帮助您深入理解线性逻辑回归,以及如何在 R 和 Python 中实现它们。现在,执行线性与逻辑回归成为可能。问题在于,线性回归只能应用于单个未分组的数据序列,而执行逻辑回归则较为繁琐,可能需要使用外部求解器插件。此外,这个过程只能针对未分组或非嵌套数据进行。在 R 和 Python 中,我们没有这样的限制。

在本章中,我们将使用基础 R、Python 以及tidymodels框架来介绍以下主题:

  • 在基础 R、Python 以及tidymodels框架中执行线性回归,以及在 Python 中

  • 在基础 R、Python 以及tidymodels框架中执行逻辑回归,以及在 Python 中

技术要求

本章所有代码可在 GitHub 上通过此 URL 找到:github.com/PacktPublishing/Extending-Excel-with-Python-and-R/tree/main/Chapter9。为了跟随教程,您需要安装以下 R 包:

  • readxl 1.4.3

  • performance 0.10.8

  • tidymodels 1.1.1

  • purrr 1.0.2

我们将首先了解线性与逻辑回归是什么,然后深入探讨所有相关细节。

线性回归

线性回归是一种基本的统计方法,用于建模因变量(通常表示为“Y”)与一个或多个自变量(通常表示为“X”)之间的关系。它的目标是找到最佳拟合的线性方程,描述自变量的变化如何影响因变量。你们中许多人可能知道这是普通最小二乘法OLS)。

简而言之,线性回归帮助我们根据一个或多个输入特征预测连续数值结果。为了使其工作,如果您不知道,必须满足许多假设。如果您想了解更多,简单的搜索会为您带来大量关于这些假设的好信息。在本教程中,我们将深入探讨简单线性回归(一个自变量)和多元线性回归(多个自变量)。

逻辑回归

逻辑回归是另一种重要的统计技术,主要用于二元分类问题。逻辑回归不是预测连续结果,而是预测事件发生的概率,通常表示为“是”或“否”的结果。这种方法在需要模拟事件发生可能性的场景中特别有用,例如,客户是否会流失或电子邮件是否为垃圾邮件。逻辑回归模型独立变量与二元结果的逻辑优势之间的关系。

框架

我们将探讨两种在 R 中实现线性回归和逻辑回归的方法。首先,我们将使用基础 R 框架,这是理解基本概念和函数的绝佳起点。然后,我们将深入研究tidymodels,这是 R 中建模和机器学习的现代且整洁的方法。tidymodels提供了一种一致且高效的方式来构建、调整和评估模型,使其成为数据科学家的一个宝贵工具。在 Python 中,我们将使用两个突出的库来并行这一探索:sklearnstatsmodelssklearn,或 Scikit-learn,提供了一系列简单且高效的预测数据分析工具,这些工具对每个人都是可访问的,并且可以在各种环境中重复使用。statsmodels更专注于统计模型和假设检验。这两个 Python 库共同提供了一个强大的框架,用于实现线性回归和逻辑回归,满足机器学习和统计需求。

在本章中,我们将提供逐步说明、代码示例和实用见解,以确保你可以自信地将线性回归和逻辑回归技术应用于自己的数据分析项目中。

让我们开始这段学习之旅,并解锁 R 中回归分析的力量!有了这个基础,我们将转向第一个示例,使用我们保存在第一章中的iris数据集在基础 R 中进行操作。

在 R 中执行线性回归

在本节中,我们将使用 R 进行线性回归,包括基础 R 和通过tidymodels框架。在本节中,你将学习如何在包含不同组的数据集中进行这一操作。我们将这样做,因为如果你能学会这种方式,那么在单一组中进行操作就会变得简单,因为不需要按组分组数据并按组执行操作。这里的思路是,通过在分组数据上操作,我们希望你能学会一项额外的技能。

基础 R 中的线性回归

我们将要展示的第一个示例是使用lm()函数在基础 R 中执行线性回归。让我们直接使用iris数据集来深入探讨。

我们将把代码分解成块,并讨论每个步骤中发生的事情。对我们来说,第一步是使用library命令将必要的包引入我们的开发环境:

library(readxl)

在本节中,我们正在加载一个名为readxl的库。库是预先编写的 R 函数和代码的集合,我们可以在自己的 R 脚本中使用它们。在这种情况下,我们正在加载readxl库,它通常用于从 Excel 文件中读取数据。路径假设你有一个名为chapter1的文件夹,其中包含一个名为iris_data.xlsx的数据文件:

df <- read_xlsx(
  path = "chapter1/iris_data.xlsx",
  sheet = "iris"
)
head(df)

在这里,我们正在从位于chapter1文件夹中的 Excel 文件iris_data.xlsx中读取数据。我们特别读取该 Excel 文件中的iris工作表。read_xlsx函数用于此目的。得到的数据存储在一个名为df的变量中。head(df)函数显示这个数据框(df)的前几行,以便我们可以看到它的样子:

iris_split <- split(df, df$species)

这段代码将df数据集根据species列中的唯一值分割成多个子集。结果是包含多个数据框的列表,其中每个数据框只包含对应特定iris物种的行。

现在,我们将定义将是什么是因变量和自变量,以及formula对象:

dependent_variable <- "petal_length"
independent_variables <- c("petal_width", "sepal_length", "sepal_width")
f_x <- formula(
  paste(
dependent_variable,
"~",
paste(independent_variables, collapse = " + ")
)
)

在这里,我们正在定义线性回归所需的变量。dependent_variablepetal_length,这是我们想要预测的变量。independent_variablespetal_widthsepal_lengthsepal_width,我们将使用这些变量来预测因变量。

代码随后创建了一个f_x公式,它代表了线性回归模型。它本质上表示我们想要使用其他列出的变量来预测petal_length,这些变量通过加号分隔:

perform_linear_regression <- function(data) {
  lm_model <- lm(f_x, data = data)
  return(lm_model)
}

在这部分,我们正在定义一个名为perform_linear_regression的自定义 R 函数。这个函数接受一个data参数,它是一个数据框。在函数内部,我们使用lm函数执行线性回归,使用我们之前定义的f_x公式和提供的数据框。得到的线性模型存储在lm_model中,并将其作为函数的输出返回:

results <- lapply(iris_split, perform_linear_regression)

在这里,我们正在使用lapply函数将perform_linear_regression函数应用于iris数据集的每个子集。这意味着我们正在为每个 iris 物种单独运行线性回归,并将结果存储在results列表中:

lapply(results, summary)

这段代码再次使用lapply,但这次我们将summary函数应用于results列表中的每个线性回归模型。summary函数提供了关于线性回归模型的统计信息,例如系数和 R-squared 值:

par(mfrow = c(2,2))
lapply(results, plot)
par(mfrow = c(1, 1))

这几行代码用于创建一组四个图表来可视化模型性能。我们首先使用par(mfrow = c(2,2))设置图表布局为 2x2 网格,这样 4 个图表将显示在一个 2x2 网格中。然后,我们使用lapply来绘制results列表中的每个线性回归模型。最后,我们使用par(mfrow = c(1, 1))将绘图布局重置为默认设置:

lm_models <- lapply(
iris_split,
function(df) lm(f_x, data = df)
)

这一部分与之前完成的线性回归分析相同,但将线性模型创建和总结结合成一个更简洁的形式,使用匿名函数实现。首先,它将 lm 函数应用于 iris_split 中的每个物种子集,创建一个存储在 lm_models 中的线性模型列表。然后,使用 lapply 获取这些线性模型的总结。

总结来说,这段 R 代码从 Excel 文件中读取鸢尾花数据,对 iris 的每个物种进行线性回归,总结结果,并创建可视化来评估模型性能。它详细分析了每个物种的因变量(petal_length)如何受自变量(petal_widthsepal_lengthsepal_width)的影响。

使用 tidymodels 和 purrr 进行线性回归

既然我们已经介绍了如何在 R 中对 iris 数据集进行简单线性回归,我们将使用 tidymodels 框架进行相同的操作。让我们直接进入正题:

f_x <- formula(paste("petal_width", "~", "petal_length + sepal_width + sepal_length"))

此部分定义了线性回归模型的公式。formula() 函数接受两个参数:响应变量和预测变量。响应变量是我们想要预测的变量,预测变量是我们认为可以帮助我们预测响应变量的变量。在这种情况下,响应变量是 petal_width,预测变量是 petal_lengthsepal_widthsepal_length

library(dplyr)
library(tidyr)
library(purrr)
library(tidymodels)
nested_lm <- df |>
 nest(data = -species) |>
 mutate(split = map(data, ~ initial_split(., prop = 8/10)),
        train = map(split, ~ training(.)),
        test = map(split, ~ testing(.)),
        fit  = map(train, ~ lm(f_x, data = .)),
        pred = map2(.x = fit, .y = test, ~ predict(object = .x, newdata = .y)))

此部分使用 tidyr 包中的 nest() 函数创建一个嵌套的线性回归模型。nest() 函数根据指定的变量分组数据,在这种情况下,是 species 变量。

对于每个组,nest() 函数创建一个包含该组数据的列表。然后,使用 mutate() 函数向嵌套数据框添加新列。

split() 函数用于将每个组中的数据随机分成训练集和测试集。然后,使用 training()testing() 函数分别选择训练集和测试集。通过 map()map2(),我们可以遍历一个向量或列表,或者两个向量或列表,并应用一个函数。

使用 lm() 函数将线性回归模型拟合到每个组中的训练数据。然后,使用 predict() 函数预测每个组测试数据的响应变量,使用拟合的线性回归模型:

nested_lm |>
 select(species, pred) |>
 unnest(pred)

此部分从嵌套数据框中选择 speciespred 列,并解包 pred 列。unnest() 函数将嵌套数据框转换为常规数据框,每行对应一个观测值。

结果数据框是一个嵌套的线性回归模型,每个物种都有一个拟合的线性回归模型。

让我们看看一个例子。我们将使用之前创建的f_x公式以及我们在开头创建的df tibble变量。以下代码展示了如何使用嵌套线性回归模型预测新鸢尾花的花瓣宽度:

library(dplyr)
library(tidyr)
library(purrr)
library(tidymodels)
# Create a nested linear regression model
nested_lm <- df |>
 nest(data = -species) |>
 mutate(split = map(data, ~ initial_split(., prop = 8/10)),
        train = map(split, ~ training(.)),
        test = map(split, ~ testing(.)),
        fit  = map(train, ~ lm(f_x, data = .)),
        pred = map2(.x = fit, .y = test, ~ predict(object = .x, newdata = .y)))
# Predict the petal width for a new iris flower
new_iris <- data.frame(sepal_length = 5.2, sepal_width = 2.7, 
    petal_length = 3.5)
# Predict the petal width
predicted_petal_width <- predict(nested_lm[[1]]$fit, 
    newdata = new_iris))
# Print the predicted petal width
print(predicted_petal_width)

这是输出结果:

1.45

预测的花瓣宽度是 1.45 厘米。我们现在已经用基本示例完成了 R 中的线性回归的讲解。我们将在下一节继续本章,讲解在 R 中执行逻辑回归。

在 R 中执行逻辑回归

正如我们在线性回归部分所做的那样,在这一节中,我们也将使用基础 R 和tidymodels框架执行逻辑回归。我们将只使用Titanic数据集执行一个简单的二元分类回归问题,我们将决定某人是否会幸存。让我们直接进入正题。

逻辑回归使用基础 R

为了开始,我们将从Titanic数据集上的基础 R 实现逻辑回归开始,我们将对Survived的响应进行建模。所以,让我们直接进入正题。

下面的代码将执行数据建模,并解释正在发生的事情:

library(tidyverse)
df <- Titanic |>
       as.data.frame() |>
       uncount(Freq)

这段代码块首先加载了一个名为tidyverse的库,其中包含各种数据处理和可视化工具。然后,通过使用|>运算符对Titanic数据集(假设它存在于你的环境中)执行三个操作来创建一个名为df的数据框,其中我们使用as.data.frame()将数据集转换为数据框,接着是uncount(Freq),它根据Freq列中的值重复数据集中的每一行。这通常是为了扩展汇总数据:

set.seed(123)
train_index <- sample(nrow(df), floor(nrow(df) * 0.8), replace = FALSE)
train <- df[train_index, ]
test <- df[-train_index, ]

本节内容是关于将数据分为训练集和测试集,这在机器学习中是一种常见的做法:

  • set.seed(123):这设置了一个随机种子以确保可重复性,确保每次随机操作产生相同的结果。

  • sample(nrow(df), floor(nrow(df) * 0.8), replace = FALSE):这随机选择df数据框(训练集)中的 80%的行,不进行替换,并将它们的索引存储在train_index中。

  • train <- df[train_index, ]:这是通过使用train_index索引从df中选择行来创建训练集。

  • test <- df[-train_index, ]:这是通过从df中选择不在训练集中的行来创建测试集。接下来,我们创建模型。

    model <- glm(Survived ~ Sex + Age + Class, data = train, family = "binomial")
    

现在,让我们按以下方式讨论模型代码:

  • 这个代码块使用glm函数训练逻辑回归模型。

  • 该模型被训练来根据训练数据中的SexAgeClass变量预测Survived变量。在这里,Age实际上是离散的。

  • family = "binomial" 参数指定这是一个二元分类问题,其中结果要么是 Yes,要么是 No。以下链接有助于选择合适的家族:stats.stackexchange.com/a/303592/35448

现在,让我们设置模型预测和响应变量:

predictions <- predict(model, newdata = test, type = "response")
pred_resp <- ifelse(predictions <= 0.5, "No", "Yes")

现在,让我们回顾一下我们刚才所做的工作:

  • 这里,我们使用训练好的模型对测试集进行预测。

  • predict(model, newdata = test, type = "response") 计算测试集中每个乘客的生存预测概率。

  • ifelse(predictions <= 0.5, "No", "Yes") 将这些概率转换为二元预测:如果概率小于或等于 0.5,则输出 "No",否则输出 "Yes"。这是一种常见做法,但您必须首先了解您的项目,才能确定这种方法是否正确。现在,让我们继续到 accuracy 变量:

    accuracy <- mean(pred_resp == test$Survived)
    

我们通过以下方式创建了 accuracy 变量:

  • 这一行通过比较 pred_resp(模型的预测)与测试集中的实际生存状态(test$Survived)来计算模型预测的准确度。

  • 它计算了结果逻辑值的平均值,其中 TRUE 代表正确预测,而 FALSE 代表错误预测。现在,让我们回顾一下代码的其余部分:

    print(accuracy)
    table(pred_resp, test$Survived)
    

代码打印了两件事:

  • 测试集上模型的准确度。

  • 一个混淆矩阵,显示了有多少预测是正确的,有多少是错误的。如果您想更深入地了解混淆矩阵,这里有一个好的链接:www.v7labs.com/blog/confusion-matrix-guide

总结来说,这段代码加载了一个数据集,将其分为训练集和测试集,训练了一个逻辑回归模型来预测生存,评估了模型的准确度,并显示了结果。这是一个二元分类机器学习工作流程的基本示例。现在我们已经覆盖了在基础 R 中执行分类问题的逻辑回归,我们将尝试使用 tidymodels 框架来完成同样的任务。

使用 tidymodels 进行逻辑回归

在本节中,我们将使用 tidymodels 框架对 Titanic 数据集进行逻辑回归。由于我们已经在基础 R 中完成了这项工作,让我们直接进入正题:

library(tidymodels)
library(healthyR.ai)

这段代码加载了我们将需要用于分析的两个库:tidymodelshealthyR.aitidymodels 是一个库,它为许多机器学习算法提供了一个通用接口,而 healthyR.ai 提供了一套用于评估机器学习模型性能的工具:

df <- Titanic |>
    as_tibble() |>
    uncount(n) |>
    mutate(across(where(is.character), as.factor))

这段代码将Titanic数据集转换为tibble,这是一种与tidymodels兼容的数据结构。它还取消了n列的计数,该列包含每行在数据集中出现的次数,由uncount()函数创建。最后,它将数据集中的所有字符变量转换为因子:

# Set seed for reproducibility
set.seed(123)
# Split the data into training and test sets
split <- initial_split(df, prop = 0.8)
train <- training(split)
test <- testing(split)

这段代码将df数据集拆分为训练集和测试集。训练集用于训练模型,而测试集用于评估模型在未见数据上的性能。使用tidymodels中的initial_split()函数进行拆分。prop参数指定了应该用于训练的数据比例。在这种情况下,我们使用 80%的数据进行训练,20%的数据进行测试:

# Create a recipe for pre-processing
recipe <- recipe(Survived ~ Sex + Age + Class, data = train)
# Specify logistic regression as the model
log_reg <- logistic_reg() |> set_engine("glm", family = "binomial")
# Combine the recipe and model into a workflow
workflow <- workflow() %>% add_recipe(recipe) %>% add_model(log_reg)
# Train the logistic regression model
fit <- fit(workflow, data = train)

这段代码训练了一个逻辑回归模型来预测泰坦尼克号上的生存情况。使用tidymodels中的recipe()函数来预处理数据。使用tidymodels中的logistic_reg()函数来指定逻辑回归模型。使用tidymodels中的workflow()函数将 recipe 和模型组合成一个工作流程。最后,使用tidymodels中的fit()函数在训练数据上训练模型:

# Predict on the test set
predictions <- predict(fit, new_data = test) |> bind_cols(test) |> select(Class:Survived, .pred_class)
# Better method
pred_fit_tbl <- fit |> augment(new_data = test)

这段代码预测测试集中每位乘客的生存概率。使用tidymodels中的predict()函数进行预测。new_data参数指定了我们想要进行预测的数据。在这种情况下,我们正在对测试集进行预测。使用bind_cols()函数将预测绑定到测试集数据上。使用select()函数选择我们想要保留的列。pred_fit_tbl对象是一个包含模型预测以及真实生存标签的tibble实例。该对象将用于评估模型的性能:

# Accuracy metrics for the model to be scored against from the healthyR.ai package
perf <- hai_default_classification_metric_set()
# Calculate the accuracy metrics
perf(pred_fit_tbl, truth = Survived, estimate = .pred_class)
# Print the confusion matrix
predictions |> conf_mat(truth = Survived, estimate = .pred_class)

准确度检查代码块通过使用来自 healthyR.ai 包的hai_default_classification_metric_set()函数创建一组默认分类指标来评估模型在测试集上的性能。这些指标包括准确率、精确率、召回率和 F1 分数。

然后,使用perf()函数在测试集上计算准确度指标。pred_fit_tbl对象是一个包含模型预测以及真实生存标签的数据框。truthestimate参数指定了数据框中包含真实标签和预测标签的列。

然后,使用conf_mat()函数打印模型的混淆矩阵。混淆矩阵是一个表格,显示了模型正确和错误预测的观测数。

最后,可以使用 broom 包中的 tidy()glance() 函数来整理和总结拟合的模型。tidy() 函数将模型对象转换为 tibble 实例,这是一种易于处理的数据结构。glance() 函数打印出模型的摘要,包括模型中所有变量的系数、标准误差和 p 值。

这里是对准确性检查代码块中计算的每个准确性指标的一个简单解释:

  • 准确率:模型的准确率是指模型正确预测的观测值的比例。

  • 精确率:模型的精确率是指正确预测的正预测的比例。

  • 召回率:模型的召回率是指模型正确预测的实际正观测值的比例。

  • F1 分数:F1 分数是精确率和召回率的调和平均值。它是衡量模型性能的良好整体指标。

混淆矩阵是理解模型性能的有用工具。理想的混淆矩阵将对角线上的所有观测值都正确预测。然而,在实践中,没有模型是完美的,总会有一些观测值被错误预测。

最后,我们将使用 接收者操作特征(ROC)曲线来可视化模型。要了解更多关于这种曲线的信息,请参阅以下链接:www.tmwr.org/performance。以下是创建 ROC 曲线的代码:

roc_curve(
  pred_fit_tbl, truth = Survived, .pred_Yes,
  event_level = "second"
) |>
  autoplot()

这里是输出结果:

图 9.1 – 逻辑回归模型的 ROC 曲线

图 9.1 – 逻辑回归模型的 ROC 曲线

现在,我们已经学会了如何在基础 R 和 tidymodels 模型框架中执行线性回归和逻辑回归。我们使用 Titaniciris 数据集做到了这一点。现在是时候在 Python 中做同样的事情了!

使用 Excel 数据在 Python 中执行线性回归

在 Python 中,可以使用 pandasscikit-learnstatsmodelsmatplotlib 等库执行线性回归。以下是一个逐步的代码示例:

  1. 首先,导入必要的库:

    # Import necessary libraries
    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn.model_selection import train_test_split
    import statsmodels.api as sm
    from statsmodels.graphics.regressionplots import plot_regress_exog
    from statsmodels.graphics.gofplots import qqplot
    
  2. 然后,我们创建一个包含测试数据的 Excel 文件。当然,在实际场景中,你不需要模拟数据 - 你会跳过这一步,在加载必要的库之后(见下一步)从 Excel 加载数据:

    # Step 0: Generate sample data and save as Excel file
    np.random.seed(0)
    n_samples = 100
    X = np.random.rand(n_samples, 2)  # Two features
    y = 2 * X[:, 0] + 3 * X[:, 1] + np.random.randn(n_samples)
    # Linear relationship with noise
    # Create a pandas DataFrame
    data = {'Feature1': X[:, 0], 'Feature2': X[:, 1], 'Target': y}
    df = pd.DataFrame(data)
    # Save the data to Excel
    df.to_excel("linear_regression_input.xlsx")
    
  3. 接下来,使用你在上一章中学到的工具从 Excel 文件中导入测试数据,并对其进行分析准备:

    # Step 1: Import Excel data into a pandas DataFrame
    excel_file = "linear_regression_input.xlsx"
    df = pd.read_excel(excel_file)
    # Step 2: Explore the data
    # Use the tools learned in the previous chapter on EDA
    # Step 3: Data Preparation (if needed)
    # Use the tools learned in the previous chapter on data cleaning
    
  4. 现在,我们已经准备好进行实际分析了。将数据分为训练数据和测试数据,以便我们可以在一个专门的数据(子集)上评估模型,然后在训练数据上拟合 普通最小二乘法(OLS)线性模型:

    # Step 4: Split data into training and testing sets
    X = df[['Feature1', 'Feature2']] # Independent variables
    y = df['Target'] # Dependent variable
    # Split the data into training and test set using a fixed random seed for reproducibility
    X_train, X_test, y_train, y_test = train_test_split(X, y, 
        test_size=0.2, random_state=42)
    # Step 5: Fit the Linear Regression model
    # Add a constant (intercept) to the independent variables
    X_train = sm.add_constant(X_train)
    X_test = sm.add_constant(X_test)
    # Fit the linear model
    model = sm.OLS(y_train, X_train).fit()
    

    注意,在分割测试集和训练集之前,作为数据清洗过程的一部分进行插补可能会导致测试集受到训练集的污染。在执行数据清洗和准备步骤时要对此保持警觉!

  5. 接下来,评估训练好的模型在测试数据上的表现:

    # Step 6: Model Evaluation
    y_pred = model.predict(X_test)
    # Print the model summary
    print(model.summary())
    

    这将生成输出摘要统计信息,这些信息可以提供关于数据集中关系的重要见解:

图 9.2 – 拟合模型的摘要统计

图 9.2 – 拟合模型的摘要统计

实际上对模型结果的解释超出了本书的范围,但以下是一些帮助你开始的提示:

  • 系数:与模型中每个自变量(预测器)相关的系数告诉你关系的强度和方向。正系数表示正相关,这意味着随着预测器的增加,目标变量倾向于增加。相反,负系数表示负相关。

  • 截距:截距表示当所有预测变量都设置为零时目标变量的预测值。在分析上下文中考虑截距的值是至关重要的。

  • R 平方(R²):R 平方值衡量模型的拟合优度。它告诉你目标变量中可以由预测器解释的方差比例。较高的 R 平方值(接近 1)表示更好的拟合。请注意,添加更多变量总会增加这个度量。一个“更好的”拟合可能会导致“过拟合”,这是我们不想看到的。你可能想检查模型拟合选择标准,如 Mallow 的 Cp、AIC、BIC 和调整 R 平方,后者对用于拟合模型的参数数量进行惩罚。

  • P 值:与系数相关的 P 值有助于确定每个预测器的统计显著性。较低的 P 值表示更大的显著性(在拒绝零假设的证据更强的意义上)。如果一个 P 值小于选定的显著性水平(例如,0.05),你可以得出结论,该预测器对目标变量有统计显著的效应。请注意,有很好的理由不单独依赖 P 值;请参阅关于 p-hacking 和统计科学相关主题的持续辩论。

  • 残差:检查残差(观测值与预测值之间的差异)对于评估模型性能至关重要。理想情况下,残差应该是随机的,没有明显的模式。残差中的模式可能表明模型存在误设。

  • 置信区间:系数周围的置信区间提供了一个范围,其中真实的总体参数很可能位于其中。较宽的区间表示更大的不确定性。

  • F 统计量:F 统计量检验模型的总体显著性。小的 F 统计量表明模型对目标变量的方差解释不多,而大的值则表示更好的整体拟合。

  • 调整后的 R 平方:调整后的 R 平方根据模型中的预测因子数量调整 R 平方值。它帮助您确定添加更多预测因子是否可以改善模型的拟合度。

通过仔细检查这些元素,您可以深入了解线性模型与您的数据拟合得如何,预测变量的显著性以及模型的总体质量。这些信息对于做出明智的决策和从分析中得出有意义的结论至关重要。

在模型训练和拟合评估后,我们可以可视化结果以帮助解释。以下代码创建了一个预测值与观察值之间的散点图:

plt.scatter(X_test['Feature1'], y_test, color='blue', label='Actual')
plt.scatter(X_test['Feature1'], y_pred, color='red', 
    label='Predicted')
plt.xlabel('Feature1')
plt.ylabel('Target')
plt.title('Linear Regression Prediction')
plt.legend()
plt.show()

这是它的散点图:

图 9.3 – 线性回归预测图

图 9.3 – 线性回归预测图

此外,我们还可以创建诊断图和可视化,如残差图和 Q-Q 图,这有助于您识别模型中可能存在的问题,例如异方差性或异常值:

# Set the backend to 'TkAgg' before generating the plots if needed – comment out this line if in WSL or other non-interactive environment
plt.switch_backend('TkAgg')
# Residuals
fig, ax = plt.subplots(figsize=(12, 8))
plot_regress_exog(model, "Feature1", fig=fig)
plt.show()
# Q-Q plot:
qqplot(model.resid, line="s")
plt.show()

前两个图表看起来像这样:

图 9.4 – 残差图

图 9.4 – 残差图

图 9.5 – 残差 Q-Q 图

图 9.5 – 残差 Q-Q 图

最后,我们可以将结果导出到 Excel。这将在下一小节中详细介绍。

作为旁注,scikit-learn 也内置了线性模型,但它没有提供我们在前面代码中使用的手动汇总统计信息。

这段代码展示了使用 Python 和 Excel 数据进行基本线性回归工作流程。让我们继续学习逻辑回归!

使用 Excel 数据在 Python 中进行逻辑回归

在以下代码中,我们根据简单条件生成具有两个特征(Feature1Feature2)和二元目标变量(Target)的随机样本数据。我们执行逻辑回归,使用准确率、混淆矩阵和分类报告评估模型,可视化二元分类的结果,并解释系数。

下面是一个逐步的代码示例:

  1. 再次,我们从导入必要的库开始:

    # Import necessary libraries
    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn.model_selection import train_test_split
    from sklearn.linear_model import LogisticRegression
    from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
    

    对于这个例子,我们将使用不同的样本数据集:

    # Step 0: Generate sample data
    np.random.seed(0)
    n_samples = 100
    X = np.random.rand(n_samples, 2)  # Two features
    y = (X[:, 0] + X[:, 1] > 1).astype(int)  # Binary classification based on a condition
    # Create a pandas DataFrame
    data = {'Feature1': X[:, 0], 'Feature2': X[:, 1], 'Target': y}
    df = pd.DataFrame(data)
    df.to_excel("logistic_regression_input.xlsx")
    
  2. 在 Excel 中有了您的数据后,我们可以读取它并为建模步骤做准备:

    # Step 1: Import Excel data into a pandas DataFrame
    excel_file = "logistic_regression_input.xlsx"
    df = pd.read_excel(excel_file)
    # Step 2: Split data into training and testing sets
    X_train, X_test, y_train, y_test = train_test_split(X, y,
        test_size=0.2, random_state=42)
    
  3. 现在,我们可以创建和拟合一个模型。这次我们将使用 scikit-learn 库:

    # Step 3: Create and train the logistic regression model
    model = LogisticRegression()
    model.fit(X_train, y_train)
    
  4. 在模型拟合后,我们现在可以可视化结果:

    # Step 4: Visualization
    # Visualization for binary classification
    plt.scatter(X_test[y_test == 1][:, 0], 
        X_test[y_test == 1][:, 1], color='blue', 
        label='Class 1 (Actual)')
    plt.scatter(X_test[y_test == 0][:, 0], 
        X_test[y_test == 0][:, 1], color='red', 
        label='Class 0 (Actual)')
    plt.xlabel('Feature1')
    plt.ylabel('Feature2')
    plt.title('Logistic Regression Prediction')
    plt.legend()
    plt.show()
    
  5. 与线性回归不同,我们需要不同的拟合优度指标,因为我们使用逻辑回归进行二元分类:

    # Step 5: Model Evaluation and Interpretation
    y_pred = model.predict(X_test)
    accuracy = accuracy_score(y_test, y_pred)
    conf_matrix = confusion_matrix(y_test, y_pred)
    class_report = classification_report(y_test, y_pred)
    print("Accuracy:", accuracy)
    print("Confusion Matrix:\n", conf_matrix)
    print("Classification Report:\n", class_report)
    

    结果看起来像这样:

图 9.6 – 逻辑回归预测图

图 9.6 – 逻辑回归预测图

这是代码结果:

图 9.7 – 模型摘要统计

图 9.7 – 模型摘要统计

为了解释前面的结果,您可以从以下内容开始:

  • 准确度是一个基本指标,表示正确预测的实例数与总实例数的比率。虽然容易理解,但如果类别之间存在不平衡,准确度可能会误导。

  • 混淆矩阵提供了更详细的视图。它将预测分解为四个类别:真正例、真负例、假正例和假负例。这个矩阵清晰地说明了模型在正确分类正负实例方面的表现。

  • 分类报告提供了全面的摘要。它包括针对两个类别的精确度召回率F1 分数支持度等指标。精确度衡量预测为正的实例中有多少实际上是正的,而召回率量化了多少实际正例被正确预测。F1 分数平衡了精确度召回率支持度表示每个类别的实例数量。这些指标共同提供了对模型在二元分类任务中性能的更细致评估。

您可以使用此示例数据和代码进行逻辑回归的测试和实验。

请注意,与流行的(但错误)说法相反,逻辑回归也可以用作回归——使其成为分类器的是预测概率的任意截止点。对于某些用例,您可能希望使用原始回归输出(例如,如果您对数据点属于某个类别的预测概率感兴趣,而不仅仅是更可能的类别),而对于其他用例,您可能希望调整截止点(例如,如果存在先验领域信息表明 50% 不是正确的截止点)。

就这样!逻辑回归是一个相对简单的模型,具有许多优点。它性能良好,易于拟合,易于解释,并且非常灵活。它最常用于具有领域知识驱动的截止点的分类,但本质上,它仍然是一种可以用于预测类别概率的回归方法。

摘要

在本章中,我们使用 Excel 数据探索了线性回归和逻辑回归强大的世界。线性回归是一种基本的统计技术,使我们能够建模因变量和自变量之间的关系。我们讨论了其假设和应用,并介绍了从 Excel 加载数据、准备分析以及使用 R(使用基础 R 和 tidymodels)和 Python(使用 scikit-learnstatsmodels 库)拟合线性回归模型的全过程。

通过综合的代码示例,你学习了如何进行回归分析,评估模型准确性,并生成有价值的统计数据和指标来解释模型结果。我们获得了创建诊断图(如残差图和 Q-Q 图)的见解,这些图有助于识别异方差性和异常值等问题。

此外,我们还深入探讨了逻辑回归,这是一种用于类别概率预测和二分类任务的强大工具。我们阐述了其重要性和应用,并概述了数据准备、模型拟合和指标评估的过程。通过实际代码示例,我们观察了如何在 R 中的tidymodels和 Python 中的scikit-learn库中使用逻辑回归模型进行构建。

到本章结束时,你应该对线性回归和逻辑回归有深刻的理解,从理论到实际应用,并能够利用这些技术高效地分析你的数据。

拥有这些技能,你将能够熟练地进行回归分析,并从你的数据中提取有价值的见解,使用 Python。

接下来是下一章,你将学习时间序列分析及其在 Excel 数据中的应用。

第十章:时间序列分析:统计、图表和预测

在数学分析领域,尤其是在数据趋势研究方面,时间序列图表扮演着关键角色。时间序列图表是显示在一系列时间间隔内收集到的数据点的图形表示。这个工具在经济学、金融、环境科学和社会科学等众多领域都是不可或缺的,用于分析数据随时间变化的模式、趋势和波动。

典型的时间序列图表包含两个基本组件:时间轴和数据轴。时间轴表示时间的推移,可以以各种单位来衡量,如秒、分钟、小时、天、月或年。数据轴显示被研究变量的值,可以是股价、温度读数、人口计数或销售数据等。

要构建时间序列图表,你必须执行以下操作:

  • 数据收集:在固定的时间间隔或时间戳上收集数据点。这些间隔应该保持一致,以便准确捕捉时间模式。

  • 数据表示:在图表上绘制收集到的数据点,将每个点与其对应的时间戳对齐在时间轴上。

  • 坐标轴缩放:选择时间轴和数据轴的适当缩放比例。这确保了模式可见且准确表示。

  • 连接数据点:根据上下文,数据点可以用线、曲线或条形连接。连接点可以更有效地揭示趋势。

时间序列图表的主要功能是使数据中的趋势、模式和异常分析成为可能。可以从这种分析中获得以下见解:

  • 趋势识别:时间序列图表有助于识别长期趋势,如随时间逐渐增加或减少的值。这些趋势可以为决策提供宝贵信息。

  • 季节性变化:通过观察特定时期内数据的规律性波动,可以识别出季节性模式,例如假日季节销售激增。

  • 周期性模式:除了季节性变化外,还可以观察到周期性模式——重复但非规律性的波动。这些可能受经济周期或环境变化等因素的影响。

  • 波动性和异常值:数据中的突然上升或下降可能表明波动性或异常值,引起对影响被测变量的事件或因素的注意。

时间序列图也构成了预测分析和预测分析的基础。可以将数学模型应用于历史数据,以预测未来的趋势和值。需要注意的是,当我说做出预测时,我的确是指我们在推断如果所有事情都保持不变,可能会发生什么。

在数学分析领域,时间序列图是一种强大的工具,有助于理解数据随时间变化的动态。通过直观地表示数据点和趋势,它使研究人员、分析师和决策者能够提取有价值的见解,识别模式,并做出明智的预测。通过数学分析的角度来看,时间序列图提供了一种理解时间数据的结构化方法,从而对依赖数据驱动决策的领域做出了重大贡献。

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

  • 在 R 中生成随机时间序列对象

  • 使用 R 进行时间序列绘图

  • 使用healthyR.ts进行自动 ARIMA 建模

  • 使用healthyR.ts创建布朗运动

  • 时间序列绘图 – 基本绘图和 ACF/PACF 图

  • 时间序列统计和统计预测

  • 基于深度学习的时间序列预测 – LSTM

技术要求

本章有一些技术要求。请注意,本章的代码可以在github.com/PacktPublishing/Extending-Excel-with-Python-and-R/tree/main/Chapter%2010找到。

本章我们将使用的一些包如下:

  • healthyR.ts

  • forecast

  • timetk

  • Modeltime

  • prophet (``for Python)

  • keras

  • tensorflow

我们将首先在基础 R 中创建时间序列对象。R 中时间序列对象的基本对象类是ts,可以通过直接使用ts()函数或在一个向量等对象上调用as.ts()来将对象强制转换为该对象。

在 R 中生成随机时间序列对象

我们将在基础 R 中生成一些随机时间序列对象。这样做非常简单,因为基础 R 已经内置了一些分布函数。我们将通过调用rnorm()函数来使用随机正态分布。此函数有三个参数,用于提供以下参数:

  • n: 要生成的点的数量

  • mean: 分布的均值,默认为 0

  • sd: 分布的标准差,默认值为 1

让我们继续生成我们的第一个随机向量。我们将称之为x

# Generate a Random Time Series
# Set seed to make results reproducible
set.seed(123)
# Generate Random Points using a gaussian distribution with mean 0 and sd = 1
n <- 25
x <- rnorm(n)
head(x)
[1] -0.56047565 -0.23017749  1.55870831  0.07050839  0.12928774  1.71506499

在前面的代码中,我们做了以下操作:

  • set.seed(123): 这行代码的目的是确保每次运行代码时生成的随机数都是一致的。通过设置种子值(在这个例子中是123),你确保每次运行代码时生成的随机数将是相同的。这对于分析的重复性很有用。

  • n <- 25: 在这里,你正在定义一个名为n的变量并将其值设置为25。这个变量代表你想要在随机时间序列中生成的数据点的数量。

  • x <- rnorm(n): 这实际上是数据生成的地方。你正在创建一个新的变量x,并使用rnorm()函数生成随机数。这些数字是从高斯(或正态)分布中抽取的,通常被称为钟形曲线。n指定了要生成的随机数据点的数量,在这个例子中是 25。

  • head(x): 最后,你正在使用head()函数来显示x变量的前几个值。这有助于你快速检查生成的数据看起来像什么。这是一种方便的方法,可以在不打印整个数据集的情况下查看数据的一瞥。

总结来说,这段代码设置了一个随机种子以确保可重复性,指定了您想要的数据点数量(25),并从高斯分布中生成这些数据点,将它们存储在x变量中。然后,它使用head()函数显示了x的前几个值。这段代码在需要随机数据来处理或模拟现实世界场景的数据分析和统计学中经常被使用。

现在,让我们使用ts()函数将这个向量x转换为时间序列对象:

# Make x a ts object
ts_obj <- ts(x)

让我们检查新创建的对象的类:

class(ts_obj)
[1] "ts"

我们必须对其结构和属性做同样的处理:

str(ts_obj)
 Time-Series [1:25] from 1 to 25: -0.5605 -0.2302 1.5587 0.0705 0.1293 ...
attributes(ts_obj)
$tsp
[1]  1 25  1
$class
[1] "ts"

那么,到底发生了什么?让我们以简单而简洁的方式回顾一下。

这段 R 代码执行以下操作:

  • ts_obj <- ts(x): 这是从向量或数据序列x创建一个时间序列对象(ts_obj)。这一步将x转换为时间序列格式。

  • class(ts_obj): 这将检查并显示ts_obj的类。这应该返回ts,表示ts_obj确实是一个时间序列。

  • str(ts_obj): 这行代码显示了ts_obj的结构,提供了关于时间序列的信息。在这种情况下,它显示时间序列有 25 个数据点,范围从 1 到 25,以及相应的值。

  • attributes(ts_obj): 这显示了时间序列对象的属性。在这种情况下,它显示了时间跨度(tsp)的值为1 25 1,这意味着时间序列从周期 1 开始,到周期 25 结束,频率为 1。

因此,这段代码本质上是将一个向量x转换为时间序列对象,然后提供关于结果时间序列的类和结构的信息。现在,让我们使用plot函数来可视化时间序列。我们可以通过plot(ts_obj)来实现这一点:

图 10.1 – 来自 rnorm(25)的时间序列对象的绘图

图 10.1 – rnorm(25) 生成的时间序列对象的图

现在我们已经介绍了如何将向量强制转换为时间序列对象,我们可以讨论如何更改起始点、结束点和频率参数。

操作时间序列参数

现在,我们将使用之前用 rnorm() 创建的向量,并将其转换为具有不同起始点、结束点和频率的不同时间序列对象。在基础 R 中做这类事情非常简单。

让我们先看看一些代码操作;然后,我们将逐一解释示例:

# Change Start
ts(x, start = 1980)
ts(x, start = c(1980, 05))
ts(x, start = 1980, frequency = 12)
ts(x, start = 1980, frequency = 12/3)
# Change End
ts(x, end = 2023)
ts(x, end = 2023, frequency = 12)
ts(x, end = 2023, frequency = 12/3)
      Qtr1         Qtr2         Qtr3         Qtr4
2017 -0.56047565  -0.23017749   1.55870831   0.07050839
2018  0.12928774   1.71506499   0.46091621  -1.26506123
2019 -0.68685285  -0.44566197   1.22408180   0.35981383
2020  0.40077145   0.11068272  -0.55584113   1.78691314
2021  0.49785048  -1.96661716   0.70135590  -0.47279141
2022 -1.06782371  -0.21797491  -1.02600445  -0.72889123
2023 -0.62503927

这里是前面示例的解释。前面代码块中的最后一个示例显示了最后一种操作的输出:

  • ts(x, start = 1980): 这创建了一个从 1980 年开始的时间序列。确切的月份和日期没有指定,因此默认为 1980 年 1 月 1 日。

  • ts(x, start = c(1980, 05)): 这明确地将起始日期设置为 1980 年 5 月(年和月)。

  • ts(x, start = 1980, frequency = 12): 这一行创建了一个从 1980 年开始的时间序列,频率为每月一次,表示每个数据点代表一个月。

  • ts(x, start = 1980, frequency = 12/3): 这将起始年份设置为 1980 并指定频率为 4,这意味着每个数据点相隔四分之一(三个月)。

  • ts(x, end = 2023): 这创建了一个以 2023 年为结束日期的时间序列。这里没有指定起始日期,因此默认为序列的开始。

  • ts(x, end = 2023, frequency = 12): 这一行表示结束日期为 2023,频率为每月一次,假设每个数据点代表一个月。

  • ts(x, end = 2023, frequency = 12/3): 这将结束年份设置为 2023 并指定频率为 4,这意味着每个数据点相隔四分之一(三个月)。

这些变化允许您控制时间序列数据的时序特征,如起始点和结束点以及观测频率。现在我们已经生成了一些数据,让我们将其绘制出来。

时间序列绘图

在本节中,我们将介绍时间序列对象的绘图,以及绘制一些诊断图,如分解。这些图包括时间序列图本身,readxl 包:

# Read the airpassengers.xlsx file in and convert to a ts object starting at 1949
ap_ts <- read_xlsx("./Chapter 10/airpassengers.xlsx")  |>
  ts(start = 1949, frequency = 12)
# Plot the ts object
plot(ap_ts)

这产生了以下图表:

图 10.2 – 可视化 AirPassengers 时间序列数据集

图 10.2 – 可视化 AirPassengers 时间序列数据集

从这里,我们可以很容易地看出数据具有趋势和季节周期成分。这个观察结果将引导我们到下一个可视化。我们将把数据分解成其各个部分,并可视化分解。时间序列分解将数据分解成以下部分:

  • 观察到的数据

  • 数据的趋势

  • 数据的季节周期

  • 剩余的“随机性”或“残差/余数”

让我们来看看它是什么样子。首先,我们有代码:

plot(decompose(ap_ts))

这里是图表:

图 10.3 – 分解时间序列的图

图 10.3 – 分解时间序列的图

现在我们已经可视化了分解,我们可以开始分析 ACF 和 PACF 图。

在 R 中创建 ACF 和 PACF 图

在本节中,我们将介绍 ACF 和 PACF 图。ACF 图是自相关函数图。自相关函数是当前时间点的观察值与之前时间点的观察值之间的关系。它告诉你当前观察值与同一时间序列的不同滞后之间的相关性如何。因此,如果啤酒有强烈的季节性需求,你将在之前的季节性周期中看到与之相关的强烈相关性。

首先,让我们看看acf()函数的输出:

acf(ap_ts)

这是它的图:

图 10.4 – AirPassengers 数据的 ACF 图

图 10.4 – AirPassengers 数据的 ACF 图

在这里,我们可以看到所有点都与它们的前一个点有显著的相关性,因为数据本身是向上趋势的。然而,我们也可以看到数据中有峰值和谷值,这代表了季节性相关性。

现在,让我们看看 PACF 图,它也是通过将acf()函数的类型设置为“partial”而生成的。

偏自相关是观察值t与某些观察值t-n之间的关系。通过移除t与通过t-n的先前观察值之间的关系,偏自相关是移除较短滞后项的影响的结果。现在,让我们看看同一时间序列的 PACF,acf(ap_ts, type = "partial")

图 10.5 – AirPassengers 数据的 PACF

图 10.5 – AirPassengers 数据的 PACF

通过这些,我们已经介绍了如何在 R 中快速创建 ACF 和 PACF 图。我们还提供了一个非常快速的了解它们是什么的概述。现在,让我们学习如何使用healthyR.ts库对时间序列进行建模。

使用 healthyR.ts 进行自动 ARIMA 建模

时间序列,就像任何其他数据集一样,可以被建模。方法众多,既有古老的也有新的。在本节中,我们将讨论 ARIMA 建模,特别是使用 R 中的healthyR.ts库构建自动 ARIMA 模型。ARIMA 模型本身试图描述数据中的自相关性。

在本节中,我们将使用一个以ts_auto_arima()函数创建和拟合调整后的模型结束的工作流程。此模型需要我们的数据以 tibble 格式。因此,为了做到这一点,我们将使用 AirPassengers 数据集并确保它是一个 tibble。

让我们从我们已经引入的数据集开始,并将其强制转换为 tibble:

library(healthyR.ts)
library(dplyr)
library(timetk)
ap_tbl <- ts_to_tbl(ap_ts) |>
  select(-index)
> class(ap_tbl)
[1] "tbl_df"      "tbl"           "data.frame"

在前面的代码中,我们加载了healthyR.tsdplyr库,然后使用healthyR.ts库中的ts_to_tbl()函数将已经存在的ap_ts时间序列对象转换为 tibble。接下来,我们必须使用timetk库中的time_series_split()函数创建一个训练/测试分割:

# Time Series Split
splits <- time_series_split(
  data = ap_tbl
  , date_var = date_col
  , assess = 12
  , skip = 3
  , cumulative = TRUE
)
> splits
<Analysis/Assess/Total>
<132/12/144>

现在我们已经创建了分析/评估数据分割,我们就可以运行主函数了。这个函数旨在成为一个样板函数,它会自动完成大多数工作。然而,你总是可以取用模型并对其进行你想要的操作。healthyR.ts中的这些样板函数并不打算成为终极解决方案。

让我们现在运行这个函数,然后看看输出:

Library(modeltime)
ts_auto_arima <- ts_auto_arima(
  .data = ap_tbl,
  .num_cores = 10,
  .date_col = date_col,
  .value_col = x,
  .rsamp_obj = splits,
  .formula = x ~ .,
  .grid_size = 20,
  .cv_slice_limit = 5,
  .tune = TRUE
)

在前面,我们提供了包含数据和我们要使用的核心数(在我们的案例中是10)的 tibble。接下来,我们提供了包含日期的列——在这个案例中是date_col——值列来自我们提供的 tibble 中的x。接下来是重采样对象,分割,然后是我们的公式,它被传递到ts_auto_arima()函数内部的 recipe 函数。在这种情况下,它是x对日期。我们提供了一个20的网格大小来制作调整网格,以及一个5的切片限制,以确保不会生成超过五个数据切片。最重要的是,我们将.tune参数设置为TRUE。这指示函数继续进行模型调整。模型调整可能会导致数据返回需要几秒钟/几分钟。

让我们看看输出。我们将首先查看配方信息:

> ts_auto_arima$recipe_info
$recipe_call
recipe(.data = ap_tbl, .date_col = date_col, .value_col = x,
     .formula = x ~ ., .rsamp_obj = splits, .tune = TRUE, .grid_size = 20,
     .num_cores = 10, .cv_slice_limit = 5)
$recipe_syntax
[1] "ts_arima_recipe <-"
[2] "\n  recipe(.data = ap_tbl, .date_col = date_col, .value_col = x, .formula = x ~ \n     ., .rsamp_obj = splits, .tune = TRUE, .grid_size = 20, .num_cores = 10, \n     .cv_slice_limit = 5)"
$rec_obj
── Recipe ────────────────────────────────────────────────────────────────────────────────────────
── Inputs
Number of variables by role
outcome:   1
predictor: 1

因此,从前面的输出中,我们可以看到我们有一个单一的结果变量和一个预测变量。对于一个没有外生回归变量的自动 ARIMA 模型来说,这已经足够了。

现在,让我们看看模型信息:

ts_auto_arima
> ts_auto_arima$model_info
$model_spec
ARIMA Regression Model Specification (regression)
Main Arguments:
  seasonal_period = tune::tune()
  non_seasonal_ar = tune::tune()
  non_seasonal_differences = tune::tune()
  non_seasonal_ma = tune::tune()
  seasonal_ar = tune::tune()
  seasonal_differences = tune::tune()
  seasonal_ma = tune::tune()
Computational engine: arima

在前面的代码中,我们可以看到模型的所有参数都设置为tune::tune()。这将允许模型通过调整网格运行:

$wflw
══ Workflow
Preprocessor: Recipe
Model: arima_reg()
── Preprocessor
0 Recipe Steps
── Model
ARIMA Regression Model Specification (regression)
Main Arguments:
  seasonal_period = tune::tune()
  non_seasonal_ar = tune::tune()
  non_seasonal_differences = tune::tune()
  non_seasonal_ma = tune::tune()
  seasonal_ar = tune::tune()
  seasonal_differences = tune::tune()
  seasonal_ma = tune::tune()
Computational engine: arima

创建的以下工作流程对象显示,配方没有任何步骤,因为没有进行任何类型的转换:

$fitted_wflw
…
── Model
Series: outcome
ARIMA(4,1,2)(1,0,1)[12]
Coefficients:
       ar1    ar2     ar3      ar4     ma1      ma2     sar1     sma1
     -0.221  0.9020  0.0894  -0.2144  0.0477  -0.9523  0.9695  -0.0869
s.e.  0.092  0.0996  0.0958   0.0875  0.0367   0.0365  0.0143   0.0927
sigma² = 99.46:  log likelihood = -497.36
AIC=1012.72   AICc=1014.21   BIC=1038.6
$was_tuned
[1] "tuned"

拟合的工作流程对象显示,选定的最佳模型是ARIMA(4,1,2)(1,0,1)[12]模型。它还提供了我们的系数和模型 AIC。

接下来,我们将查看返回输出的model_calibration对象:

> ts_auto_arima$model_calibration
$plot
$calibration_tbl
# Modeltime Table
# A tibble: 1 × 5
  .model_id .model.model_desc.type .calibration_data
        <int> <list>      <chr>                           <chr> <list>
1            1 <workflow> ARIMA(4,1,2)(1,0,1)[12] Test  <tibble [12 × 4]>
$model_accuracy
# A tibble: 1 × 9
  .model_id .model_desc.type   mae  mape  mase smape  rmse   rsq
        <int> <chr>                           <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1            1 ARIMA(4,1,2)(1,0,1)[12] Test   16.2  3.35 0.335  3.35  19.5 0.960

下面是生成的图表:

图 10.6 – 自动 ARIMA 校准图

图 10.6 – 自动 ARIMA 校准图

最后,我们将回顾返回的tuned_model对象:

> ts_auto_arima$tuned_info
$tuning_grid
# A tibble: 20 × 7
   seasonal_period non_seasonal_ar non_seasonal_differences non_seasonal_ma seasonal_ar
   <chr>         <int>           <int>         <int>       <int>
 1 weekly          3               0            1             2
 2 yearly          5               1            4               0
# ℹ 2 more variables: seasonal_differences <int>, seasonal_ma <int>
$tscv
# Time Series Cross Validation Plan
# A tibble: 5 × 2
  splits               id
  <list>               <chr>
1 <split [120/12]> Slice1
2 <split [117/12]> Slice2
3 <split [114/12]> Slice3
4 <split [111/12]> Slice4
5 <split [108/12]> Slice5
$tuned_results
# Tuning results
# NA
# A tibble: 5 × 4
  splits               id      .metrics                 .notes
  <list>               <chr>  <list>                    <list>
1 <split [120/12]> Slice1 <tibble [120 × 11]> <tibble [1 × 3]>
2 …
$grid_size
[1] 20
$best_metric
[1] "rmse"
$best_result_set
# A tibble: 1 × 13
  seasonal_period non_seasonal_ar non_seasonal_differences non_seasonal_ma seasonal_ar
  <chr>           <int>            <int>         <int>         <int>
1 yearly             4                1              2               1
# ℹ 8 more variables: seasonal_differences <int>, seasonal_ma <int>, .metric <chr>,
#   .estimator <chr>, mean <dbl>, n <int>, std_err <dbl>, .config <chr>
$tuning_grid_plot
`geom_smooth()` using method = 'loess' and formula = 'y ~ x'
$plotly_grid_plot

从前面的代码中,我们可以看到从这个函数返回的这一部分有很多信息。这应该包含你做出明智决定所需的所有信息,决定你是否应该继续调整或继续前进。

让我们看看最后一个图表,它作为静态ggplot2对象和plotly对象返回:

图 10.7 – 自动 ARIMA 模型的调优网格

图 10.7 – 自动 ARIMA 模型的调优网格

完成这些后,让我们看看布朗运动的概念是如何工作的。

使用 healthyR.ts 创建布朗运动

我们将要展示的最后一个时间序列图是布朗运动。布朗运动,也称为维纳过程,是金融和数学中的一个基本概念,描述了流体中粒子的随机运动。在金融的背景下,它通常用于模拟股票、商品和货币等金融工具的价格变动。

布朗运动的一些关键特征如下:

  • 随机性:布朗运动本质上是随机的。在任何时间点,未来方向和移动幅度都不能被确定地预测。

  • 连续路径:布朗运动的路径是连续的,这意味着资产的价格可以平滑移动,没有突然的跳跃或缺口。

  • 独立增量:资产价格在非重叠时间间隔内的变化是相互独立的。换句话说,一个时间间隔的价格变动不会影响另一个时间间隔的价格变动。

  • 高斯分布:布朗运动的增量(即价格变化)是正态分布的,遵循高斯或正态分布。这与金融市场中小幅度价格变动比大幅度变动更常见的观点一致。

  • 恒定方差:价格增量的方差随时间保持恒定。这有时被称为同方差属性。

从数学上讲,资产价格S(t)随时间t的变化可以用随机微分方程来描述:

这里,我们有以下内容:

  • dS(t) 是资产价格在微小时间间隔dt内的无穷小变化

  • μ 是资产随时间变化的漂移或预期平均回报率

  • σ 是资产的波动性,代表其价格变化的标准差

  • dW(t) 是维纳过程,代表一个随机增量

布朗运动是金融模型(如 Black-Scholes 期权定价模型和 Vasicek 利率模型)的基石之一。它通过捕捉其固有的随机性和波动性,有助于理解和估计金融工具的行为。然而,需要注意的是,由于市场情绪、新闻和其他外部因素的影响,实际金融市场可能偏离完美的布朗运动。

我们可以使用healthyR.ts库快速生成布朗运动并绘制其输出。以下是代码:

library(healthyR.ts)
ts_brownian_motion() |>
  ts_brownian_motion_plot(t, y)

这里是前面代码的输出。这是一个随机过程,所以你的输出可能不会匹配:

图 10.8 – 使用 healthyR.ts 库创建和查看布朗运动

图 10.8 – 使用 healthyR.ts 库创建和查看布朗运动

既然我们已经了解了 R 中的时间序列数据,让我们转到 Python 看看那里是如何操作的。

Python 中的时间序列分析 – 统计、绘图和预测

在深入研究时间序列分析之前,拥有可工作的数据至关重要。在本节中,我们将介绍创建模拟时间序列数据、将其保存到 Excel 文件中,然后将其读回到 pandas 的过程。这将成为我们进行时间序列分析的基础。

和往常一样,我们将从加载相关的库开始:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

然后,我们必须创建样本数据并将其保存到 Excel 中,以便在本章的其余部分使用:

# Create a date range
date_rng = pd.date_range(start='2022-01-01', end='2023-12-31',
    freq='D')
# Create a trend component
trend = 0.05 * np.arange(len(date_rng))
# Create a seasonal component (cyclicality)
seasonal = 2.5 * np.sin(2 * np.pi * np.arange(len(date_rng)) / 365)
# Add some random noise
noise = np.random.normal(0, 0.5, len(date_rng))
# Combine all components to create the time series
time_series = trend + seasonal + noise
# Create a DataFrame
df = pd.DataFrame({'Date': date_rng, 'Value': time_series})
# Save the data to an Excel file
df.to_excel('time_series_data.xlsx', index=False)

最后,我们必须从 Excel 中加载数据,并查看加载的数据,如下所示:

# Read the data back into pandas
loaded_df = pd.read_excel('time_series_data.xlsx')
# Display the first few rows
print(loaded_df.head())

在这个例子中,我们生成一个具有线性趋势、正弦波季节成分和随机噪声的合成时间序列。这种数据集更真实地反映了现实世界中的时间序列数据,其中模式通常涉及这些元素的组合。然后,数据集被保存到 Excel 文件中,您可以根据需要将其读回到 Python 进行分析。

正如我们在 第六章 中讨论的,分析的第一步是绘图(插入邪恶的笑声)!

时间序列绘图 – 基本绘图和 ACF/PACF 图

可视化时间序列数据是理解其潜在模式和趋势的关键步骤。在本节中,我们将探讨各种时间序列图以及如何使用 Python 创建它们。这些可视化有助于我们深入了解时间序列数据中的季节性、趋势和自相关性。

我们将首先加载所需的库:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

然后,我们必须从 Excel 中加载数据,并确保日期信息被正确转换:

# Load time series data (replace 'time_series_data.xlsx' with your data file)
data = pd.read_excel('time_series_data.xlsx')
# Convert the 'Date' column to datetime format and set it as the index
data['Date'] = pd.to_datetime(data['Date'])
data.set_index('Date', inplace=True)

现在,我们可以创建时间序列的基本图,以便进行初步查看:

# Plot the time series
plt.figure(figsize=(12, 6))
plt.plot(data['Value'])
plt.title('Time Series Plot')
plt.xlabel('Date')
plt.ylabel('Value')
plt.grid(True)
plt.show()

这就是该图的样子:

图 10.9 - 标题

图 10.9 - 标题

接下来,我们必须使用以下代码创建更高级的 ACF 和 PACF 图:

# ACF and PACF plots
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))
# ACF plot
plot_acf(data['Value'], lags=10, ax=ax1)
ax1.set_title('Autocorrelation Function (ACF)')
# PACF plot
plot_pacf(data['Value'], lags=40, ax=ax2)
ax2.set_title('Partial Autocorrelation Function (PACF)')
plt.tight_layout()
plt.show()

结果图如下所示:

图 10.10 – 滞后 1 和 2 的 ACF 和 PACF 图

图 10.10 – 滞后 1 和 2 的 ACF 和 PACF 图

在这里,我们首先从 Excel 文件中加载数据,并将 日期 列转换为 datetime 索引。然后,我们创建了一个时间序列图来可视化数据随时间的变化。此外,我们还生成了 ACF 和 PACF 图来探索时间序列中的自相关模式。这些图对于识别时间序列模型中可能的滞后值非常有价值。

现在,让我们看看 ACF 和 PACF 图如何帮助我们深入了解时间序列数据。特别是,我们将看到它们如何被用来理解季节性、趋势和自相关性。

自相关函数 (ACF) 图

ACF 图显示了时间序列与其滞后值之间的相关性。换句话说,它量化了当前值与过去值的相关程度。

ACF 图在特定滞后处的峰值表示数据中可能存在的季节性或周期性模式。例如,在每日序列中滞后 7 处的显著峰值表明存在每周季节性,而在月度序列中滞后 12 处的峰值可能表明存在年度季节性。

通过分析 ACF 图,您可以识别出相关性显著偏离零的滞后值。这些滞后值可以提供有关数据季节性的见解。此外,识别 ACF 中的指数衰减可以表明时间序列模型中存在自回归成分。

部分自相关函数(PACF)图

PACF 图衡量时间序列与其滞后值之间的直接关系,同时消除中间滞后值的影响。

PACF 图在特定滞后处的峰值表示直接影响当前值的时间序列滞后值的数量。例如,滞后 1 处的一个显著峰值以及之后没有显著峰值表明存在一阶自回归AR)过程。

PACF 图有助于确定 ARIMA 模型中自回归项(p)的阶数。它还可以揭示时间序列中的突然变化,表明结构断裂或位移。

通过结合分析这些图表和您的时间序列数据,您可以获得有关季节性、趋势和自相关性的宝贵见解。这些见解在选择适当的时间序列模型和进行准确预测方面至关重要。

图 10.9中显示的图中,对于 PACF 图,只有滞后 1 具有强烈的自相关性,而 ACF 图由于随机数据生成的方式而被误导,在所有研究的滞后中都显示出高度的自相关性。

通过从这些图表中获得见解,我们可以继续进行实质性的分析:统计分析与预测

时间序列统计与统计预测

数据探索和统计分析是理解时间序列数据特征的关键步骤。在本节中,我们将向您展示如何使用 Python 进行数据探索和运用统计分析技术,以获得对时间序列的宝贵见解。

时间序列数据的统计分析

在上一节中使用图表探索数据后,让我们继续进行统计分析,以获得更深入的理解。本节重点关注两个领域:

  • Augmented Dickey-Fuller (ADF) 测试:这种统计测试用于确定时间序列数据是否平稳。平稳数据更容易建模和预测。

  • 时间序列分解:时间序列分解将数据分解为其组成部分:趋势、季节性和残差。这种分解有助于隔离用于预测的模式。

我们将在接下来的章节中了解这两者。

ADF 测试

ADF 测试是一种用于评估时间序列平稳性的统计方法。平稳性是时间序列分析中的一个基本概念,因为它简化了建模过程。平稳时间序列具有统计属性,如恒定的均值和方差,这些属性不会随时间变化。另一方面,非平稳数据表现出趋势或季节性,这使得准确建模和预测变得具有挑战性。

在 ADF 测试中,零假设(H0)假定数据是非平稳的。备择假设(H1)表明数据是平稳的。通过分析从测试中获得的 p 值,你可以确定是否拒绝零假设。低 p 值(通常小于 0.05)表明数据是平稳的,而高 p 值则表明非平稳性。因此,在进行 ADF 测试时,p 值小于 0.05 是平稳时间序列的一个指标。

这里是一个代码示例,展示了如何使用我们信任的statsmodels库在 Python 中实现 ADF 测试:

from statsmodels.tsa.stattools import adfuller
import pandas as pd
# Read the data back into pandas
df = pd.read_excel('time_series_data.xlsx')
# Augmented Dickey-Fuller Test
adf_result = adfuller(df['Value'])
print("\nAugmented Dickey-Fuller Test:")
print(f"ADF Statistic: {adf_result[0]}")
print(f"P-value: {adf_result[1]}")
print("Null Hypothesis (H0): Data is non-stationary")
print("Alternative Hypothesis (H1): Data is stationary")
if adf_result[1] <= 0.05:
     print("Result: Reject the null hypothesis. Data is stationary.")
else:
     print("Result: Failed to reject the null hypothesis. Data is non-stationary.")

毫不奇怪,我们没有拒绝零假设,因为我们之前生成的时序数据具有明显的线性趋势,因此它不是平稳的。

为了获得更深入的见解,我们可以进一步分析详细的输出:

图 10.11 – ADF 测试结果

图 10.11 – ADF 测试结果

如您所见,ADF 测试的结果,由adfuller返回,包含几个组成部分:

  • 在我们的情况下(-0.24536819384067887)是测试统计量。这个统计量用于评估时序数据集中是否存在单位根的零假设。测试统计量越负(或越不积极),对零假设的证据就越强。

  • 在我们的情况下(0.9328933413659218)是与测试统计量相关的 p 值。它代表如果零假设为真,观察给定测试统计量的概率。小的 p 值(通常小于 0.05)表明拒绝零假设,支持平稳性。

  • 在我们的情况下(9))代表在估计 ADF 测试时回归中使用的滞后数。

  • 在我们的情况下(720)代表在 ADF 回归中使用的观测数。

  • 字典:结果的下一段是一个包含不同置信水平(1%、5%和 10%)临界值的字典。这些临界值用于确定测试统计量的显著性。

  • 在我们的情况下(1208.8292254446185)是最大化的 IC。它代表模型拟合优度的一个度量。IC 的值越低,拟合度越好。

总结来说,你通常会通过关注测试统计量和 p 值来解释 ADF 测试结果。如果测试统计量更负(或更正)且 p 值较小(通常小于 0.05),则表明拒绝单位根的零假设,并得出时间序列是平稳的结论。

时间序列分解

时间序列分解是一种将时间序列数据集分解为其关键组成部分(趋势、季节性和残差)的技术。这些组成部分为理解时间序列的潜在模式提供了宝贵的见解,使其更容易理解和预测。

让我们了解这些组成部分:

  • 趋势:趋势组成部分代表数据中的潜在长期运动或趋势。它捕捉整体方向——即数据随时间增加或减少。

  • 季节性:季节性指的是数据在固定间隔内重复出现的模式。这些模式可能是每日、每周、每月或每年的模式,具体取决于数据。检测季节性对于理解周期性趋势并在预测中调整它们至关重要。

  • 残差:残差是时间序列数据的非规则或随机组成部分。它们代表在去除趋势和季节性之后剩余的部分。分析残差有助于识别数据中的任何剩余模式或异常事件。

在我们的代码中,我们应用时间序列分解将时间序列分解为其组成部分,并可视化每个组成部分。这个过程使我们能够理解数据的结构,从而更容易地识别预测中的潜在模式。

让我们看看 Python 中时间序列分解的一个实现:

from statsmodels.tsa.seasonal import seasonal_decompose
import matplotlib.pyplot as plt
# Time Series Decomposition
decomposition = seasonal_decompose(df['Value'],
    model='additive',  period=365)
trend = decomposition.trend
seasonal = decomposition.seasonal
residual = decomposition.resid
# Plot the decomposition components
plt.figure(figsize=(12, 8))
plt.subplot(411)
plt.plot(df['Date'], df['Value'], label='Original')
plt.legend(loc='best')
plt.subplot(412)
plt.plot(df['Date'], trend, label='Trend')
plt.legend(loc='best')
plt.subplot(413)
plt.plot(df['Date'], seasonal, label='Seasonal')
plt.legend(loc='best')
plt.subplot(414)
plt.plot(df['Date'], residual, label='Residual')
plt.legend(loc='best')
plt.suptitle("Time Series Decomposition")
plt.show()

结果图是自解释的(特别是因为它反映了数据是如何人工生成的):

/

图 10.12 – 时间序列分解

图 10.12 – 时间序列分解

在本节中,我们介绍了可以帮助你理解时间序列和解决建模中最典型挑战的核心技术:分解和如何解释组成部分。通过提供的图表和统计分析,我们对时间序列有了更深入的理解,可以继续进行最有价值的步骤:预测。

理解预测建模方法

在本节中,我们将深入探讨使用两个强大的 Python 库——statsmodelsprophet——进行预测建模方法。

这些库提供了多样化的工具来处理时间序列预测,使你能够根据时间序列数据做出明智的决定和预测。

使用 statsmodels 进行预测

statsmodels 是 Python 生态系统中的一个流行库,它提供了一系列的统计工具,包括时间序列分析。对于预测,它提供了构建 ARIMA 模型的功能。ARIMA 模型是时间序列分析的基础,允许你捕捉并模拟数据中的复杂模式。

使用 statsmodels 构建 ARIMA 模型涉及选择合适的差分阶数、自回归组件和移动平均组件,以最好地表示数据的潜在模式。一旦模型建立,你就可以进行预测并评估其性能。

最后,非常重要的一点是,由于我们拥有的时间序列不是平稳的,我们应该模拟时间序列中的变化或差异。

让我们看看代码中的工作流程!

  1. 首先,导入必要的库并加载数据:

    # Import necessary libraries
    import pandas as pd
    import numpy as np
    import statsmodels.api as sm
    from scipy.stats import norm
    import matplotlib.pyplot as plt
    # Load the time series data (replace with your data)
    time_series_data = pd.read_excel('time_series_data.xlsx')['Value']
    
  2. 然后,检查平稳性并决定我们是要模拟时间序列本身还是差异:

    # Perform the Augmented Dickey-Fuller test to check for stationarity
    result = sm.tsa.adfuller(time_series_data, autolag='AIC')
    # If the p-value is greater than a threshold (e.g., 0.05), perform differencing to make the data stationary
    if result[1] > 0.05:
            differenced_data = np.diff(time_series_data, n=1)
    else:
            differenced_data = time_series_data
    
  3. 现在(由于我们的时间序列不是平稳的,所以我们使用了差分数据),我们可以构建实际的模型并将其拟合:

    # Build an ARIMA model
    order = (1, 1, 1)  # Values based on ACF and PACF analysis
    model = sm.tsa.ARIMA(differenced_data, order=order)
    # Fit the ARIMA model
    model_fit = model.fit()
    
  4. 可选地,我们可以对阶数参数进行一些超参数调整,而不是仅基于图表做出决策。然而,对于这个例子,这已经足够了。超参数调整是指调整定义模型的参数,而不是拟合数据的参数,例如 ARIMA 模型的阶数。

  5. 现在,我们可以使用训练好的模型创建我们的预测。

    注意,由于我们建模了差分数据,我们需要将预测结果转换回实际的时间序列:

    # Make forecasts
    forecast_steps = 50  # Adjust the number of forecast steps as needed
    forecast = model_fit.forecast(steps=forecast_steps)
    # If the p-value is greater than a threshold (e.g., 0.05), perform differencing to make the data stationary
    if result[1] > 0.05:
            # The model was trained on the differenced data so the forecasts have to be added to the last data point
            cumsum_forecasts = np.cumsum(forecast)
            # Add this cumulative sum to the last observed value in your raw data
            real_forecasts = cumsum_forecasts + time_series_data[len(time_series_data)-1]
    else:
            real_forecasts = forecast
    
  6. 然后,我们必须计算基本统计量并使用它们来计算置信区间:

    # Retrieve ARIMA model parameters
    params = model_fit.params
    p, d, q = order
    resid = model_fit.resid
    # Compute the standard errors
    stderr = np.std(resid)
    # Calculate the confidence intervals
    z_score = norm.ppf(0.975)  # For a 95% confidence interval
    conf_int = np.column_stack((real_forecasts - z_score * stderr,
            real_forecasts + z_score * stderr))
    # Separate the forecasts into point forecasts and confidence intervals
    point_forecasts = real_forecasts  # The point forecasts
    forecast_stderr = stderr  # The standard errors of the forecasts
    lower_bound = conf_int[:, 0]  # Lower confidence interval bounds
    upper_bound = conf_int[:, 1]  # Upper confidence interval bounds
    
  7. 最后,我们必须将预测与原始时间序列一起绘制出来,以便对模型进行视觉评估:

    # Visualize the original time series and forecasts
    plt.figure(figsize=(12, 6))
    plt.plot(time_series_data, label='Original Time Series', color='blue')
    plt.plot(range(len(time_series_data),
        len(time_series_data) + forecast_steps),
        real_forecasts, label='Forecast', color='red')
    plt.fill_between(range(len(time_series_data),
        len(time_series_data) + forecast_steps),
        lower_bound, upper_bound, color='pink', alpha=0.5)
    plt.xlabel('Time Steps')
    plt.ylabel('Value')
    plt.title('ARIMA Time Series Forecast')
    plt.legend()
    plt.show()
    

    结果图为我们提供了一些有价值的见解:

图 10.13 – 时间序列和 statsmodel 预测

图 10.13 – 时间序列和 statsmodel 预测

我们可以看到,虽然趋势被很好地捕捉到了,并且一些季节性也出现了,但该模型过于简单,无法完全捕捉时间序列的本质。

为了解决这个问题,我们可以使用来自专用时间序列库的更复杂模型:prophet

使用 Facebook 的 prophet 进行时间序列预测

专门为时间序列预测任务设计的 prophet 库以其易用性和广泛的模型选择而闻名,适用于各种预测场景。

prophet 提供了一种直观的方式来模拟时间序列数据。它还提供了超参数优化和预测评估的工具。

我们将使用的代码也看起来更简单:

  1. 首先,我们必须加载必要的库,读取 Excel 数据,并创建 DataFrame,使其符合 prophet 期望的列:

    # Import necessary libraries
    import pandas as pd
    from prophet import Prophet
    from prophet.plot import plot
    # Load the time series data (replace with your data)
    time_series_data = pd.read_excel('time_series_data.xlsx')
    # Create a DataFrame with 'ds' and 'y' columns
    df = pd.DataFrame({'ds': time_series_data['Date'], 
        'y': time_series_data['Value']})
    
  2. 然后,我们必须使用领域知识(在这种情况下,来自我们这样生成数据的事实)稍微调整模型:

    # Initialize and fit the Prophet model without weekly seasonality
    model = Prophet(weekly_seasonality=False)
    # Add custom seasonality obtained from domain knowledge (in this case: we generated the data so)
    model.add_seasonality(name='custom_season', period=365, 
        fourier_order=5)
    # Fit the customized model
    model.fit(df)
    
  3. 最后,我们可以创建我们的预测并绘制它及其组成部分:

    # Create a dataframe for future dates
    forecast_steps = 150  # Adjust the number of forecast steps as needed
    future = model.make_future_dataframe(periods=forecast_steps,
        freq='D')
    # Make predictions
    forecast = model.predict(future)
    # Plot the forecast
    fig = model.plot(forecast)
    fig.show()
    # Plot components of the forecast (trend, yearly, and weekly seasonality)
    fig2 = model.plot_components(forecast)
    fig2.show()
    

    生成的图表显示了一个比statsmodel更高的预测质量,置信区间更紧密。季节性和趋势都得到了明显的捕捉:

图 10.14 – 时间序列和 prophet 预测

图 10.14 – 时间序列和 prophet 预测

要深入了解模型拟合,让我们看看拟合的时间序列模型的组成部分:

图 10.15 – 由 prophet 拟合的时间序列模型的组成部分

图 10.15 – 由 prophet 拟合的时间序列模型的组成部分

如您所见,prophet以非常简单的方式拟合模型,无需猜测起始参数。您可以使用并应该使用任何领域知识来改进初始模型。

在前面的代码中,我们关闭了默认的每周季节性,并添加了自定义的年度季节性。如果需要,我们可以做更多的事情:

  • 我们可以添加自定义的假日日历,例如,使用model.add_country_holidays(country_name='US')命令。

  • 如果我们确信存在变化点,但不确定具体位置,我们可以尝试调整变化点。

  • 我们可以调整自定义季节性的傅里叶阶数。

使用statsmodelprophet完成预测后,是时候总结本节内容并继续下一部分了。

在本节中,您为时间序列数据建立了强大的统计分析与预测基础。这些技能对于理解过去趋势和做出预测至关重要,能够支持数据驱动的决策和洞察。

在下一节中,我们将探讨用于时间序列分析的深度学习模型。

深度学习时间序列预测 – LSTM

本节将向您介绍使用深度学习模型的高级时间序列预测技术。无论您是处理传统时间序列数据还是更复杂、高维度的数据,这些深度学习模型都能帮助您做出更准确的预测。特别是,我们将涵盖keras

我们将使用kerastensorflow后端,因此您需要安装这两个库:

  1. 像往常一样,让我们加载必要的库并预处理一些时间序列数据:

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    from keras.models import Sequential
    from keras.layers import LSTM, Dense
    from sklearn.preprocessing import MinMaxScaler
    # Load the time series data (replace with your data)
    time_series_data = pd.read_excel('time_series_data.xlsx')
    # Normalize the data to be in the range [0, 1]
    scaler = MinMaxScaler()
    data = scaler.fit_transform(
        time_series_data['Value'].to_numpy().reshape(-1, 1))
    
  2. 数据集准备就绪后,我们将将其分为训练集和测试集,并重新塑形以供 LSTM 输入:

    # Split the data into training and testing sets
    train_size = int(len(data) * 0.67)
    train, test = data[0:train_size, :], data[train_size:len(data), :]
    # Create sequences and labels for training
    def create_dataset(dataset, look_back=1):
        X, Y = [], []
        for i in range(len(dataset) - look_back):
            a = dataset[i:(i + look_back), 0]
            X.append(a)
            Y.append(dataset[i + look_back, 0])
        return np.array(X), np.array(Y)
    look_back = 3
    X_train, Y_train = create_dataset(train, look_back)
    X_test, Y_test = create_dataset(test, look_back)
    # Reshape the data for LSTM input
    X_train = np.reshape(X_train, (X_train.shape[0], 1, 
        X_train.shape[1]))
    X_test = np.reshape(X_test, (X_test.shape[0], 1, 
        X_test.shape[1]))
    
  3. 数据准备就绪后,让我们创建并训练一个 LSTM 模型:

    model = Sequential()
    model.add(LSTM(4, input_shape=(1, look_back)))
    model.add(Dense(1))
    model.compile(loss='mean_squared_error', optimizer='adam')
    model.fit(X_train, Y_train, epochs=100, batch_size=1, verbose=2)
    

    此代码定义了一个简单的 LSTM 模型,编译它,并使用我们的训练数据进行训练。您可以根据您特定的时序分析需要自定义模型架构和训练参数。请注意,训练时间比我们在上一节中使用的简单模型长得多。

  4. 模型训练完成后,我们可以做出预测并将它们缩放回原始数据集进行比较:

    # Make predictions:
    trainPredict = model.predict(X_train)
    testPredict = model.predict(X_test)
    # Inverse transform the predictions to the original scale
    trainPredict = scaler.inverse_transform(trainPredict)
    testPredict = scaler.inverse_transform(testPredict)
    
  5. 最后,可视化实际数据集和测试集的预测:

    # Plot the training predictions
    trainPredictPlot = np.empty_like(data)
    trainPredictPlot[:, :] = np.nan
    trainPredictPlot[look_back:len(trainPredict) + look_back, :] =\
        trainPredict
    # Plot the test predictions
    testPredictPlot = np.empty_like(data)
    testPredictPlot[:, :] = np.nan
    testPredictPlot[len(trainPredict) + (look_back * 2):len(data),
        :] = testPredict
    # Plot the training data in blue
    plt.plot(time_series_data['Value'], color='blue', label=
        'Actual Data')
    # Create shaded regions for the training and test data
    plt.fill_between(range(len(data)), 0, 
        trainPredictPlot.reshape(-1),
        color='lightgray', label='Training Data')
    plt.fill_between(range(len(data)), 0, 
        testPredictPlot.reshape(-1),
        color='lightcoral', label='Test Data')
    # Overlay the predictions in green
    plt.plot(testPredictPlot, color='green', label='Predictions')
    plt.title('Time Series Analysis with LSTM')
    plt.legend()
    plt.show()
    

    对于如此小的数据集和简单的模型,生成的图像相当令人印象深刻:

图 10.16 – 实际数据(蓝色)和测试集预测(绿色)

图 10.16 – 实际数据(蓝色)和测试集预测(绿色)

请记住,这是一个基本示例。LSTM 模型可以显著更复杂,你可能需要探索堆叠 LSTM、超参数调整等技术,具体取决于你的时间序列数据。

这标志着我们使用 Python 进行时间序列分析之旅的结束。让我们回顾一下本章你学到了什么!

摘要

在本章中,我们深入探讨了时间序列分析的迷人世界。我们首先探索了时间序列绘图,掌握了基本绘图,并理解了 ACF/PACF 图的重要性。

接下来,我们进入了时间序列统计领域,包括 ADF 测试、时间序列分解以及使用statsmodelsprophet等工具进行统计预测。

为了提升我们的预测能力,我们采用了深度学习,使用 Python 的keras库来应用 LSTM 网络。我们学会了开发准确的时间序列预测,并创建深入的数据驱动洞察的视觉化。

本章为我们提供了一套全面的时间序列分析技能,使我们能够揭示基于时间数据的隐藏模式和洞察,从绘图到统计分析再到深度学习预测。

在下一章中,我们将讨论不同的集成方法——即直接从 Excel 调用 R 和 Python。

第四部分:反过来调用——从 Excel 调用 R 和 Python

在本部分,你将解锁在 Excel 中 R 和 Python 的强大功能,通过为无缝集成设计的全面解决方案。你将发现如何利用 BERT 和xlwings在 Excel 和你的首选编程语言之间实现流畅的通信。你将探索开源 API 解决方案,如 Plumber 和 FastAPI,以及商业产品如 Posit Connect 和 ownR,以通过基于 API 的集成扩展 Excel 工作流程的功能。

本部分包含以下章节:

  • 第十一章从 Excel 直接或通过 API 调用 R/Python

第十一章:直接从 Excel 或通过 API 本地调用 R/Python

在本章中,我们将讨论如何在 Excel 内部调用 R 和 Python。你可能想知道为什么你想要这样做,因为 Excel 内部有许多函数可以使用,或者如果你愿意,可以使用应用程序的 VBA 部分编写。你可能想要从 Excel 调用 R 或 Python 的一个原因是为了利用这些编程语言在数据分析可视化方面的强大功能和灵活性。Excel 是一种广泛使用的电子表格应用程序,可以处理大型数据集并执行基本的计算和函数。然而,当涉及到更高级或定制的任务时,例如统计建模、机器学习、网络抓取、自然语言处理等,Excel 有一些局限性。通过从 Excel 调用 R 或 Python,你可以访问这些语言提供的丰富库和包,并使用它们以更复杂的方式操纵、转换和可视化你的数据。你还可以自动化你的工作流程并创建可重复的报告和仪表板。从 Excel 调用 R 或 Python 可以提高你的生产力和效率,以及扩展你的分析能力。

在这里,我们将有一些不同。在本章中,我们将介绍两种从 Excel 调用 R 和 Python 的(非常)不同的方法:本地调用,其中 R 或 Python 安装在同一台机器上,以及运行和使用 API 调用,其中 R 或 Python 功能作为 API 端点部署到服务器上。对于后者,我们将探讨开源工具和一些最受欢迎的商业解决方案。

技术要求

在本章中,你可以在以下链接找到所有代码:github.com/PacktPublishing/Extending-Excel-with-Python-and-R/tree/main/Chapter%2011.

你需要安装以下外部软件:

  • BERT,可以在以下位置找到:bert-toolkit.com/download-bert

  • Python 和 xlwings(参考 设置环境 部分)

  • R 的 plumber

  • Python 的 FastAPI

让我们从第一部分开始。

在本地从 Excel 调用 R 和 Python

在本章的第一部分,我们将学习如何使用可以直接与 R 接口的 Excel,以及 xlwings 从 Excel 交互 Python。我们还将快速展示如何使用 VBA 脚本从 Excel 调用 R。在本章中,我们将涵盖以下主要主题:

  • 为什么你想要在本地从 Excel 调用 R/Python

  • 设置环境

  • 直接从 Excel 调用 R/Python

让我们开始吧!

为什么你想要在本地从 Excel 调用 R/Python

正如我们在开头讨论的那样,通过使用 VBA,你可以在 Excel 中进行各种分析和编程。然而,编写这些代码可能很繁琐,实施起来也困难。通过利用 BERTxlwings 的力量,你可以使用现成的丰富功能集,或者在这些语言中编写自己的函数并在 Excel 中使用它们。

使用 BERT,你可以在 Excel 中获得 R 的力量:R 是一种功能强大的统计编程语言,具有广泛的能力。BERT 允许你直接在 Excel 中使用这些能力,而无需切换到单独的 R 环境。如果你已经在 Excel 中工作,并且不想离开应用程序,这将非常方便。

BERT 允许你编写可以在 Excel 中用作自定义函数的 R 函数。这可以用于创建 Excel 中不可用的函数,或者提高现有 Excel 函数的性能。例如,你可以使用 BERT 调用 R 内部构建的函数来创建布朗运动,这在 R 中编码会比在 Excel 中更容易。

对于 R,BERT 是什么,对于 Python,xlwings 就是那个。它们的益处也是相似的:在 Python 中创建你的解决方案,然后直接从 Excel 中调用它。

让我们开始设置你的环境,这样你就可以动手实践了!

设置环境

由于设置 BERTxlwings 的环境不是一件简单的事情,我们将在接下来的小节中详细说明这个过程。

设置 BERT for R 的步骤

在本节中,我们将介绍在 Windows 上安装 BERT,以便我们可以利用 BERT 从 R 内部操作 Excel。我们首先必须做的是下载 BERT 安装程序,可以从这里获得:bert-toolkit.com/download-bert

下载完成后,你可以像安装任何其他程序一样安装它。安装后,你可以使用 Excel 的 添加组件 工作表来打开 BERT 控制台,如下所示:

图 11.1 – 从 Excel 的添加组件功能区打开的 BERT 控制台

图 11.1 – 从 Excel 的添加组件功能区打开的 BERT 控制台

一旦看到它,点击按钮,控制台就会打开,如下所示:

图 11.2 – BERT 控制台

图 11.2 – BERT 控制台

现在,让我们转向 Python。

设置 xlwings for Python 的步骤

在本小节中,我们将介绍设置 xlwings 所需的步骤:

安装 Python

确保你的机器上已安装 Python。你可以从官方 Python 网站下载最新版本(www.python.org/downloads/)。在安装过程中,你可以勾选表示 将 Python 添加到 PATH 的复选框,以便更容易访问。

安装 Excel 插件:

按照以下简单步骤开始使用 xlwings

  1. 打开命令提示符并运行以下命令:

    WARNING: The script xlwings.exe is installed in '<folder>' which is not on PATH. If you do, you will have to specify the full path to be able to call xlwings in the next step.
    
  2. 要安装插件,请使用命令行客户端:

    xlwings add-in will appear after the Help menu in the toolbar:
    

图 11.3 – Excel 中的 xlwings 在功能区

图 11.3 – Excel 中的 xlwings 在功能区

配置 Excel 和 Python 环境

在 Excel 插件设置中指定 Python 解释器路径来配置 xlwings。然而,这通常由 xlwings 自动完成。

为了验证设置,运行下一节中给出的任何示例。

故障排除

如果您遇到问题,请参阅 xlwings 的文档(docs.xlwings.org/en/stable/)。检查常见的故障排除技巧和解决方案。

这份逐步指南确保您本地环境的顺利设置,使 Excel 和 Python 能够无缝协同工作。遵循这些说明将为后续章节提供一个坚实的基础,让您能够利用 Excel 和 Python 的结合力量。

现在您已经设置好了,让我们来探讨如何实际使用这些工具!

直接从 Excel 调用 R/Python

在本节中,我们将深入探讨使用上一节中设置的工具从 Excel 调用 R 和 Python 的方法。我们将介绍几种实现方式,并提供示例,以便您可以尝试它们。

使用 VBA 和 BERT 执行 R

另一种从 Excel 调用 R 的好方法是使用 VBA 宏。这要求工作簿以宏启用工作簿保存。由于 BERT 是设计从 Excel 到 R 工作的,R 表达式的语法可以在 VBA 控制台中编写,并在 VBA 中使用以下方式调用:

Application.Run "BERT.Exec", r

让我们看看一个简单的例子:

Sub PlotNormalDensity()
    r = "plot(density(rnorm(1000)))"
    Application.Run "BERT.Exec", r
End Sub

这将最终生成一个随机正态分布密度的图表。让我们看看输出结果:

图 11.4 – 使用 BERT 从 VBA 调用 R

图 11.4 – 使用 BERT 从 VBA 调用 R

通过 BERT 与 Excel 交互

使用 BERT 通过 Excel 脚本接口 操作 Excel 是可能的。你可能想知道,“我为什么要做这样的事情”?好吧,记住,有了 BERT,你不仅可以访问 Excel,还可以访问 R。这意味着你可以使用 R 函数来生成数据,这些函数可能不在 Excel 中;让我们看看一个例子。这是在左侧面板中完成的。

首先,我们将定义一个范围:

rng <- EXCEL$Application$get_Range( "A1:B4" )

这将在 R 中定义一个范围,用于单元格 A1:B4,并将其作为名为 rng 的变量放入全局环境中。这是在 BERT 的 R 接口中输入的。现在这个范围已经定义,就可以看到有多少范围命令在您的指尖,以及其中的一些:

> length(ls(rng))
[1] 234
> head(ls(rng))
[1] "Activate"                        "AddComment"
                   "AddCommentThreaded"
[4] "AdvancedFilter"         "AllocateChanges"       "ApplyNames"

因此,我们看到有 234 个范围命令可用。通过调用 ls(rng),R 控制台将打印出所有命令;这里,我们使用 head() 以仅显示前几个。在这里,我们将使用 RAND() Excel 命令将随机数放入定义的范围中:

rng$put_Formula("=RAND()");

让我们看看 Excel 文件中的输出结果:

图 11.5 – 在 Excel 中使用 BERT 的 RAND() 函数

图 11.5 – 在 Excel 中使用 BERT 的 RAND() 函数

如果我们想保持在 BERT 内部并查看发送到 Excel 的值,我们可以执行以下操作:

> rng$get_Value()
                        [,1]            [,2]
[1,] 0.63474248 0.7993663
[2,] 0.55409965 0.4134328
[3,] 0.86992109 0.7948257
[4,] 0.07100827 0.9219299

现在我们已经了解了如何通过 R 与 Excel 交互的一些基础知识,是时候看看我们如何在 Python 中实现类似的功能了。

使用 xlwings 从 Excel 调用 Python

您可以使用 xlwings 从 Excel 调用 Python 的三种方法:

  • 标题栏 xlwings 选项卡下的 Run 按钮

  • 宏:这些从 Excel 调用 Python

  • 用户自定义函数UDFs)(仅限 Windows)

让我们来看看这三种方法的优缺点,以及一个示例!

运行按钮

Run 按钮期望在具有与工作簿相同名称的 Python 模块中有一个名为 main 的函数。这是文档中的引用,是一个硬性前提。这种方法的主要优点是无需 VBA 和宏;您可以使用正常的 XLSX 文件,这在不允许 XLSM 文件的安全受限情况下非常有用。

要尝试 Run 按钮,请按照以下步骤操作:

  1. 创建一个名为 sumitup.py 的 Python 模块,代码如下:

    import xlwings as xw
    def main():
                wb = xw.Book.caller()
                a = wb.sheets[0]['A1'].value
                b = wb.sheets[0]['A2'].value
                wb.sheets[0]['A3'].value = a + b
                pass
    
  2. 打开 Excel 并在单元格 A1 中输入 2,在单元格 A2 中输入 3

  3. 将 Excel 表格保存为 sumitup.xlsx,与 sumitup.py 所在的文件夹相同。

  4. 在功能区 xlwings 菜单中点击 Run 按钮。

这种方法的缺点是严格的命名约定和文件放置,以及缺乏灵活性;只有 main() 函数将被调用,Python 代码需要编码哪些字段将被用作输入以及输出将去哪里,这意味着您不能从 Excel 端传递输入到函数。

如果您需要更多的灵活性,并且可以使用宏(并将文件保存为 XLSM),您可以从 VBA 使用 RunPython

在这个例子中,RunPython 将导入 world 模块并运行该模块中的 helloworld() 函数。要运行此示例,请尝试以下步骤:

  1. 创建一个 .xlsm 文件并保存为 world.xlsm

  2. 打开 VBA 编辑器并尝试以下操作:

    1. 打开 xlwings 已被选中:

图 11.6 – 将 xlwings 引用添加到 VBA 项目中

图 11.6 – 将 xlwings 引用添加到 VBA 项目中

  1. 在文件中创建一个新的宏,使用 Sub 如下所示:

      Sub HelloWorld()
               RunPython "import world; world.helloworld()"
    End Sub
    
  2. 在保存 .xlsm 文件的同一文件夹中创建 hello.py 模块,内容如下:

    import xlwings as xw
    def helloworld():
        wb = xw.Book.caller()
        wb.sheets[0]['A1'].value = 'Hello World!'
    
  3. 现在,您可以在 world.xlsm 中运行宏并查看结果!

如您所见,使用宏解决了 Run 按钮的一个缺点,即 Python 模块(s)和函数(s)的位置和名称。然而,您仍然不能直接从 Excel 文件传递输入;输入必须在 Excel 文件中预先确定的单元格中,输出单元格(s)也必须预先确定。

注意,你可以更改模块的名称(以便不与 Excel 文件名称匹配)以及模块的位置(即,将其保存在与.xlsm文件不同的文件夹中)。从xlwings文档中,我们看到“默认情况下,RunPython 期望 Excel 文件目录中的 world.py 与 Excel 文件具有相同的名称,但你也可以更改这两者:如果你的 Python 文件在不同的文件夹中,请将此文件夹添加到 config 中的 PYTHONPATH。如果文件具有不同的名称,请相应地更改 RunPython 命令。”

UDFs

用户自定义函数允许用户扩展 Excel,添加可以像SUM()IF()一样使用的自定义函数。

如下所示,使用xlwings在 Python 中编写 UDF 非常简单:

import xlwings as xw
import numpy as np
@xw.func
@xw.arg('x', np.array, ndim=2)
@xw.arg('y', np.array, ndim=2)
def matrix_add(x, y):
    return x + y

在前面的示例中,我们指定输入都是numpy数组实例,并定义了矩阵加法函数。

要使用xlwings将 Python 函数集成到 Excel 中,你需要以特定的方式设置你的 Python 源文件。默认情况下,xlwings期望 Python 源文件位于 Excel 文件相同的目录中,并且与 Excel 文件具有相同的名称,但使用.py扩展名而不是.xlsm

或者,你可以通过xlwings功能区指定一个特定的模块。

一旦你准备好了你的 Python 源文件,你可以按照以下步骤将函数导入到 Excel 中:

  1. 将 Excel 文件保存为与你的 Python 模块相同的名称,并将其保存为与 Python 模块相同的文件夹中的.xlsm文件。

  2. 在 Excel 中,转到xlwings选项卡,然后单击导入 Python UDFs以获取对 Python 模块所做的更改。

  3. 将数据输入到 Excel 表中的两个范围(确保范围的维度适合矩阵乘法)。

  4. 在单元格中输入公式 =matrix_add([range1], [range2]),其中 [range1][range2] 是你已输入数据的数据范围。

    你应该看到正确的结果显示在单元格中:

图 11.7 – 使用 xlwings 的 matrix_add 函数从 Excel 中

图 11.7 – 使用 xlwings 的 matrix_add 函数从 Excel 中

这种方法的优点是显而易见的:Excel 用户可以确定使用哪些输入以及输出应该去哪里,而无需实际与 Python(或你,Python 开发者)交互。

这种方法的缺点是xlwings及其所有类似解决方案的通用缺点;对于本地 Python(或 R)安装,所有依赖项都必须正确设置,并且必须为所有用户提供正确的版本。

请注意,UDFs 不与 Python 一起工作,Python 可以从 Microsoft Store 获取。

值得注意的是,存在替代方案,尤其是 PyXLL,它是xlwings的流行替代品。它提供了类似的功能和限制(包括但不限于不与从 Microsoft Store 安装的 Python 一起工作)。

在本章中,你已经学习了为什么以及如何使用工具BERTxlwings直接从 Excel 调用 R 和 Python。

在本章的下一部分,我们将探讨另一种实现此类集成的方法,无需本地安装,同时完全控制代码及其版本(这在企业环境中可能很有用),但需要服务器环境。

通过 API 从 Excel 调用 R 和 Python

API,或应用程序编程接口,作为不同软件应用之间的桥梁,允许它们以标准化的方式通信和共享数据。它就像餐厅里的服务员,接受你的订单并将其传达给厨房,一旦准备好就带回食物。

在数字世界中,API 指定了软件组件应该如何交互。它定义了应用程序可以使用的方法和数据格式来请求和交换信息。API 可以用于各种目的,例如访问网络服务、数据库,甚至硬件设备。

API 的一个基本用途是允许第三方开发者将他们的应用程序与现有服务或平台集成。在你对 R 和 Python 的编码兴趣的背景下,API 可以用于数据检索,以及将你的模型暴露给其他软件,包括 Excel。

API 的美丽之处在于其多功能性。它们抽象了底层系统的复杂性,为开发者提供了一个标准化的方式来与之交互。这种抽象使得开发过程和集成过程更加直接,促进了协作和创新。

从本质上讲,API 是数字世界的隐形英雄,它促进了各种软件组件之间的无缝通信,并使得创建更强大和互联的应用程序成为可能。无论你是在处理数据、网络服务还是其他软件,理解和有效使用 API 可以显著提升你作为程序员的技能。

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

  • API 简介

  • 将 R 和 Python 作为 API 端点公开的开源解决方案

  • 从 Excel 调用 API 进行集成

API 简介

你可以将 API 想象成一套规则,允许一个软件组件与另一个软件组件交互。一个 API 使用的快速示例就是智能手机上的天气应用连接到天气系统以获取当前的天气或天气预报。

将 API 想象成一种机制,除了是不同系统之间通信的途径之外,还可以将其视为一份合同。API 的文档将具体说明一个系统如何连接并与另一个系统进行交流,它被允许做什么,以及频率如何。

维护 API 的系统通常会充当一种客户端和服务器类型的安排。REST API 是当今最受欢迎的 API 类型之一。REST代表表示状态转移。这种类型 API 的主要优点是它无状态。无状态意味着服务器在请求之间不会保存客户端数据。发送到服务器的请求会让你想起一个 URL。一个通用的 REST API 调用可能看起来如下:

 GET https://example.com/api/v1/users

你可以将前面的操作视为获取用户列表,你可能认为你会获取一个列表,因为这是一个GET请求。下面是一个通用的POST请求:

POST https://example.com/api/v1/users
Content-Type: application/json
{
  "name": "John Doe",
  "email": "john.doe@example.com"
}

在这里,你已经向服务器发送了(POST)数据。因此,在 REST API 中,考虑从服务器发送和获取信息。

现在我们已经了解了 API 是什么以及它们的一些类型和用例,我们可以继续探讨将 R/Python 作为 API 端点暴露的开源解决方案。

将 R 作为 API 端点暴露的开源解决方案

我们将首先展示如何通过 plumber 包将 R 暴露为一个 API 端点。plumber 包及其相关文档可以在以下 URL 找到:www.rplumber.io/index.html

我们首先要做的是构建一个非常简单的单参数 API,以获取标准正态分布的直方图。让我们看看代码;然后我们将讨论其中发生的事情:

#* Plot out data from a random normal distribution
#* @param .mean The mean of the standard normal distribution
#* @get /plot
#* @serializer png
function(.mean) {
  mu <- as.numeric(.mean)
  hist(rnorm(n = 1000, mean = mu, sd = 1))
}

#*开头的行是注释。在 plumber API 中,这些注释是特殊的,用于文档。它们描述了 API 端点的作用,并提供了有关参数的信息。第一条注释介绍了 API 端点的目的。它指出 API 将根据随机正态分布的数据生成一个图表。行#* @param .mean The mean of the standard normal deviation描述了一个名为.mean的参数,代表标准正态分布的均值。plumber API 中的参数类似于在请求 API 时可以传递的输入。

以下#* @get /plot注释指定了可以通过HTTP GET请求访问此 API 端点,端点路径是/plot。用简单的话说,如果你想使用这个 API,你会请求类似your-api-url/plot的东西。函数定义如下:function(.mean);这里,实际的 R 函数开始。它接受一个参数,.mean,这是标准正态分布的均值。为了将参数传递给rnorm()函数本身,我们必须确保将其声明为数值数据类型。我们通过以下方式内部声明:mu <- as.numeric(.mean),其中参数.mean被转换为数值并存储在一个名为mu的变量中。在将参数转换为数值后,我们可以将其传递给rnorm()hist()以创建图表。

最后,我们到了生成和绘制数据的地方。这是通过以下代码片段完成的:hist(rnorm(n = 1000, mean = mu, sd = 1)):这一行生成 1000 个来自指定均值(mu)和标准差(sd = 1)的正态分布的随机数。然后,它创建这些数字的直方图。本质上,它是在生成随机数据并绘制直方图。

总结来说,当部署此 plumber API 时,它创建了一个端点(/plot),当使用平均值访问时,会根据正态分布的随机数据生成直方图。平均值是您在向此 API 发出请求时提供的参数。这是一个简单而强大的例子,展示了您如何使用 R 和 plumber 在网络上公开数据处理能力。

现在我们已经生成了将生成 API 的代码,让我们看一下代码运行后的输出。为此,让我们查看以下脚本:

# Library Load
library(plumber)
# Set dir and file path
wd <- getwd()
sub_dir <- paste0("/Chapter 11/")
full_dir <- paste0(wd, sub_dir)
f <- "plumber_api.R"
f_path <- paste0(full_dir, f)
# Initiate root
root <- pr(f_path)
root
# Plumber router with 1 endpoint, 4 filters, and 0 sub-routers.
# Use `pr_run()` on this object to start the API.
├──[queryString]
├──[body]
├──[cookieParser]
├──[sharedSecret]
└──/plot (GET)

让我们逐行解释:

# Library Load
library(plumber)

这行代码加载了plumber包,这是创建 plumber API 所必需的:

# Set dir and file path
wd <- getwd()
sub_dir <- paste0("/Chapter 11/")
full_dir <- paste0(wd, sub_dir)
f <- "plumber_api.R"
f_path <- paste0(full_dir, f)

这些行设置了plumber API 文件的目录和文件路径。getwd()函数返回工作目录,即 R 当前使用当前目录。paste0()函数用于连接字符串,因此sub_dir变量包含字符串/Chapter11/,而full_dir变量包含到/Chapter12/目录的路径。f变量包含 plumber API 文件的文件名,即plumber_api.Rf_path变量包含 plumber API 文件的完整路径,这是full_dirf变量的组合:

# Initiate root
root <- pr(f_path)

这一行通过使用f_path变量作为参数调用pr()函数来启动 plumber API。pr()函数读取 plumber API 文件并创建一个 plumber API 对象:

root

这一行简单地返回root变量,它是 plumber API 对象。提供的 R 代码从名为plumber_api.R的文件中创建一个 plumber API。然后,可以使用 plumber API 将 R 函数公开为 Web 端点。

让我们用一个简单的类比:想象一下,你有一家餐厅,并想提供外卖服务。你可以创建一个简单的网站,让客户可以在线订购食物。该网站需要能够与你的餐厅厨房通信以放置订单。在这个类比中,plumber API 就像网站,而 R 函数就像餐厅的厨房。plumber API 允许你将 R 函数公开给外界,以便其他应用程序可以与之通信。现在让我们运行 API 并看看会发生什么;我们用以下代码这样做:pr_run(root)

图 11.8 – plumber GET API

图 11.8 – plumber GET API

我们看到,当我们运行前面的代码时,我们得到一个屏幕,允许我们测试 API;所以,让我们这样做。

要做到这一点,我们可以点击 GET 按钮,因为这是一个 GET API 调用。当我们这样做时,我们会看到以下屏幕:

图 11.9 – 输入 API 参数

图 11.9 – 输入 API 参数

我们可以看到我们可以向 .mean 的参数输入一个参数;让我们输入 10。首先,点击 Try it out 按钮,然后您可以输入一个值;然后,您可以点击 Execute,如以下截图所示:

图 11.10 – 输入参数并点击执行

图 11.10 – 输入参数并点击执行

现在,让我们点击那个 curl 请求:

curl -X GET "http://127.0.0.1:9220/plot?.mean=10" -H "accept: image/png"

接下来,我们获取请求 URL:

http://127.0.0.1:9220/plot?.mean=10

最后但同样重要的是,我们得到了直方图:

图 11.11 – 由 API 调用生成的直方图

图 11.11 – 由 API 调用生成的直方图

现在,我们已经学习了如何构建和使用 R 的 API,我们将在下一节学习如何为 Python 做同样的事情。

将 Python 作为 API 端点公开的开源解决方案

FastAPI 是一个基于 Python 3.7+ 标准 Python 类型提示的现代、快速(高性能)Web 框架,用于构建 API。它易于使用,并允许您快速创建健壮的 API。

您可以使用 pip 安装 FastAPI:

pip install fastapi

以下是一个创建 FastAPI 端点以公开 Python 函数的简化示例:

from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/api/add")
def add_numbers(
    num1: int = Query(..., description="First number"),
    num2: int = Query(..., description="Second number"),
):
    result = num1 + num2
    return {"result": result}

在此示例中,位于 /api/add 端点的 add_numbers 函数接受两个查询参数(num1num2),代表要相加的数字。使用 FastAPI 的 Query 函数定义这些参数,并带有可选的描述。然后计算结果,并返回包含结果的 JSON 响应。

通过这个示例,您现在可以向 /api/add?num1=3&num2=4 发送 GET 请求以获取结果。num1num2 参数在 URL 的查询字符串中指定。

FastAPI 自动生成 OpenAPI 和 JSON Schema 文档,使用户能够方便地理解和交互您的 API。

要运行开发服务器,请在命令行中运行以下命令:

uvicorn your_app_name:app --reload

your_app_name 替换为您的 Python 文件名,同时请注意,Python 文件名应不同于 fastapi 或与之前安装的模块类似。

重要提示

确保您的 API 安全,特别是如果它可以通过互联网访问。FastAPI 提供了处理身份验证和授权的功能。

我们已经介绍了如何为 R 和 Python 创建 API。现在是时候从 Excel 中调用我们创建的 API 了!

从 Excel VBA 调用 API

现在,我们将回顾代码,该代码将允许我们使用curl请求从由plumber_api.R文件生成的 API 中获取图片。为了做到这一点,您必须运行上一节中的代码:root |> pr_run();这是将打开 swagger 对话框并给出plumber中运行的 URL 的部分。对我来说,在撰写本文时,它如下所示:http://127.0.0.1:6855

在本节中,我们将特别执行 VBA 中的curl命令来发送GET请求。以下是将要运行的代码,解释将随后进行:

Sub MakeCurlRequestAndInsertImage()
       ' Define the curl command
       Dim curlCommand As String
       curlCommand = "curl -X GET ""http://127.0.0.1:6855/plot?.mean=0"" -H ""accept: image/png"" -o " & Environ("TEMP") & "\temp_image.png"
       ' Run the curl command using Shell
       Shell "cmd /c " & curlCommand, vbHide
       ' Create a new worksheet or refer to an existing one (Sheet1)
       Dim ws As Worksheet
       Set ws = ActiveWorkbook.Worksheets("Sheet1")
       ' Clear previous content in Sheet1
       ws.Cells.Clear
       ' Insert the image into the worksheet
       ws.Pictures.Insert(Environ("TEMP") & "\temp_image.png").Select
End Sub

让我们一步步简单地分解代码:

定义curl命令:

Dim curlCommand As String
curlCommand = "curl -X GET ""http://127.0.0.1:6855/plot?.mean=0"" -H ""accept: image/png"" -o " & Environ("TEMP") & "\temp_image.png"

这部分创建了一个变量(curlCommand),用于存储命令行指令。该命令实际上是在告诉计算机使用curl(一个用于发送 HTTP 请求的命令行工具)从指定的网址(http://127.0.0.1:6855/plot?.mean=0)获取图片。所有这些都在 VBA 编辑器中单行完成。-H标志指定了一个 HTTP 头,在这种情况下,告诉服务器我们接受 PNG 格式的图片。-o标志指定了输出文件,它被设置为将图片保存到临时文件夹中,文件名为temp_image.png

使用Shell运行curl命令:

Shell "cmd /c " & curlCommand, vbHide

这行代码使用 Windows 命令提示符(cmd /c)执行curlCommand。最后的vbHide意味着在执行过程中命令提示符窗口将不可见:

Create or refer to a worksheet (Sheet1):
Dim ws As Worksheet
Set ws = ActiveWorkbook.Worksheets("Sheet1")

这部分创建了一个变量(ws),用于表示 Excel 中的一个工作表。它要么创建一个名为"Sheet1"的新工作表,要么引用活动工作簿中现有的一个。

清除Sheet1中的先前内容:

ws.Cells.Clear

这行代码将指定工作表("Sheet1")中现有的任何内容清除。

将图片插入工作表:

ws.Pictures.Insert(Environ("TEMP") & "\temp_image.png").Select

这行代码将curl命令下载的图片插入指定的工作表("Sheet1")。Environ("TEMP")指的是系统的临时文件夹。"\temp_image.png"curl命令下载的图片文件名。

总结来说,这段 VBA 代码通过使用curl命令从网址下载图片,然后将该图片插入名为Sheet1的 Excel 工作表中。首先清除工作表,以确保没有之前的内容残留。

现在,让我们看看 VBA 脚本的输出:

图 11.12 – 由 R 从 VBA 生成的直方图

图 11.12 – 由 R 从 VBA 生成的直方图

在本节中,您学习了如何通过 R 中的 plumber 包创建 API。您还学习了如何在 Excel VBA 宏内部通过 curl 请求调用此 API。

基于 API 的解决方案之美在于,Excel(以及随之而来的终端用户)无需知道 API 背后的代码是用 R 编写的。同一个宏可以调用用 Python 编写的 API,而无需任何更改!

那么,这种方法的优缺点是什么?

优点已在之前阐明:无需本地安装,无需为每个用户维护 R/Python 环境,并且对 API 背后运行的代码拥有完全控制权。如果您需要更新任何内容,从 R/Python 版本到包依赖,再到代码本身,您都可以在服务器端进行,而无需涉及最终用户。

一个普遍存在的问题是所有基于 API 的解决方案:它需要设置和维护一个服务器,这对于数据分析师和数据科学家来说通常既困难又不被允许。这意味着需要专门的 IT 资源。

对于 API 托管的开源解决方案,有一个普遍存在的问题:你在许可证费用上节省的,你需要在更多自己动手上付出代价。开源 API 解决方案期望你处理安全性(参见 FastAPI 部分末尾的注释)、与企业环境的集成(如用户管理),以及通常需要你自己完成所有事情。

最后,plumberFastAPI的一个共同缺点是需要编写自定义代码来定义您的 API 端点和功能。在单人团队中,这除了需要的时间之外,并不是一个大问题,但在大型团队中,这往往导致一个碎片化的环境,在那里很难强制执行命名约定和标准化。

在本章的下一节中,我们将探讨一些最常用的商业解决方案,用于托管 R 和 Python API 端点,并了解它们如何解决这些问题。

R 和 Python 的商业 API 解决方案

在本节中,我们将介绍一些最常用的商业 API 解决方案,用于 R 和 Python。

Azure Functions(以及其他大型云服务提供商的类似解决方案)

Azure Functions 是由 Microsoft Azure 提供的一种无服务器计算服务。它允许您在不显式配置或管理基础设施的情况下运行由事件触发的代码。您可以使用包括 Python 和 JavaScript 在内的广泛支持的语言构建 API、响应事件和执行各种任务:

  • 用例:非常适合构建轻量级、事件驱动的 API 或微服务。与其他 Azure 服务的集成提供了可扩展性和灵活性。

  • 优点:无服务器基础设施意味着对 IT 参与的最小需求。

  • 缺点:灵活性有限(例如,R/Python 版本的选项)和迁移到其他云提供商的难度。

Posit Connect

Posit Connect 是一个商业解决方案,旨在将 R 和 Python 连接到 Excel。它促进了分析学和数据科学直接集成到 Excel 工作簿中,使用户能够在熟悉的 Excel 界面中利用 R 和 Python 的力量。

  • 用例:特别适合将 Excel 作为数据分析主要工具的组织,提供了一种无缝的方式,通过高级分析增强 Excel 的功能。

  • 优点:为 Posit 解决方案提供深度集成的生态系统,包括 RStudio、Quarto 和 Shiny Pro。

  • 缺点:它使用 plumber 和 FastAPI/Flask,因此您需要编写自定义代码来定义您的 API,从而导致在开源 API 解决方案下讨论的缺点。仅支持 Linux 服务器,无论是在本地还是在云端。

ownR Infinity 平台

ownR Infinity 是一个多功能的平台,旨在在用户友好的环境中赋予 R 和 Python 功能。通过启用创建个性化函数和模型,它们可以转化为可访问的 API,特别关注在 Excel 中的无缝集成。

  • 用例:适用于高度依赖 R 和 Python 进行高级数据分析的组织。非常适合寻求通过统计和数据分析功能增强 Excel 功能的用户。

  • 优点:提供了用户友好的界面,无需广泛的编程知识即可利用 R 和 Python 的功能。使 R 和 Python 的功能在各种环境中无缝集成。

  • 缺点:仅支持 Linux 服务器,无论是在本地还是在云端。

以下是如何在 Excel 中使用 ownR API 的示例,您可以在此处下载示例工作簿:bitbucket.org/functionalanalytics/examples/src/master/ccy%20converter%20Excel%20demo%20button.xlsm

以下代码示例使用托管 API:bitbucket.org/functionalanalytics/converter/src/master/

注意,除了纯 Python 代码(或 R 代码)之外,无需编写任何自定义代码,也无需手动添加安全性、部署和其他考虑因素,因为这些由 ownR 自动添加。

这些商业解决方案提供了高水平的集成和功能,用于连接 Python 和 R 与 Excel 和其他前端,满足分析和数据科学社区内多样化的用例和偏好。

与开源解决方案相比,商业解决方案的优点在于支持水平和在诸如开箱即用的安全性、与更广泛的企业的深度和易于集成以及出现问题时专门的客户支持等方面的指导。

缺点很明显:这些解决方案有许可费用,需要专门的预算。虽然所有这些公司都旨在以降低人工工作量并增加附加值来证明价格合理,但与预算持有者的讨论从来都不容易。

摘要

在本章中,您已经学习了如何从 Excel 而不是反过来调用 R 和 Python,以进一步增强最终用户的能力。我们涵盖了这样做的原因以及两种非常不同的方法:在本地调用 R 和 Python 以及通过 API 端点调用。

对于本地调用 R 和 Python,我们详细介绍了BERTxlwings,从设置和测试环境,到创建 R 和 Python 解决方案,以及如何使用BERTxlwings提供的各种方法从 Excel 中调用这些解决方案,例如 VBA 代码和 UDFs。

接下来,你学习了 API 端点以及使用 API 端点将 Python 和 R 连接到 Excel 的好处。我们讨论了这种设置的优缺点,然后深入探讨了两种 API 托管方式:开源工具和商业解决方案。我们介绍了两种最常用的开源设置:用于 R 的 plumber 和用于 Python 的 FastAPI。最后,我们查看了一些商业解决方案,用于托管 R 和 Python API 端点。

下一章(也是最后一章)将涵盖一个更具领域针对性的主题:在 Excel 中使用 Python 和 R 进行数据分析和可视化。

第五部分:使用 R 和 Python 对 Excel 数据进行数据分析与可视化 – 一个案例研究

利用 Python 和 R 的力量深入 Excel 中的数据分析与可视化世界。通过一个引人入胜的案例研究,你将发现如何利用这些多才多艺的编程语言来揭示洞察力,可视化数据,并在 Excel 中直接进行明智的决策。

本部分包含以下章节:

  • 第十二章在 Excel 中使用 R 和 Python 进行数据分析和可视化 – 一个案例研究

第十二章:使用 R 和 Python 在 Excel 中进行数据分析与可视化 – 案例研究

在本章的最后部分,我们将执行一个分析——可视化和一个简单的模型——使用 Excel 中的数据构建,并将所有这些结果放回其中。当数据量很大,或者计算本身最适合在 Excel 外部进行时,这可能很有用。

首先,我们将从导入我们的数据开始,然后通过可视化进行一些数据探索。对于本章,我们将使用名为 ggplot2 的 R 包中的 diamonds 数据集。我们将查看价格作为结果的数据,并通过钻石特性的不同方面来观察它。在完成可视化后,我们将进行一些简单的建模,以根据其特性预测钻石的价格。

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

  • 获取可视化

  • 执行一个简单的 机器学习ML) 模型

技术要求

对于本章,我们将使用以下包/库:

  • ggplot2 3.4.4

  • dplyr 1.1.4

  • healthyR 0.2.1

  • readxl 1.4.3

  • tidyverse 2.0.0

  • janitor 2.2.0

  • writexl 1.5.0

  • healthyR.ai 0.0.13

使用 R 获取可视化

在本节中,我们将介绍如何获取数据的一些可视化。我们将创建几个可视化,并对其中结果的简短解释。为此,我们将使用基础 R 创建两个直方图,并使用 ggplot2 库创建几个不同的可视化。

获取数据

我们需要做的第一件事是加载库并获取数据。我在一个特定于这本书的目录中工作,因此我可以直接从我所写的章节中获取函数;你的路径可能不同。让我们看看到目前为止的代码:

# Library Load
library(ggplot2)
library(dplyr)
library(healthyR)
library(readxl)
# Source Functions
source(paste0(getwd(),"/Chapter1/excel_sheet_reader.R"))
# Read data
file_path <- paste0(getwd(), "/Chapter12/")
df <- read_excel_sheets(
  filename = paste0(file_path, "diamonds_split.xlsx"),"),
  single_tbl = TRUE
)

我们在这里所做的是简单地调用几个库到我们的环境中,拉入读取工作表的函数,并读取我们的数据。我们使用 source() 命令将 read_excel_sheets() 函数加载到我们的环境中。你可能想知道本节的数据是如何创建的,这是很重要的,因为它是从 ggplot2 库导出的。如果你想要重新创建数据,以便前面的代码可以工作,接下来的部分也可以工作,以下是代码:

# Library Load
library(tidyverse)
library(writexl)
library(janitor)
# Write File to disk
file_path <- paste0(getwd(), "/Chapter12/")
# Split data by cut and clean names of the list
df_list <- split(diamonds, diamonds$cut) |>
  clean_names()
# Write to xlsx
df_list |>
  write_xlsx(paste0(file_path, "diamonds_split.xlsx"))

现在我们已经了解了如何生成和读取数据,让我们开始看看一些可视化。

可视化数据

在本节中,我们将使用两种不同的方法来创建图表,首先使用基础 R,其次使用 ggplot2。考虑到这一点,让我们开始吧。

基础 R 可视化

我们将要做的第一件事是为diamonds数据集中的price列创建一些直方图。价格是我们将在下一节中用作模型的预测变量的结果变量。首先,我们需要创建一个将传递给直方图的断点向量。关于最优分箱策略的技巧有很多文献。基本核心是这将有助于为直方图提供适当的形状,以最好地表示数据。这是一个单独的主题,我们不会在本书中探讨,因为这个主题可以单独成为一本书。有一个名为opt_bin()的函数来自healthyR包,它可以生成一个包含传递给它的value列断点的 tibble。让我们看看它:

breaks <- tibble(x = df$price) |>
  opt_bin(x) |>
  pull(value)
head(breaks)
[1]  326.000 1130.217 1934.435 2738.652 3542.870 4347.087

做这件事的目的是尝试捕捉数据中适当的信息密度。hist()基本函数已经以标准方法很好地完成了这一点。现在,让我们继续创建图表,并看看方法并排展示。我们将使用par(mfrow = c(1, 2)),这样我们就可以并排绘制它们:

par(mfrow = c(1, 2))
hist(df$price, main = "Price Histogram - Default binning",
      xlab = "Price", ylab = "Frequency")
hist(df$price, breaks = breaks, main = "Price Histogram - Optimal binning",
      xlab = "Price", ylab = "Frequency")
par(mfrow = c(1, 1))

让我们看看它产生了什么:

图 12.1 – 默认分箱与最优分箱的直方图比较

图 12.1 – 默认分箱与最优分箱的直方图比较

我们可以看到直方图的形状略有不同,但同样,这个策略可能不适合你,或者你可能有一个你经常使用的其他策略;这只是一个说明不同方法确实存在的方法。这就是使用基础 R 制作视觉效果的全部内容;我们现在将转向使用ggplot2

使用 ggplot2 的视觉效果

现在,我们将使用ggplot2制作其余的视觉效果,因为我发现它的语法更容易一些,而且可以生成的图形更复杂,除了它还是tidyverse包的一部分,这意味着它可以与其他包(如dplyr)互操作。你可能还需要安装hexbin包。让我们开始吧:

df |>
  ggplot(aes(x = carat, y = price, fill = cut)) +
  geom_hex(bins = length(breaks), alpha = 1/5) +
  facet_wrap(~ clarity, scales = "free") +
  theme_minimal() +
  labs(
     x = "Carat",
     y = "Price",
     title = "Diamonds Data",
     fill = "Cut"
  ) +
  hr_scale_color_colorblind()

下面是代码的分解。

对于数据和美学,是这样进行的:

  • df |> ggplot(...): 这使用df中的数据开始可视化。

  • aes(x = carat, y = price, fill = cut): 这定义了绘图的美学:

    • x: x 轴代表克拉重量

    • y: y 轴代表价格

    • fill: 颜色填充代表钻石的切割

对于六边形几何形状,我们有以下内容:

  • geom_hex(bins = length(breaks), alpha = 1/5): 这绘制了代表数据点的六边形。

  • bins: 这控制了六边形网格的箱数。在这里,它使用与breaks中定义的相同数量(在提供的代码中未显示)。

  • alpha: 这是六边形的透明度,设置为 1/5 以获得更好的可见性。

对于通过清晰度分面,我们有以下内容:

  • facet_wrap(~ clarity, scales = "free"): 这根据钻石的光度将数据分组到子图中,每个图都有独立的颜色尺度

这些是主题和标签:

  • theme_minimal(): 这应用了一个最小主题,以获得更清晰的视觉效果

  • labs(..., title = "Diamonds Data"): 这为坐标轴和标题添加了标签。

这是为色盲友好调色板编写的代码:

  • hr_scale_color_colorblind(): 这确保了调色板针对色盲观众进行了优化

现在,让我们检查输出。

图 12.2 – 使用六边形几何的 ggplot2 钻石数据

图 12.2 – 使用六边形几何的 ggplot2 钻石数据

总体而言,此代码可视化了钻石的克拉重量、价格和切割之间的关系,并考虑了具有色盲友好调色板的光度组。

下一个我们将看到的视觉是使用箱线图来检查数据的分散:

df |>
  ggplot(aes(x = carat, y = price, fill = cut)) +
  geom_boxplot(alpha = 1/5, outlier.color = "lightgrey") +
  facet_wrap(~ clarity, scales = "free") +
  theme_minimal() +
  labs(
     x = "Carat",
     y = "Price",
     title = "Diamonds Data",
     fille = "Cut"
  ) +
  hr_scale_color_colorblind()

再次,让我们看看输出:

图 12.3 – ggplot2 价格分散箱线图

图 12.3 – ggplot2 价格分散箱线图

我们现在可以带着一个问题来看平均价格:它是否准确地显示了信息?让我们参考以下代码:

df |>
  summarize(m = mean(price), .by = c(clarity, cut)) |>
  ggplot(aes(x = clarity, y = m, group = cut, color = cut)) +
  geom_point() +
  geom_line() +
  geom_smooth() +
  facet_wrap(~cut, ncol = 2) +
  labs(x= "Clarity",
         y = "Mean Price",
         title = "Mean Price by Clarity and Cut",
         color = "Cut") +
  theme_minimal() +
  hr_scale_color_colorblind()

此代码的输出如下:

图 12.4 – ggplot2 平均价格分散

图 12.4 – ggplot2 平均价格分散

这里是平均价格的另一视角,但这次是通过查看每克拉的平均价格:

df |>
  summarize(m = mean(price/carat), .by = c(cut, color, clarity)) |>
  ggplot(aes(x = color, y = m, group = clarity, color = clarity)) +
  geom_point() +
  geom_line() +
  facet_wrap(~ cut, ncol = 2, scales = "free") +
  labs(x= "Clarity",
         y = "Mean Price",
         title = "Mean Price per Carat by Clarity, Color and Cut",
         color = "Cut") +
  theme_minimal() +
  hr_scale_color_colorblind()

让我们看看这个故事告诉我们什么:

图 12.5 – ggplot 每克拉平均价格

图 12.5 – ggplot 每克拉平均价格

这些是非常好的钻石 – 只要清晰度比“良好”更好,切割或颜色是否重要?看起来并不重要。

最后,我们将查看一个按切割而不是按颜色分面的价格直方图,我们将使用之前创建的breaks数据。请看以下代码:

df |>
  ggplot(aes(x = price)) +
  geom_histogram(breaks = breaks, fill = "lightblue",
                        color = "black") +
  theme_minimal() +
  facet_wrap(~ cut, ncol = 2, scales = 'free') +
  labs(x = "Price", y = "Frequency", title = "Price Histogram by Cut")

让我们再看最后一眼:

图 12.6 – 根据切割方式分面的价格直方图

图 12.6 – 根据切割方式分面的价格直方图

现在我们已经创建了所有视觉元素,我们可以进入建模阶段。

使用 R 执行简单的机器学习模型

在本节中,我们将介绍如何在 R 中执行一个简单的机器学习模型。在 R 中有许多不同的方法来做这件事,我无法一一列出,然而 CRAN 已经做了这件事,这样你和我就不必做了。如果你想查看 CRAN 上机器学习的任务视图,可以点击以下链接:cran.r-project.org/view=MachineLearning

对于本节,我们将使用由healthyR.ai包实现的 XGBoost 算法。算法本身并没有不同的写法,唯一的不同是输出中数据保存的方式。healthyR.ai包还包含 XGBoost 算法的预处理程序,以确保在建模之前输入数据与算法期望的数据匹配。我们将使用的主要函数是hai_xgboost_data_prepper()hai_auto_xgboost()

我们不会再次介绍加载数据,因为之前已经介绍过了。让我们开始吧!

数据预处理

在我们开始之前,我们将预处理我们的数据,以确保它满足算法建模的需求。这可以通过healthyR.ai库中的hai_xgboost_data_prepper()函数来实现。我们将看看数据在处理前后的样子。让我们看看以下代码和输出:

# Lib Load
library(healthyR.ai)
library(dplyr)
glimpse(head(df, 2))
Rows: 2
Columns: 10
$ carat   <dbl> 0.22, 0.86
$ cut      <chr> "Fair", "Fair"
$ color   <chr> "E", "E"
$ clarity <chr> "VS2", "SI2"
$ depth   <dbl> 65.1, 55.1
$ table   <dbl> 61, 69
$ price   <dbl> 337, 2757
$ x         <dbl> 3.87, 6.45
$ y         <dbl> 3.78, 6.33
$ z         <dbl> 2.49, 3.52

这是处理开始之前的数据。我们看到有 10 列,我们可以在输出中清楚地看到每一列的数据类型。现在,让我们通过将数据传递给hai_xgboost_data_prepper()并检查那里的输出来创建一个recipe对象。这个函数接受两个参数:.data.recipe_formula

# Pass data through pre-processor
rec_obj <- hai_xgboost_data_prepper(
  .data = df,
  .recipe_formula = price ~ .
)
rec_obj
── Recipe ───────────
── Inputs
Number of variables by role
outcome:   1
predictor: 9
── Operations
• Factor variables from: tidyselect::vars_select_helpers$where(is.character)
• Novel factor level assignment for: recipes::all_nominal_predictors()
• Dummy variables from: recipes::all_nominal_predictors()
• Zero variance filter on: recipes::all_predictors()

现在,让我们看看处理后的数据。我们可以看到以下列已经添加,并且所有数据类型现在都是<dbl>,这是预处理程序所要求的:

# Now see the juiced output
get_juiced_data(rec_obj) |>
  head(2) |>
  glimpse()
Rows: 2
Columns: 24
$ carat            <dbl> 0.22, 0.86
$ depth            <dbl> 65.1, 55.1
$ table            <dbl> 61, 69
$ x                  <dbl> 3.87, 6.45
$ y                  <dbl> 3.78, 6.33
$ z                  <dbl> 2.49, 3.52
$ price            <dbl> 337, 2757
$ cut_Good        <dbl> 0, 0
$ cut_Ideal      <dbl> 0, 0
$ cut_Premium   <dbl> 0, 0
$ cut_Very.Good <dbl> 0, 0
$ color_E         <dbl> 1, 1
$ color_F         <dbl> 0, 0
$ color_G         <dbl> 0, 0
$ color_H         <dbl> 0, 0
$ color_I         <dbl> 0, 0
$ color_J         <dbl> 0, 0
$ clarity_IF     <dbl> 0, 0
$ clarity_SI1   <dbl> 0, 0
$ clarity_SI2   <dbl> 0, 1
$ clarity_VS1   <dbl> 0, 0
$ clarity_VS2   <dbl> 1, 0
$ clarity_VVS1  <dbl> 0, 0
$ clarity_VVS2  <dbl> 0, 0

现在我们已经看到了处理后的数据,让我们使用hai_auto_xgboost()函数进行建模。这是完整的函数调用和它的文档可以在www.spsanderson.com/healthyR.ai/reference/hai_auto_xgboost.html找到:

hai_auto_xgboost(
  .data,
  .rec_obj,
  .splits_obj = NULL,
  .rsamp_obj = NULL,
  .tune = TRUE,
  .grid_size = 10,
  .num_cores = 1,
  .best_metric = "f_meas",
  .model_type = "classification"
)

现在,我们将创建模型并检查输出。我使用了.num_cores = 10.best_metric = "rsq".model_type = "regression",并且我不建议你自己运行这个,除非你有足够的时间。

现在,使用hai_auto_xgboost()函数进行建模:

auto_xgb <- hai_auto_xgboost(
  .data = df,
  .rec_obj = rec_obj,
  .best_metric = "rsq",
  .num_cores = 10,
  .model_type = "regression"
)

这会产生一个相当大的对象;在我的机器上,它是 196.1 MB,其中最大部分是$tuned_info,占169836312 bytes,这主要是由于plotly图和 Monte Carlo 交叉验证的tibble,因为输入数据的大小。我们现在可以看看导出的某些对象:

xgb_wflw_fit <- auto_xgb$model_info$fitted_wflw
class(xgb_wflw_fit)
[1] "workflow"
mod_spec <- xgb_wflw_fit[["fit"]][["actions"]][["model"]][["spec"]]
mod_spec
Boosted Tree Model Specification (regression)
Main Arguments:
  trees = 817
  min_n = 17
  tree_depth = 9
  learn_rate = 0.0205081386887847
  loss_reduction = 2.0421383990836e-05
  sample_size = 0.762693894910626
Computational engine: xgboost

我们首先做的是提取拟合的工作流对象,该对象可以用来使用通用的predict()函数对数据进行预测。我们知道它是一个workflow对象,因为我们运行了class(xgb_wflw_fit)

我们最后要做的就是查看拟合模型的规格本身。这将显示在交叉验证过程中设置的参数。重要的是要记住,我没有使用种子,这意味着您可能得到不同的结果。这旨在作为一个入门,而不是对输入和输出的详尽描述,而是仅仅展示如何将 XGBoost 模型拟合到 Excel 文件中的数据,因为您不能像在 R 中那样轻松地完成这样的建模任务。

现在,我们可以进入 Python 部分,我们将对相同的数据集执行类似的流程。

使用 Python 获取可视化

在本节中,我们将回顾 Python 中的数据可视化,类似于前面的 R 部分。我们将使用 plotnine 来创建与 R 中使用 ggplot2 创建的可视化相似的结果,并提供结果的解释。

获取数据

就像前面的章节一样,我们将使用 pandas 加载数据。就像之前一样,XLSX 文件的路径可能与你我的不同,所以相应地调整 filepath

import pandas as pd
# Define the file path (may be different for you)
file_path = "./Chapter 12/diamonds.xlsx"
# Load the dataset into a pandas DataFrame
df = pd.read_excel(file_path)
# Display the first few rows of the DataFrame
print(df.head())

注意,我们使用原始的 diamonds 数据集,而没有先将其分割再重新组合,就像本章 R 部分所做的那样。

可视化数据

一旦我们加载数据,我们就可以使用 plotnine 创建可视化。在本节中,我们将演示如何可视化 diamonds 数据集的各个方面。

使用之前加载的数据集,我们可以先看看数据:

from plotnine import ggplot, aes, geom_bin2d, facet_wrap, theme_minimal, labs, scale_fill_manual
# Define a colorblind-friendly color palette
color_palette = ["#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7"]
# Plot using plotnine
(
    ggplot(df, aes(x='carat', y='price', fill='cut')) +
    geom_bin2d(bins=20) +  # Adjust the bins parameter as needed
    facet_wrap('~ clarity', scales='free') +
    theme_minimal() +
    labs(
        x='Carat',
        y='Price',
        title='Diamonds Data',
        fill='Cut'
    ) +
    scale_fill_manual(values=color_palette)
)

这段 Python 代码使用 plotnine 对数据进行了可视化,复制了本章开头使用的 R 代码。ggplot() 函数初始化绘图,aes() 定义美学,geom_bin2d() 添加几何形状,facet_wrap() 创建面元,theme_minimal() 设置主题,labs() 添加标签,scale_fill_manual(values=color_palette) 确保使用预定义的 color_palette 使调色板色盲友好。

生成的图像将看起来像这样:

图 12.7 – diamonds 数据集的 plotnine 散点图

图 12.7 – diamonds 数据集的 plotnine 散点图

如您所见,该图通过使用颜色编码钻石的切割来显示克拉重量和价格之间的关系,并使用色盲友好的颜色方案。

让我们来看看数据的箱线图(我们不会再次重新导入所有的 plotnine 函数):

from plotnine import geom_boxplot
# Plot using plotnine
(
    ggplot(df, aes(x='carat', y='price', fill='cut')) +
    geom_boxplot(alpha=1/5, outlier_color="lightgrey") +
    facet_wrap('~ clarity', scales='free') +
    theme_minimal() +
    labs(
        x='Carat',
        y='Price',
        title='Diamonds Data',
        fill='Cut'
    ) +
    scale_fill_manual(values=color_palette)
)

在此代码中,geom_boxplot() 用于创建箱线图。outlier_color 参数设置为 lightgrey 以改变箱线图中异常值的颜色:

图 12.8 – diamonds 数据集的箱线图

图 12.8 – diamonds 数据集的箱线图

数据可视化的核心目的是为了深入了解数据,以便更好地理解它。如果我们绘制平均价格,我们会看到我们需要看到的内容吗?

我们可以使用pandas中的groupby功能来汇总价格,计算每个组的平均值,并创建一个包含点、线和平滑线的图表,以可视化清晰度和切工的平均价格:

from plotnine import geom_point, geom_line, geom_smooth, scale_color_manual
# Plot the mean price
(
    ggplot(df.groupby(['clarity', 'cut']).mean().reset_index(), aes(x='clarity', y='price', group='cut', color='cut')) +
    geom_point() +
    geom_line() +
    geom_smooth() +
    facet_wrap('~ cut', ncol=2) +
    labs(
        x='Clarity',
        y='Mean Price',
        title='Mean Price by Clarity and Cut',
        color='Cut'
    ) +
    theme_minimal() +
    scale_color_manual(values=color_palette)
)

让我们看看结果数据可视化:

图 12.9 – 根据清晰度和切工的平均价格

图 12.9 – 根据清晰度和切工的平均价格

对于每个切工,都会出现类似的曲线:平均价格首先随着清晰度的提高而上升,然后下降。上升和下降对于理想清晰度来说最不相关,而对于优质非常好清晰度来说最相关。

我们能否通过以不同的分组绘制平均价格来获得更多见解?让我们看看每克拉的平均价格:

# Calculate mean price per carat by clarity, color, and cut
df_mean = df.groupby(['cut', 'color', 'clarity']).apply(lambda x: (x['price'] / x['carat']).mean()).reset_index(name='m')
# Plot using plotnine
(
        ggplot(df_mean, aes(x='color', y='m', group='clarity', color='clarity')) +
        geom_point() +
        geom_line() +
        facet_wrap('~ cut', ncol=2, scales='free') +
        labs(
                x='Clarity',
                y='Mean Price',
                title='Mean Price per Carat by Clarity, 
                Color and Cut',
                color='Cut'
        ) +
        scale_color_manual(values=color_palette)
)

结果图像确实显示了一些有趣的东西:

图 12.10 – 根据清晰度、颜色和切工的平均价格

图 12.10 – 根据清晰度、颜色和切工的平均价格

对于除了公平以外的所有清晰度,我们看到 D 色对于 IF 切工的价格极端,但对于其他切工,价格保持相似。然而,对于公平清晰度,价格显示出明显的下降趋势,只有 D 色与其他颜色在 I1 切工之间存在较大的价格差异。

最后,在继续建模之前,让我们看看价格按切工的直方图:

from plotnine import geom_histogram
# Create a histogram of price by Cut
(
        ggplot(df, aes(x='price')) +
        geom_histogram(fill='lightblue', color='black') +
        theme_minimal() +
        facet_wrap('~ cut', ncol=2, scales='free') +
        labs(x='Price', y='Frequency', title='Price Histogram by Cut')
)

我们使用默认的分组,因为不幸的是,用于 R 版本的优秀包healthyR目前还没有 Python 版本(可用)。

图 12.11 – 根据切工的价格直方图

图 12.11 – 根据切工的价格直方图

我们可以看到价格有一个非常长的尾巴(也就是说,即使不常见,极高价格也是相对典型的),并且令人惊讶的是,我们还可以看到良好优质切工的第二个高点(对于非常好切工来说,程度较小)。

通过可视化更好地理解了数据,我们可以开始建模!

使用 Python 执行简单的机器学习模型

在本节中,我们将在 Python 中创建一个简单的机器学习模型。Python 已经成长为主要用于机器学习工作的语言(R 是明显的替代品),实现机器学习算法的包的数量难以高估。话虽如此,sklearn仍然是使用最广泛的,因此我们也将选择它在本节中使用。与本章的 R 部分类似,我们将使用xgboost模型,因为它在性能和可解释性之间取得了很好的平衡。

我们将使用上一节中加载的数据。

数据预处理

对于建模阶段的第一步,是准备数据。幸运的是,sklearn内置了预处理功能!

让我们回顾一下数据预处理中涉及到的步骤:

  • sklearn提供了填充缺失值或删除包含缺失数据行/列的方法。

  • sklearn提供了用于缩放特征的实用工具,包括标准化(将特征缩放到具有零均值和单位方差)和归一化(将特征缩放到指定的范围)。

  • sklearn提供了一元编码分类变量或使用序数标签进行编码的方法。

  • sklearn提供了用于按指定比例将数据集分为训练集和测试集的函数。

  • sklearn支持各种特征工程技术,例如多项式特征生成、交互项创建以及使用主成分分析(PCA)等技术进行降维。

注意

重要的是要在不将测试数据的信息污染到训练数据中的方式下进行特征工程,就像数据清洗(如插补)一样。

我们在专门的章节中详细介绍了数据清洗,因此我们将利用diamonds数据集已经清洗好的事实。我们将继续进行特征缩放和分类变量的编码:

from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.model_selection import train_test_split
import numpy as np
# Encode categorical variables
encoder = OneHotEncoder()
df_encoded = encoder.fit_transform(df[['cut', 'color', 'clarity']])
# Scale numerical features
scaler = StandardScaler()
df_scaled = scaler.fit_transform(df[['carat', 'depth', 'table', 
    'x', 'y', 'z']])
# Concatenate encoded categorical features with scaled numerical features
df_processed = np.concatenate((df_encoded.toarray(), df_scaled),
    axis=1)
# Split data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(
    df_processed, df["price"], test_size=0.2, random_state=42)

此代码片段演示了如何使用独热编码对分类变量(切割、颜色和清晰度)进行编码,并使用sklearn中的StandardScaler对数值特征进行缩放。然后,它将编码的分类特征与缩放的数值特征连接起来,并使用train_test_split()将数据集分为训练集和测试集。

让我们比较预处理前后的数据。

原始数据集看起来如下:

图 12.12 – 从 Excel 读取的原始数据

图 12.12 – 从 Excel 读取的原始数据

如您所见,数据集包含数值和分类变量(后者将使用独热编码进行编码)的混合。

预处理之后,数据集看起来如下:

图 12.13 – 预处理后的训练数据

之前展示的预处理后的训练数据行数较少(其余部分构成测试数据),但列数更多:虽然price列不存在(这是我们想要预测的变量),但分类变量已被多个01值所替代 – 这是独热编码的结果。对于每个分类变量的每个唯一值,都会引入一个新列,如果原始数据集有该值,则该列的值为1,如果有其他值,则该列的值为0

y_train变量包含训练数据中每行的price列的值。

使用预处理后的数据,我们可以开始建模:

from sklearn.ensemble import GradientBoostingRegressor
from sklearn.metrics import mean_squared_error
# Instantiate XGBoost regressor
xgb_reg = GradientBoostingRegressor(random_state=42)
# Train the model
xgb_reg.fit(X_train, y_train)
# Predict on the test set
y_pred = xgb_reg.predict(X_test)
# Calculate RMSE
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
print("Root Mean Squared Error:", rmse)

在此代码中,我们观察到以下内容:

  1. 我们从sklearn.ensemble中导入GradientBoostingRegressor

  2. 我们从scikit-learn的实现中实例化了一个梯度提升回归器(xgb_reg)。

  3. 我们使用训练数据(X_trainy_train)通过fit方法训练模型。

  4. 我们使用predict方法在测试集上进行预测,并计算预测值(y_pred)与实际目标值(y_test)之间的RMSE

RMSE 是回归分析中广泛使用的指标,用于衡量预测值与观察值之间误差的平均幅度。它提供了一个单一的数值来评估回归模型的拟合优度。RMSE 与目标变量(price)处于相同的尺度(单位)。

RMSE 的值越低,表明模型的预测值越接近实际值,这意味着性能更好。换句话说,较低的 RMSE 表示模型与真实值的平均偏差更小,这表明更高的准确性和更好的预测能力。

RMSE 特别有用,因为它考虑了误差的幅度,并且对较大误差的惩罚比对较小误差的惩罚更重。因此,最小化 RMSE 导致的模型能提供更精确和准确的预测。

总体而言,RMSE 是一个有价值的工具,用于比较不同的回归模型,并在实际应用中评估它们的预测准确性。

模型结果具有大约 720 的均方根误差(RMSE),这显著低于平均价格(3933)和 price 变量的标准差(3989)。这确实是好消息,因为它表明模型拟合相当好。

当然,您可以考虑其他机器学习模型(如随机森林、lightgbmcatgbm,甚至 深度学习模型)以及其他拟合优度指标(如 R2、MAE 等)。本节旨在作为端到端工作流程的入门指南,因此探索这些选项超出了本书的范围。

摘要

在最后一章中,我们探讨了使用 R 和 Python 以及来自 Excel 的数据执行数据分析和可视化的技术。我们首先加载并可视化了 diamonds 数据集以及用于数据可视化的 ggplot2plotnine 库。通过箱线图、平均价格可视化和直方图等各种图表,我们了解了数据集中不同变量之间的关系。

在进行机器学习建模时,我们使用了 healthyRscikit-learn 库来预处理数据,包括编码分类变量并将数据集划分为训练集和测试集。然后我们使用 XGBoost 算法实现了一个回归模型,并使用 RMSE 指标评估其性能。

通过利用 R、Python 和 Excel 的优势,用户可以增强他们的分析能力,并从他们的数据中提取有价值的见解。

感谢您与我们一同踏上通过 Excel 中的 R 和 Python 探索数据分析与可视化的激动人心的旅程。我们希望您觉得内容引人入胜,示例富有洞察力。随着您继续探索和实施从本书中获得的知识,我们希望您能在数据驱动的努力中发现新的可能性和机会。祝您分析愉快,可视化精彩!

posted @ 2025-10-23 15:19  绝不原创的飞龙  阅读(5)  评论(0)    收藏  举报