4.数据可视化(一)

数据可视化

4.1 简介

“The simple graph has brought more information to the data analyst’s mind than any other device.” — John Tukey

通过本节你将学会如何使用ggplot2可视化数据。R有多种用于生成图的系统,但ggplot2是最高效和最通用的系统之一。Ggplot2实现了graphics语法,这是一个用于描述和构建图的连贯系统。它可以许多地方快速地完成任务。

如果想了解更多关于 ggplot2 的理论基础,可参阅我的简书主页ggplot2绘图

4.1.1 数据准备

本章主要关注ggplot2,它是 tidyverse 的核心成员之一。要访问本章将要用到的数据集、帮助页面和函数,通过运行下面的代码来加载tidyverse:

library(tidyverse)
#> ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.0 ──
#> ✔ ggplot2 3.3.2     ✔ purrr   0.3.4
#> ✔ tibble  3.0.3     ✔ dplyr   1.0.2
#> ✔ tidyr   1.1.2     ✔ stringr 1.4.0
#> ✔ readr   1.4.0     ✔ forcats 0.5.0
#> ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
#> ✖ dplyr::filter() masks stats::filter()
#> ✖ dplyr::lag()    masks stats::lag()

这一行代码加载了核心的tidyverse,该包几乎在每个数据分析中均可用到。它还告诉您 tidyverse 中的哪些函数与R Base中的函数(或您可能已加载的其他包)中的函数发生冲突。

如果你运行这段代码得到了错误“there is no package called ' tidyverse '”,你需要首先安装它,然后再加载 library()。

install.packages("tidyverse")
library(tidyverse)

您只需要安装一次软件包,但每次打开一个新的窗口时都需要重新加载它。

如果我们需要明确函数(或数据集)的来源,我们将使用特殊形式package::function()。例如,ggplot2::ggplot()明确告诉您我们正在使用ggplot2 包中的ggplot()函数。

4.2 开始

让我们用第一张图来回答一个问题:大引擎的汽车比小引擎的汽车耗油量更高吗?你可能已经有了一个答案,但要尽量使你的答案准确。发动机尺寸和燃油效率之间的关系是怎样的?是正值还是负值呢?线性还是非线性呢?

4.2.1 使用mpg数据

您可以使用在ggplot2(又名ggplot2::mpg)中的mpg数据集来得到你的答案。数据集中的变量(在列中)和观察值(在行中)的矩形集合构成。mpg包含了美国环境保护局对38种车型收集的观察结果。

mpg
#> # A tibble: 234 x 11
#>   manufacturer model displ  year   cyl trans      drv     cty   hwy fl    class 
#>   <chr>        <chr> <dbl> <int> <int> <chr>      <chr> <int> <int> <chr> <chr> 
#> 1 audi         a4      1.8  1999     4 auto(l5)   f        18    29 p     compa…
#> 2 audi         a4      1.8  1999     4 manual(m5) f        21    29 p     compa…
#> 3 audi         a4      2    2008     4 manual(m6) f        20    31 p     compa…
#> 4 audi         a4      2    2008     4 auto(av)   f        21    30 p     compa…
#> 5 audi         a4      2.8  1999     6 auto(l5)   f        16    26 p     compa…
#> 6 audi         a4      2.8  1999     6 manual(m5) f        18    26 p     compa…
#> # … with 228 more rows

mpg中的变量包括:

  1. displ,汽车的发动机尺寸,以升为单位。

  2. hwy, 汽车在高速公路上的燃油效率,以英里每加仑 (mpg) 为单位。燃油效率低的汽车在行驶相同距离时比燃油效率高的汽车消耗更多的燃料。

要了解mpg更多信息,请通过运行?mpg打开其帮助页面。

4.2.2 创建ggplot

首先绘制mpg

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy))
image

该图显示了发动机尺寸 ( displ) 和燃油效率 ( hwy)之间呈负相关关系。换句话说,大引擎的汽车使用更多的燃料。

使用 ggplot2,您可以使用函数ggplot()开始绘图。ggplot()创建一个坐标系,您可以向其中添加图层。ggplot()的第一个参数是要在图中使用的数据集。所以ggplot(data = mpg)创建了一个空图,但它几乎没什么用。

您可以通过向ggplot()中添加一个或多个层来完成您的图表。该geom_point()函数为您的绘图添加了一层点,从而创建了一个散点图。ggplot2 带有许多 geom 函数,每个函数都会向绘图添加不同类型的图层。在本章中,您将了解到更多。

ggplot2 中的每个 geom 函数都有一个mapping参数。这定义了数据集中的变量如何映射到图形属性。mapping的参数总是与aes()配对,aes()中的xy的参数指定要映射哪些变量的x和y轴。ggplot2 在data参数中查找映射变量,在本例中为mpg

4.2.3 ggplot2绘图模板

以下代码是一个可重复使用的模板,用 ggplot2 绘制图表。要绘制图形,将以下代码中括号内的部分替换为数据集、几何函数或映射集合。

ggplot(data = <DATA>) + 
  <GEOM_FUNCTION>(mapping = aes(<MAPPINGS>))

本章的其余部分将向您展示如何完成和扩展此模板以绘制不同类型的图形。我们将从<MAPPINGS>组件开始。

4.3 几何对象

“The greatest value of a picture is when it forces us to notice what we never expected to see.” — John Tukey

在下图中,一组点(以红色突出显示)似乎落在线性趋势之外。这些汽车的行驶里程比您预期的要高。你怎么解释这些车?

image

让我们假设汽车是混合动力车。检验这一假设的一种方法是查看class每辆车的价值。mpg数据集的class变量将汽车分为紧凑型、中型和 SUV 等组。如果外围点是混合动力车,它们应该归类为紧凑型汽车,或者可能是超小型汽车。

您可以通过将第三个变量(例如 )class映射到几何对象,将其添加到二维散点图。图形属性是绘图中对象的视觉属性。图形属性包括诸如点的大小、形状或颜色之类的东西。您可以通过更改其图形属性的值以不同方式显示一个点(如下所示)。既然我们已经用“value”这个词来描述数据,那么让我们用“level”这个词来描述图形属性。在这里,我们更改点的大小、形状和颜色的级别,使点变小、三角形或蓝色:

image

您可以通过将绘图中的图形属性映射到数据集中的变量来传达有关数据的信息。例如,您可以将点的颜色映射到class变量以显示每辆车的类别。

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, color = class))
image

(关于颜色属性可以使用colour代替color。)

要将图形属性映射到变量,请将图形属性的名称与内部变量aes()的名称相关联。ggplot2 会自动为变量的每个唯一值分配一个唯一的图形属性级别(这里是一个唯一的颜色),这个过程称为标度。ggplot2 还将添加一个图例,解释哪些级别对应于哪些值。

颜色表明许多不寻常的点是两人座汽车。这些车看起来不像混合动力车,实际上是跑车!跑车拥有大型发动机,如 SUV 和皮卡车,但车身较小,如中型和紧凑型汽车,这提高了它们的油耗。后面来看,这些汽车不太可能是混合动力车,因为它们有大型发动机。

在上面的例子中,我们映射class到颜色图形属性,但我们可以class用同样的方式映射到尺寸图形属性。在这种情况下,每个点的确切大小将揭示其类从属关系。我们在这里收到警告,因为将无序变量 ( class)映射到有序变量 ( size) 不是一个好主意。

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, size = class))
#> Warning: Using size for a discrete variable is not advised.
image

或者我们可以映射classalpha属性,它控制点的透明度,或者映射到shape属性,它控制点的形状。

# Left
ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, alpha = class))

# Right
ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy, shape = class))
image
image

SUV到底怎么了?ggplot2 一次只会使用六个形状。默认情况下,当您使用形状属性时,不会绘制其他组。

对于每种属性,您使用aes()将图形属性名称与要显示的变量相关联。该aes()函数将图层使用的每个图形属性映射汇集在一起,并将它们传递给图层的映射参数。点的 x 和 y 位置本身就是图形、视觉属性,您可以将其映射到变量以显示有关数据的信息。

一旦您映射了图形属性,ggplot2 会处理其余的事情。它选择了一个合理的scale来与图形属性一起使用,并构建一个图例来解释级别和值之间的映射。对于 x 和 y 属性,ggplot2 不会创建图例,但会创建带有刻度线和标签的轴线。轴线作为图例;它解释了位置和值之间的映射。

您还可以手动设置geom 的图形属性。例如,我们可以将绘图中的所有点设为蓝色:

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy), color = "blue")
image

在这里,颜色不会传达有关变量的信息,而只会改变绘图的外观。要手动设置图形属性,请按名称将图形属性设置为 geom 函数的参数;即它外面aes()。您需要选择一个对这种属性有意义的级别:

  • 作为字符串的颜色名称。

  • 以毫米为单位的点的大小。

  • 点的形状为数字,如图所示。

R 有 25 个由数字标识的内置形状。 有一些看起来是重复的:例如,0、15 和 22 都是正方形。 差异来自“颜色”和“填充”属性的相互作用。 空心形状 (0--14) 的边界由“颜色”决定; 实心形状 (15--20) 填充了“颜色”; 填充的形状 (21--24) 的边框为 `color`,并填充有 `fill`。

4.4 常见问题

当您开始运行 R 代码时,您可能会遇到问题。

首先仔细比较您正在运行的代码与书中的代码。R是非常挑剔的,一个放错位置的字符可能会造成完全不同的结果。确保every(与a匹配)和every“与另一个配对”。有时您将运行代码,但什么也没有发生。检查控制台左侧:如果是+,这意味着R认为您没有输入完整的表达式,它正在等待您完成它。在这种情况下,通过按ESCAPE来中止当前命令的处理,通常很容易从头开始。

创建 ggplot2 图形时的一个常见问题是将+放在错误的位置:它必须位于行尾,而不是开头。如下:

ggplot(data = mpg) 
+ geom_point(mapping = aes(x = displ, y = hwy))

如果您仍然卡住,请尝试帮助。您可以通过?function_name在控制台中运行或在 RStudio 中选择函数名称并按 F1来获取有关任何 R 函数的帮助。如果帮助看起来没有用,请不要担心 - 可以跳到示例并查找与您要执行的操作相匹配的代码。

如果这没有帮助,请仔细阅读错误消息。有时答案会被埋在那里!但是,当您不熟悉 R 时,答案可能在错误消息中,但您还不知道如何理解它。你可以尝试在谷歌上搜索错误消息,因为很可能其他人也遇到了同样的问题,并在线获得了帮助。

4.5 分面

添加额外变量的一种方法是使用图形属性。另一种方法(对于分类变量尤其有用)是将图划分为facet,每个子图显示数据的一个子集。

使用facet_wrap()可以用一个变量对绘图进行分面。facet_wrap()的第一个参数应该是一个公式,可以用~和一个变量名创建它(这里的“公式”是R中的一个数据结构的名称,而不是“等式”的同义词)。传递给facet_wrap()的变量应该是离散的。

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy)) + 
  facet_wrap(~ class, nrow = 2)
image

要根据两个变量的组合对绘图进行f分面,请添加facet_grid()到绘图调用中。的第一个参数facet_grid()也是一个公式。这次公式应该包含两个变量名,以~.

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy)) + 
  facet_grid(drv ~ cyl)
image

如果您不想在行或列维度中分面,请使用一个.代替变量名称,例如 + facet_grid(. ~ cyl).

4.5.1练习

  1. 如果您对连续变量进行分面会发生什么?

  2. 图中的空单元格facet_grid(drv ~ cyl)是什么意思?他们与这个图形有什么关系?

    ggplot(data = mpg) + 
      geom_point(mapping = aes(x = drv, y = cyl))
    
  3. 下面的代码做了什么图?有什么作用.

    ggplot(data = mpg) + 
      geom_point(mapping = aes(x = displ, y = hwy)) +
      facet_grid(drv ~ .)
    
    ggplot(data = mpg) + 
      geom_point(mapping = aes(x = displ, y = hwy)) +
      facet_grid(. ~ cyl)
    
  4. 以本节中的第一个分面图为例:

    ggplot(data = mpg) + 
      geom_point(mapping = aes(x = displ, y = hwy)) + 
      facet_wrap(~ class, nrow = 2)
    

    使用分面代替颜色属性有什么优点?有什么缺点?如果你有一个更大的数据集,会如何变化?

  5. 阅读?facet_wrapnrow有什么作用?ncol有什么作用?还有哪些其他选项可以控制各个面板的布局?为什么 facet_grid()没有nrowncol

  6. 使用facet_grid()时,您通常应该将具有更多唯一级别的变量放在列中。为什么?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 193,968评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,682评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,254评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,074评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,964评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,055评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,484评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,170评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,433评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,512评论 2 308
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,296评论 1 325
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,184评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,545评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,150评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,437评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,630评论 2 335

推荐阅读更多精彩内容