使用泰坦尼克号数据潜入 tidyverse

使用泰坦尼克号数据潜入 tidyverse

使用 R 的 dplyr 和 tidyr 包提取见解

Photo by 马克斯·范登·欧特拉尔 on 不飞溅

今天的数据比以往任何时候都更加可用。我们可以通过互联网上的许多资源轻松找到我们感兴趣的内容。然而,当试图从数据中得出结论时,我们很快意识到数据虽然很容易找到,但并不是一种可以很容易地用于更详细分析的格式。当几个人尝试合作进行某些研究时,也会出现同样的问题。如果他们之前没有就如何标记和输入数据达成一致,那么每个人很可能都会想出自己的系统。这最终会导致共享和分析数据时出现混乱。这些问题产生了对独特数据组织系统的需求。

列夫·托尔斯泰在他的作品《安娜·卡列尼娜》中表达了这样的想法:

所有幸福的家庭都是一样的;每个不幸的家庭都有自己的不幸。

提到这句话,R 语言编程的一位远见卓识者 Hadley Wickham 用以下话语解决了数据组织问题:

整洁的数据集都是相似的,但每个杂乱无章的数据集都以自己的方式杂乱无章。

有了整洁的数据,每一行都是一个观察值,每一列是一个变量。假设我们按马力和重量列出了汽车的类型。以整齐的方式组织的数据将包含三列:汽车类型、马力和质量。因此,通过查看一行数据,我们将获得有关一种类型汽车的所有信息。专注于一个数据列将提供有关所有类型汽车的单个属性(例如质量)的信息。

为了将数据转换成整洁的格式,Hadley Wickham 开发了 tidyverse - 一套包含以下软件包的软件包: dplyr , 让我们 , ggplot2 , 咕噜咕噜 , 读者 小标题 .在下文中,我们将重点关注这些用于数据整理的包的子集 - dplyr , 让我们 小标题 .

虽然 tidyverse 提出了一套一致且有效的数据转换和可视化方法,重要的是要强调两点:

  • 使用获得的结果 tidyverse 可以使用基本的 R 函数获得函数(尽管通常以更复杂/不太直观的方式)
  • R 是一种编程语言,并且 tidyverse 是一组旨在促进数据转换和可视化的软件包。换句话说, tidyverse 包并不能解决我们可能遇到的所有问题,因此了解 R 编程的基础知识也很重要。

泰坦尼克号数据集

Photo by 美国国家海洋和大气管理局 on 不飞溅

在接下来的文章中,我将介绍最重要的功能 dplyr , 让我们 小标题 包。我将展示如何使用这些函数来执行涉及数据清理和探索性数据分析的各种常见任务。我将使用最著名的船只之一泰坦尼克号的乘客数据。

作为第一步,我们必须加载必要的包并研究我们将使用的数据结构。除了数据整理包之外,我们还必须加载 泰坦尼克号 包含所需数据的包。

泰坦尼克号数据集是 数据框 类型对象。因此,如果我们打印 Titanic 数据集,将返回整个 891 行。由于这样的布局笨拙且繁琐,我只使用基数 R 打印了前十行 功能。为了绕过这个问题, 小标题 包介绍了一个 小标题 数据类型。这种类型改进了 数据框 通过在显示数据集时仅打印前十行来分类。它还打印出数据集的行数和列数以及每列的数据类型。

即便是 函数可以改进,因为它不指示列数据类型,并且当有许多变量(许多列)时,它不会全部显示,而是仅显示尽可能多的屏幕。相反,我们可以使用 一瞥 命令显示打印输出的转置版本,以获得更完整的数据概览。

我们可以看到数据包含12个变量:乘客序列号(PassengerId)、二进制乘客生存变量(Survived)、乘客等级(Pclass)、姓名(Name)、性别(Sex)、年龄(Age)、兄弟姐妹数量和机上配偶 (Sibsp)、机上儿童/父母人数 (Parch)、票号 (Ticket)、已付票价 (Fare)、客舱号 (Cabin) 和乘客登机地点 (Embarked)。

管道 %>% 运算符

Photo by 西格蒙德 on 不飞溅

在继续分析之前,我想介绍一下管道运算符。管道运算符的优点是能够绑定函数。更准确地说,它将一个函数的结果作为第一个参数传递给序列中的下一个函数。起初这似乎不是很有用,但在使用多个函数的组合时,它大大提高了代码的清晰度。让我们看一个例子。

管道运算符使我们能够从左到右阅读作品,就好像我们在阅读一本书一样!一旦你习惯了使用它,我保证你永远不会回头。这就是为什么即使没有它也可以使用所有 R 函数,我将在本文的其余部分使用管道。

使用 dplyr 包提取信息

dplyr 包包含促进数据操作以提取有意义的见解的功能。它的部分灵感来自 SQL(结构化查询语言),所以那些有 SQL 背景的人可能会觉得它们非常直观。

重命名列

我们将首先使用重命名列 改名 为了让他们更容易理解。

重命名也可以通过将函数应用于多个列来执行,使用 rename_with 功能。例如,我们可能更喜欢所有变量名都用小写字母书写的约定:

根据名称选择列

我们通常对所有数据集变量都不感兴趣。这 选择 函数允许我们对感兴趣的列进行子集化。

如果所需的列在初始数据框中相邻放置,还有一种更短的选择它们的方法:

如果我们只想选择姓名和与船上亲属数量相关的变量怎么办?当然,我们可以再次使用第一个示例中的技术。然而, 选择 也可以与大量的辅助函数结合使用,使这些任务更快更容易执行。例如, 包含 helper 允许我们按列名的一部分进行搜索。如果我们注意到与亲属数量相关的两个变量都包含下划线符号,我们可以使用它。

类似于 包含 函数,我们也可以使用 以。。开始 以。。结束 功能。有关所有帮助函数的列表和说明,您可以通过键入来查阅帮助文件 ?选择 在 R 控制台中。

列选择也可以通过指定我们要从数据中删除的列来执行。这是通过在不需要的列的名称前面放置一个减号来完成的。

让我们通过删除机票、客舱号码和与船上亲属/配偶数量相关的列来简化我们的数据集:

基于值的列选择

如果我们只对包含数值的列感兴趣怎么办?我们可以手动查找变量类型,然后按照上一小节中的过程进行操作。

幸运的是,这项繁琐的任务可以自动化,因为列选择也可以基于存储在其中的值通过组合 选择 在哪里 功能。

使用 mutate 转换现有列或添加新列

变异 函数允许我们使用外部数据或数据框中已存在的数据来转换现有列或创建新列。

R有一个方便的 因素 当分类变量具有有限数量的可能值(级别)时,应使用内置类。我们可以看到 Sex 变量具有这样的属性。 变异 使我们能够更改列数据类型:

你们中的一些人可能还想缩写性别值。这可以使用 case_when 功能:

一次转换多个列

你们中的一些人可能注意到,将 Survived 和 Embarked 列的数据类型从字符转换为因子也不错。

我们可以通过应用 变异 + 穿过 组合。这 穿过 function 指定要转换的列和要应用的函数。

中列的选择 穿过 功能也可以使用在谈论应用程序时提到的辅助函数来执行 选择 功能。

筛选 数据框行

筛选 函数用于对数据中的观察进行子集化。因此,它可用于回答有关机上不同乘客群体的问题。

有多少乘客在坠机事故中幸存?

只有三分之一多一点的乘客在坠机事故中幸存下来。乘客性别是否存在生存差异?

乘客中女性的比例是多少?

在坠机事故中幸存的女性乘客比例是多少?

因此,尽管女性乘客人数较少,但她们的生存机会大约是男性的两倍。当然,这是意料之中的,因为妇女和儿童在救援任务中被优先考虑。

接下来,我们将检查生存如何根据乘客等级而变化。

如果您乘坐较低级别的旅行,生存的机会就会降低。这可能是由于较富裕的乘客的影响,也可能是由于头等舱更靠近救援船驻扎的船甲板。

还有 筛选 辅助函数 if_any 我摔倒 这允许我们一次过滤多个列。这些可用于执行删除具有缺失值的观察的常见任务。

安排 基于列值的行

Photo by 托尔加乌尔坎 on 不飞溅

通常,我们希望根据某个感兴趣的标准对数据进行排序。这是用 dplyr 使用 安排 .让我们按年龄升序对乘客进行排序,然后按姓名字母顺序对相同年龄的乘客进行排序。默认情况下,排序是升序,但 描述 命令可用于降序排序。

从这个输出中,我们可以假设老年乘客更可能是男性而不是女性。此外,似乎年纪较大的乘客似乎是更高级别的乘客。对我来说,这是一个合理的说法,因为我知道泰坦尼克号是从英国到美国的,它载着很多人在寻找新的机会和更好的生活。我会假设这样的人会更年轻,因为年长的人没有动力离开。我们将能够使用接下来两个小节中介绍的工具来回答所有这些问题。

获取列汇总统计信息 总结

Photo by 安妮·尼加德 on 不飞溅

当我们对单个值不感兴趣,但对数据集的汇总统计感兴趣时,此命令非常有用。让我们计算乘客的平均年龄。

我们得到了意想不到的结果。这是数据中的“漏洞”已被 NA 替换的结果(“不可用”,缺失数据)。我们可以通过在计算汇总统计数据之前过滤数据框以排除年龄未知的乘客来解决这个问题。过滤时,我们使用一个特殊的命令来测试数据是否属于类型 - is.na .

就像与 变异 , 总结 也可以与 穿过 为了一次获得多个列的摘要。

为了回答与性别和乘客等级有关的年龄差异问题,我们可以首先过滤感兴趣的人群,然后计算所需的摘要。但是,这种方法需要我们每次都写出一个新的摘要,类似于我们根据乘客类别计算存活率的方式。为了避免这种情况,我们将使用 通过...分组 下一小节中介绍的功能。

根据分类属性对观察进行分组 通过...分组

就其本身而言, 总结 功能不会那么有用,但与 通过...分组 函数,它允许快速汇总有关所有级别的分类变量的信息。这 通过...分组 函数根据某个变量的类别将数据分组。然后将感兴趣的函数分别应用于这些组中的每一个,使用 总结 ,并将结果组合回单个数据帧。

How group_by works behind the scenes. Image by Author.

这种组合最终使我们能够优雅地回答前面提出的假设。

船上 55 岁以上的男性人数增加了三倍,所以我们的第一个假设似乎被证明是正确的。

让我们也检查一下关于班级相关年龄差异的第二个假设:

我们的预感似乎得到了数据的支持,因为乘客等级和年龄之间似乎确实存在相关性。

请注意,这种方法还使我们能够更容易地找出基于乘客类别的生存差异,在 筛选 小节。

以与 总结 函数 通过...分组 命令可以与 变异 筛选 命令。

让我们创建一个变量,根据性别按年龄对乘客进行排名。这 命令将通过为从最小到最大的一组值分配一个序数来帮助我们。与 安排 命令,可以使用反转默认顺序 描述 .

结合 通过...分组 筛选 例如,可以为我们提供每个性别的三个最年长乘客的列表。

结果与我们之前的结论一致,因为最年长的女性乘客比最年长的男性小 17 岁。

事实证明,还有一个方便 slice_max 函数来实现相同的目标,所以上面的代码片段只能用作教育示例。

要取消分组,我们使用 取消组合 功能。建议在涉及分组的任何转换结束时执行此操作。这是因为忘记我们已按某个变量对数据进行分组可能会导致进一步分析中出现意外结果。

用于组合/匹配数据帧的函数

How join functions work. Image by Author.

早些时候,在计算平均年龄时,我们注意到泰坦尼克号数据不完整。让我们看看这些乘客是谁:

幸运的是,泰坦尼克号坠机事件非常有名,以至于有许多专门列出乘客及其背景的网页。因此,我们可以创建一个新的数据框,其中将包含一些缺少数据的乘客的姓名和年龄。

由于丢失的数据分散在 Titanic 数据集中(查看实际上只是行号的 PassengerId 值),因此很难手动附加附加信息。这些类型的问题可以通过以下方式解决 left_join , 一种基于公共标识变量将数据从一个数据帧添加到另一个数据帧的函数。

请注意,我们有 Age.x 和 Age.y,而不是单个 Age 变量。这样做是为了使我们能够辨别年龄变量来自哪个数据框。我们可以用 变异 case_when 将两个年龄列合并为一个。

用 tidyr 整理

顾名思义, 让我们 包包含将数据帧转换为整洁格式的命令。 Titanic 数据框已经很整洁了,因为每一行代表一个乘客,每一列代表一个独立的乘客特征。但是,数据集通常不是这种情况。此外,在某些情况下(例如绘图)可能需要“不整洁”的格式。下一小节将说明这样一个例子。

使用 pivot_wider 和 pivot_longer 的宽长格式转换

这些可能是最有价值的功能 让我们 包裹。这 pivot_longer 当我们想要将多个列转换为具有多个子组的单个列时,该函数很有用。下图说明了这是如何工作的。

How the pivot functions work. Image by Author.

左边的表格包含三个相关的列——它们都代表一种亲戚。知道了这一点,我们可能希望将它们分组到一个“相对”列中。这使数据更长(因此在函数名称中更长)。此外,它变得不整洁,因为同一个人由三个单独的行表示。我们为什么要这样做?

好吧,如果我们想在水平轴上制作一个相对类型的条形图,我们必须提供一个变量。我们可以用右边的格式做到这一点,但不能用左边的格式。

现在让我们展示如何将这些转换应用于泰坦尼克号数据。为了更容易理解转换,我们将只选择 Titanic 数据框的前三行:

我们可以通过应用使用更少的列来显示相同​​的数据 pivot_longer .例如,我们可以有一个乘客姓名列和两个包含乘客属性(乘客类别、年龄、性别、生存)所有信息的列。为什么属性有两列而不是一列?因为一列必须包含有关该属性的信息,而另一列必须包含该属性的值。由于我们正在组合数字和字符值,我们必须首先将所有值转换为相同的类型(字符)。

正如预期的那样,行数增加了七倍,因为现在我们必须将每位乘客的姓名重复七次——为 Parameter_name 列中的每个参数重复一次。当然,与上图中的示例相反,以这种方式对参数进行分组是没有意义的,因为它们不相关。但是,如果您经常使用数据,这些类型的问题将是您遇到的最少的问题,因为输入至少是一致的。你可能永远不会自己创建这样的数据,但我在这里这样做是为了向你展示当有人带来它时如何摆脱这种混乱(相信我,最终会有人......)。

作为反 pivot_longer 功能, pivot_wider 是答案。

当然,我们还应该将列值转换回它们的正确类型。

分离()和联合()

Photo by 弗朗西斯威尔 on 不飞溅

就像前面提到的 pivot_longer pivot_wider ,这两个函数也是互为逆的。使用原因的最简单示例 分离 功能是分隔日期记录。假设我们有一列奥运奖牌获得者的生日日期,格式为 day_month_year,我们想要计算获奖者的平均年龄。这意味着我们必须以某种方式仅从日期中提取年份。 分离 使我们能够做到这一点,例如,从一个日期变量中生成三个变量:日、月和年。这 团结 函数以相反的方式工作,将多个变量连接成一个变量(例如,将日、月、年转换为格式为 day_month_year 的日期变量)。本质上,它只是一个 粘贴 带有一些附加参数的函数,例如允许从数据框中自动删除输入列。

查看乘客的姓名,我们可以看到他们可以分为几组。逗号前的第一个单词是姓氏,然后是标题和名字。将这些组分开是很有用的,因为我们可以获得额外的信息。例如,来自乘客头衔的婚姻状况信息——已婚乘客的 Mr/Mrs 和单身乘客的 Master/Miss。

对于那些不熟悉正则表达式的人,表达式 [,\\.] 翻译为:每当遇到逗号或点时,就拆分字符串。为什么我们需要点前面的反斜杠?因为点本身在正则表达式中具有特殊含义,所以这是一种告诉 R 我们对点字符本身感兴趣的方法,而不是它的特殊功能。

这些标题让我们深入了解了乘客群体的社会结构,否则我们将无法轻松访问。

结论

我希望这篇文章对你有用,并且你学到了一些新东西。我试图涵盖尽可能多的常见任务和问题。但是,没有一个(非模拟)数据集包含您在数据分析中可能遇到的所有问题,因此有许多问题和场景没有被涵盖。此外,如果不将数据可视化,就无法完成探索性数据分析。由于添加它会使这篇文章太长,我把它留给了未来的故事。不过,如果您有任何疑问或遇到想要使用 tidyverse 工具箱,请随时发表评论!

PS 快速概览/提醒 dplyr 让我们 包和它们的用法,你可以使用得心应手 备忘单 由 RStudio 提供。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明

本文链接:https://www.qanswer.top/3222/26513110

posted @ 2022-08-31 10:29  哈哈哈来了啊啊啊  阅读(74)  评论(0编辑  收藏  举报