ggplot2 快速入门:基础图形作法

ggplot2 快速入门:基础图形作法

一、实验介绍

1.1 实验内容

从课程《R 语言快速入门》 中,我们已经了解过 Hadley Wickham 的 tidyverse 生态链,知道了完整的数据分析大约包括以下流程:

 ggplot2 快速入门:基础图形作法

 Source: Hadley Wickham, R for Data Science, 2016. 可视化(Visualise)不仅是数据探索(Explore)中至关重要的一个环节,而且充满趣味和成就感(所见即所得)。我们既可以用图形来验证猜想,也可以从图形中发现不为人知的秘密。因此,从基础的可视化工具开始接触数据科学通常是一个不错的选择。本课程即将带你感受 R 最受欢迎的作图工具包 ggplot2 的魅力,为你的数据科学之路奠定一个良好的开端。 通过本课程的学习,你将

  • 理解 ggplot2 基本思想和图形语法
  • 使用 ggplot2 画出优雅的散点图、折线图、柱状图、箱线图等常用图形

1.2 实验知识点

  • ggplot2
  • 附加变量
  • 几何对象
  • 统计变换
  • 坐标系

1.3 实验环境

  • R 3.4.1
  • Xfce 终端

1.4 适合人群

本课程难度较小,适合已经掌握 R 基本语法,想了解 ggplot2 作图方法和入门数据科学的朋友。

二、实验内容

2.1 ggplot2

R 语言包含多种作图工具,每种工具自有一套逻辑体系,ggplot2 则凭借它的优雅与灵活受到大部分数据科学家的喜爱。 在 2.1 节中,你将理解 ggplot2 作图的基本思想,拥有一套完整的语法模版,从模版中你将得知一个图形的要素有哪些。此外,如果你只是想迅速获得对数据的直观感受,我们还将介绍简化的作图方法。

2.1.1 基本思想

我们先进入一个实例,一边应用 ggplot2 中的函数,一边探索它的基本思想。 打开桌面上的 Xfce 终端,从云端下载实验所需数据。car.csv 文件中保存了 2011 年中国各地区每百户家用汽车保有量数据。

$ wget http://labfile.oss.aliyuncs.com/courses/978/car.csv

ggplot2 快速入门:基础图形作法

进入 R 环境 

$ sudo R

 

ggplot2 快速入门:基础图形作法

ggplot2 是 tidyverse 生态链的核心 package,因为实验环境中已经安装有 tidyverse package,所以我们可以直接加载它。如果你是在 RStudio 中操作,记得先用 install.packages() 命令安装 tidyverse

> library(tidyverse)

ggplot2 快速入门:基础图形作法

 

上图中,虚线以上部分是 tidyverse 包含的核心 package,虚线以下部分是 tidyverse 和其它 package 冲突的函数,使用这些函数时需要指明来源。接下来我们使用 tidyverse 中的 read_csv() 函数读取实验数据,并保存在 da 中。

> da <- read_csv('car.csv')

ggplot2 快速入门:基础图形作法

 

值得注意的是,read_csv() 的结果是一个 tibble 对象,tibble 本质上也是 data frame 的一种,行为观测值,列为变量,但和 R 中常见的 data.frame 不同,它有许多良好的性质。比如,我们想查看 da 变量的结构或者前几行,不需要再用 str() 或 head() 函数,而是直接运行 da 就可以了。tidyverse 中大部分数据都是 tibble 结构。

# 查看 da
> da

 

ggplot2 快速入门:基础图形作法

 从上图中我们可以看到,da 是一个 31 行、6 列的 tibble 对象,它的前 10 行被呈现出来。6 个变量依次为省份(或直辖市)、地区(E 为东部、M 为中部、NE 为东北、W 为西部)、家用汽车每百户平均保有量、人均GDP、城镇人口比重、交通工具消费价格指数,变量类型前两个为 char、后四个为 double。关键信息只需一个小小的命令就能被呈现出来,这就是 tibble 人性化的地方。 至此,准备工作已经做好,下面我们就来探索 ggplot2的基本思想。 假设我们想观察各省市家用汽车平均保有量和人均 GDP 之间有什么关系,我们可以作出 car 随 GDP 变动的散点图。 Step 1:

ggplot(data = da)

ggplot2 快速入门:基础图形作法

 

 只定义数据参数data,此时 ggplot() 生成一张空白的画布。

Step 2:

ggplot(data = da, mapping = aes(x = GDP, y = car))

ggplot2 快速入门:基础图形作法

 

 除 data 外,还定义了映射参数 mapping,将 GDP 映射到 x 轴,car 映射到 y 轴,此时图形有了坐标轴。

Step 3:

ggplot(data = da, mapping = aes(x = GDP, y = car)) + 
  geom_point()

ggplot2 快速入门:基础图形作法

 

 除数据和映射参数外,还使用 geom_point() 添加了几何对象,此时图中出现了散点,这些点的分布表示平均汽车保有量和人均 GDP 之间似乎存在正相关关系。 从以上三个分解的步骤中,我们可以体会到 ggplot2 作图的逻辑,即它需要使用一定的几何对象(点、线等)来表示整理好的数据,并且在数据和图像属性(如 x、y轴,颜色,形状等)之间建立一定的映射

Step 3 中的命令还可以简写为

# 默认 ggplot 的第一个参数为 data,第二个参数为 mapping,aes的第一个值为 x 轴,第二个值为 y轴。
ggplot(da, aes(GDP, car)) +
  geom_point()

或改写为

# mapping 的参数设定仅在 geom_point() 中使用
ggplot(data = da) +
  geom_point(mapping = aes(x = GDP, y = car))

2.1.2 语法模版

从 2.1.1 节的尝试中,我们可以总结出 ggplot2 的一套语法模版:

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

通过后续的学习,你将得到更加完整的语法模版:

ggplot(data = <DATA>) + 
  <GEOM_FUNCTION>(
  mapping = aes(<MAPPINGS>),
  stat = <STAT>,
  positon = <POSITION>,
  ) + 
  <COORDINATE_FUNCTION> + 
  <FACET_FUNCTION>

2.1.3 图形要素

从完整的语法模版中,我们得知 ggplot2 图形有以下要素:

  • 数据
  • 几何对象
  • 属性映射
  • 统计转换
  • 位置调整
  • 坐标系
  • 块面结构

你将在接下来的实验中陆续接触到这些概念。

2.1.4 快速图形作法

如果我们只是想用最少的代码迅速获得对数据的直观感受,可以使用 qplot() 函数。

qplot(GDP, car, data = da)

ggplot2 快速入门:基础图形作法

 

 尽管 qplot() 看起来更简洁,而且理论上可以实现所有 ggplot() 的功能,但是随着图形变得更加复杂,ggplot() 将是一个更好的选择。

2.2 附加变量

从 2.1 节的散点图中,我们似乎找到了 car 和 GDP 的一种正相关关系,这是两个变量之间的关系。 但是,考虑一下,如果我们想往二维图形中添加第三个变量,比如我们想知道各个样本点分别属于什么地区,或者想看不同地区的 car 和 GDP 之间的关系,应该怎么做呢? 两个坐标轴已经被固定了,第三个变量只能通过其它途径反映出来。接下来我们介绍两种途径,一种是属性映射,即把第三个变量作为某种属性赋给图形,另一种是块面图,即按照第三个变量进行分组,在不同组中呈现前两个变量之间的关系。属性映射和块面图都体现了一种分组的思想,只是前者是隐性的,后者是显性的。

2.2.1 属性映射

我们将第三个变量 region 赋值给 colorgeom_point() 就会自动把观测值按照 region 分组,每组用不同颜色的点在画布上标出。

ggplot(data = da) +
  geom_point(mapping = aes(x = GDP, y = car, color = region))

ggplot2 快速入门:基础图形作法

 

 从上图中可以看到,东部省份盘踞在右上角,人均 GDP 和平均汽车保有量都很高,中西部省份则蜷缩在左下角,这体现了我国地区间经济发展的不平衡,共同富裕的发展路线只实现了前面一半,我国仍然处于*初级阶段。 我们把省份名称标注在图上,看看能不能得出更有意思的结论。

ggplot(da, aes(GDP, car)) +
  geom_point(aes(color = region)) +
  geom_text(aes(label = province), check_overlap = TRUE)

ggplot2 快速入门:基础图形作法

 

 check_overlap = TRUE 省略了某些省份的名称,保证文本不会有重叠。 从图中来看,最右上角的点毫无疑问是北京。天津和上海两个城市比较特别,拥有很高的人均 GDP,家用汽车平均保有量却相对较低。对这个现象,我们可以做出许多猜想:影响汽车保有量的是否有其它更重要的因素?人均 GDP 是名义值(未经价格调整),也许这两个城市的物价水平很高,导致实际 GDP 较低。或者,这两个城市的其它交通工具较为发达、交通堵塞严重需摇号购车,家用汽车不是人们的首选出行工具…… 左上角的*和云南也十分引人注目,它们拥有较低的人均 GDP,家用汽车保有量却相对较高,我们可以猜想,这两个省份地广人稀,家用汽车是必要的出行工具…… 图形启发我们进行了这些猜想,它们不一定正确,需要我们进一步设计研究,但我们已经可以感受到数据可视化的力量。

除了 color,geom_point() 还有其它一些属性,比如点的形状(shape)、透明度(alpha)、大小(size)等。

ggplot(data = da) +
  geom_point(mapping = aes(x = GDP, y = car, shape = region))

 

ggplot2 快速入门:基础图形作法

 你可以使用 ?geom_point 命令查看帮助文档中的 Aesthetics,获取更多属性。

2.2.2 块面图

另一种增加变量的方法是块面图,我们使用 facet_wrap() 将观测值按照 region 分组,就可以看到不同地区的 car 和 GDP 之间的关系了。

ggplot(data = da) + 
  geom_point(mapping = aes(x = GDP, y = car)) + 
  facet_wrap(~ region, nrow = 2)

ggplot2 快速入门:基础图形作法

 除了 facet_wrap() 以外,ggplot2 中还有 facet_grid() 函数可以画块面图。你可以在帮助文档中看它们有什么不同。

2.3 几何对象

至今我们接触到的 ggplot2 中的几何对象有点和文本,除了这两个以外较为常用的还有线。下面我们分别来看散点图和折线图。

2.3.1 散点图

上面实验我们画的大多数都是散点图,因此无需赘述,但有种情形值得引起注意。 如果我们面临的是大样本,看看会发生什么。

# mpg 是 tidyverse 中一个内置的数据集,共 234 行,11列
ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = cty))

ggplot2 快速入门:基础图形作法

 

 数一数会发现,图中点的个数小于 234,这叫做 “overplotting” 问题,有些点被临近的点覆盖掉,而且所有点看起来分布得十分均匀。 如果我们想获得更贴近现实(数据)的散点图,可以设置 position = 'jitter'

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = cty), position = 'jitter')

ggplot2 快速入门:基础图形作法

 

2.3.2 拟合曲线

使用 geom_smooth 获得一条拟合观测值的曲线:

ggplot(data = da) +
  geom_smooth(mapping = aes(x = GDP, y = car))

ggplot2 快速入门:基础图形作法

 

在图中同时呈现散点和拟合的曲线,并且令 se = FALSE 去掉曲线的置信区间:

ggplot(data = da) +
  geom_point(mapping = aes(x = GDP, y = car)) +
  geom_smooth(mapping = aes(x = GDP, y = car), se = FALSE)

 

ggplot2 快速入门:基础图形作法

令 method = 'lm' 获得拟合的直线

ggplot(data = da) +
  geom_point(mapping = aes(x = GDP, y = car)) +
  geom_smooth(mapping = aes(x = GDP, y = car), se = FALSE, method = 'lm')

 

ggplot2 快速入门:基础图形作法

2.3.3 折线图

使用 geom_line() 画折线图:

ggplot(data = da) +
  geom_line(mapping = aes(x = GDP, y = car))

ggplot2 快速入门:基础图形作法

 

 这样的图看起来没有任何意义。事实上,在时间序列数据的可视化时使用 geom_line() 会比较合适。 economics 也是 tidyverse 的内置数据集,我们画出失业率随日期变动的折线图:

ggplot(data = economics) +
  geom_line(mapping = aes(x = date, y = unemploy/pop))

 

 

ggplot2 快速入门:基础图形作法

2.3.4 图层叠加

在前面的实验中,你已经接触了一些图层叠加的操作,比如带有拟合曲线的散点图、标注文本的散点图等。 图层叠加是 ggplot2 中一个非常重要的理念,正是它让 ggplot2 变得灵活,让我们可以不拘泥于固定的图例设置,自有地创造出想要的图形。 下面我们再来看一个例子,这个例子让点和曲线的颜色都根据 region 进行了分组:

ggplot(da, aes(GDP, car, color = region)) +
  geom_point() +
  geom_smooth(se = FALSE)

ggplot2 快速入门:基础图形作法

 

 需要说明的是,为了简化实验,我们用的是 2011 年的截面数据,因此样本量较小,分组后每组包含的样本就更少了,这样拟合出来的曲线毫无说服力(因此你会看到 There were 11 warnings 的警告信息)。在正式研究中,我们也许会采用面板数据(panel data)扩大样本容量。 为了更加熟练地掌握图层叠加操作,请尝试画出课后练习中的图形。

2.4 统计变换

无论是散点图还是折线图,我们都能在图形上看出原始数据来,统计变换则不同,它需要先进行一定的统计操作,再把结果反映在图形上。

2.4.1 柱状图

对观测值进行分类统计,我们可以用 geom_bar() 画出柱状图。柱状图只需要指定 x 坐标(离散的分类变量),另一个坐标为 count(计数)。

ggplot(da) +
  geom_bar(mapping = aes(x = region))

 

 

ggplot2 快速入门:基础图形作法

有时候我们拿到的并不是原始数据,而是已经分类计数好的数据,这时候应该怎么办呢? 假设 demo 是我们拿到的数据,通过令 stat = 'identity',可以画出和上面一样的柱状图来。

demo <- tribble(
  ~region, ~freq,
  "E", 10, 
  "M", 6, 
  "W", 12, 
  "NE", 3
)

ggplot(demo) +
  geom_bar(mapping = aes(x = region, y = freq), stat = 'identity')

2.4.2 直方图

假设我们想统计的变量不是离散的,而是一个连续变量,这时候就可以用 geom_histogram() 画直方图。

ggplot(da, aes(GDP)) +
  geom_histogram(binwidth = 0.5)

ggplot2 快速入门:基础图形作法

 

注意设置合适的 binwidth 很重要,你需要根据不同的数据尝试多个 binwidth,选择一个最合适的。 除了直方图外,我们也可以用 geom_freqpoly() 画频率折线图,它与直方图的功能基本一致。

ggplot(da, aes(GDP)) +
  geom_freqpoly(binwidth = 0.5)

 

 

ggplot2 快速入门:基础图形作法

2.4.3 箱线图

箱线图很受统计学家喜爱,因为它以尽可能简单的方式直观地反映了许多数据特征。下图展现了从数据的实际分布到箱线图的过程。 

ggplot2 快速入门:基础图形作法

 Source: Hadley Wickham, R for Data Science, 2016. 我们使用 geom_boxplot() 画箱线图:

ggplot(da, aes(region, GDP)) +
  geom_boxplot()

 

 

ggplot2 快速入门:基础图形作法

2.5 坐标系

2.5.1 坐标标签

我们可以使用 xlab()ylab() 函数为坐标轴添加标签:

ggplot(da, aes(GDP, car)) +
  geom_point() +
  xlab('Per Capita GDP') +
  ylab('Car Ownership (%)')

 

 

ggplot2 快速入门:基础图形作法

如果想去掉坐标轴标签,可使用 xlab(NULL)ylab(NULL)

ggplot(da, aes(GDP, car)) +
  geom_point() +
  xlab(NULL) +
  ylab(NULL)

 

 

ggplot2 快速入门:基础图形作法

2.5.2 坐标范围

如果我们只想看人均 GDP 在 2 至 4 之间,平均汽车保有量在 10 至 20 之间的省份,可以使用 xlim()ylim() 函数限定坐标轴范围:

ggplot(da, aes(GDP, car)) +
  geom_point() +
  xlim(2, 4) +
  ylim(10,20) +
  geom_text(aes(label = province), check_overlap = TRUE)

 

 

ggplot2 快速入门:基础图形作法

2.5.3 交换坐标和极坐标

如果我们想交换横纵坐标,可以使用 coord_flip() 函数。特别是当我们在画柱形图或箱线图,横坐标刻度标识很长时,可以交换横纵坐标,这样文字就不会挤在一起。 我们还可以使用 coord_polar() 将笛卡尔坐标系转化为极坐标系。

bar <- ggplot(da, aes(region)) +
  geom_bar(mapping = aes(fill = region), show.legend = FALSE, width = 1) +
  xlab(NULL) +
  ylab(NULL)

bar + coord_flip()
bar + coord_polar()  

 ggplot2 快速入门:基础图形作法

ggplot2 快速入门:基础图形作法

三、课后练习

请尝试画出如下图形(将代码和截图保存在实验报告中):

1. ggplot2 快速入门:基础图形作法

2. ggplot2 快速入门:基础图形作法

 

3. 

ggplot2 快速入门:基础图形作法

4. ggplot2 快速入门:基础图形作法

 

 

四、总结

本实验介绍了 ggplot2 作图的基本思想和语法模版,通过实例展示了如何使用 ggplot2 画出优雅的散点图、折线图、柱形图、直方图、箱线图等基础图形,对其中蕴含的映射理念和图层思想做了详细的讲述。

 

ggplot2 快速入门:基础图形作法ggplot2 快速入门:基础图形作法 git1314 发布了114 篇原创文章 · 获赞 103 · 访问量 27万+ 私信 关注
上一篇:Geom Color 线性渐变 类型


下一篇:ggplot2(5) 工具箱