本书的最后一个部分,Part III,Data Analysis。主要包括三个章节,今天先来看第九章:
ggplot2绘图基础系列:
Data Analysis9.1 简介在前面的学习中,我们使用的模拟数据集都是已经整理好的数据框,可以直接使用。但通常实际数据并不会这么理想,需要通过一定的整理好变换才能用于作图 所以这个部分的目标就是把ggplot2和其他工具结合起来,用于完整的数据分析。 首先学习整理数据的原则,了解 dplyr 以及 tidyr 等可以用于整理凌乱数据集的R包 大多数可视化需要进行数据转换,可能要在现有变量的基础上,创造新的变量;或者执行简单的聚合。这些在第十章中有详细说明。 使用R建模的过程中,如何将模型转换成整洁的数据集,这些在第十一章中可以稍作了解。
在本章中,作者用了两个事例来介绍怎样整理数据。 9.2 整理数据(Tidy Data)整理数据的原则很简单:用一致的方式存储数据。(storing your data in a consistent way) 所以整理数据的目的是为了创造一个数据框的统计学结构(变量和观测数据)和物理结构(列和行)之间的映射。 其中, 变量放在列中(Variables go in columns) 观测数据放在行中(Observations go in rows) 我们需要先安装几个R包, dplyr 、 tidyr 、 magrittr 。 下面加载一个需要整理的关于经济学失业率 economics 数据集的子集 ec2 ,作为例子: > ec2
# A tibble: 12 x 11
month `2006` `2007` `2008` `2009` `2010` `2011` `2012` `2013` `2014` `2015`
1 1.00 8.60 8.30 9.00 10.7 20.0 21.6 21.0 16.2 15.9 13.4
2 2.00 9.10 8.50 8.70 11.7 19.9 21.1 19.8 17.5 16.2 13.1
3 3.00 8.70 9.10 8.70 12.3 20.4 21.5 19.2 17.7 15.9 12.2
4 4.00 8.40 8.60 9.40 13.1 22.1 20.9 19.1 17.1 15.6 11.7
5 5.00 8.50 8.20 7.90 14.2 22.3 21.6 19.9 17.0 14.5 NA
6 6.00 7.30 7.70 9.00 17.2 25.2 22.3 20.1 16.6 13.2 NA
7 7.00 8.00 8.70 9.70 16.0 22.3 22.0 17.5 16.3 13.5 NA
8 8.00 8.40 8.80 9.70 16.3 21.0 22.4 18.5 16.8 13.3 NA
9 9.00 8.00 8.70 10.2 17.8 20.3 22.0 18.8 16.5 13.3 NA
10 10.0 7.90 8.40 10.4 18.9 21.2 20.5 19.7 16.1 13.5 NA
11 11.0 8.30 8.60 9.80 19.8 21.0 20.9 18.5 17.0 12.8 NA
12 12.0 7.50 8.40 10.5 20.1 21.9 20.5 17.6 17.0 12.6 NA
PS. 这个 ec2 不是ggplot2中自带的数据集,无法直接加载出来,通过万能的Google找到了加载ec2的方法,在此之前我们需要再多安装一个用于时间数据处理的r包 lubridate :
library(lubridate)
library(magrittr)
library(dplyr)
library(tidyr)
ec2 <>
ggplot2::economics %>%
tbl_df() %>%
transmute(year = year(date), month = month(date), rate = uempmed) %>%
filter(year > 2005) %>%
spread(year, rate)
ec2
这个数据集的混乱之处在于,变量 year 、 month 分别是列名和行名,观测结果在每个小单元里。 然后我们需要用两对工具: Spread & gather
Separate & unite
9.3 Spread and Gather先看一下这俩表格有啥区别: > indexed <> data.frame(
+ x = c('a', 'b', 'c', 'd', 'c'),
+ y = c('A', 'D', 'A', 'C', 'B'),
+ z = c(1, 5, 4, 9, 10)
+ ) %>% arrange(x, y)
> matrix <> indexed %>% spread(y, z)
>
> knitr::kable(indexed)
|x |y | z|
|:--|:--|--:|
|a |A | 1|
|b |D | 5|
|c |A | 4|
|c |B | 10|
|d |C | 9|
> knitr::kable(matrix)
|x | A| B| C| D|
|:--|--:|--:|--:|--:|
|a | 1| NA| NA| NA|
|b | NA| NA| NA| 5|
|c | 4| 10| NA| NA|
|d | NA| NA| 9| NA|
(这里面用到了一个表格生成函数 knitr::kable() ) 这两种表格分别称为“索引数据”(通过变量值查找数据)和“笛卡尔数据”(通过查看行和列的交集来找到一个值) tidyr 包包含两个函数 gather() 、 spread() 可以用来执行以下操作:
gathering:从笛卡尔数据翻译成索引数据 spreading:从索引数据翻译成笛卡尔数据 Gathergather() 函数包含以下四个参数:
所以我们要整理上面的ec2数据集,就要把所有变量放在列中。其中只有 month 在列中, year 和 rate 还是“笛卡尔数据形式”,所以我们要把他们转换成“索引形式”,可生成以下数据集: 注意2006-2015不是R语言中标准的变量名称(不是以字母开头)所以我们需要用单括号括起来
> gather(ec2, key = year, value = unemp, `2006`:`2015`)
# A tibble: 120 x 3
month year unemp
1 1.00 2006 8.60
2 2.00 2006 9.10
3 3.00 2006 8.70
4 4.00 2006 8.40
5 5.00 2006 8.50
6 6.00 2006 7.30
7 7.00 2006 8.00
8 8.00 2006 8.40
9 9.00 2006 8.00
10 10.0 2006 7.90
# ... with 110 more rows
另一种方法(gather除了month之外的数据): gather(ec2, key = year, value = unemp, -month)
增加两种参数,可以更加严谨: economics_2 <> gather(ec2, year, rate, `2006`:`2015`,
convert = TRUE, na.rm = TRUE)
economics_2
其中 convert=TRUE 自动将年份从字符串转换为数字
na.rm=TRUE 自动删除没有数据的月份
当数据处于这种形式时,比较容易可视化: library(ggplot2)
ggplot(economics_2, aes(month, rate, group = year)) +
geom_line(aes(colour = year), size = 1)
ggplot(economics_2, aes(year + (month - 1) / 12, rate)) +
geom_line()
Spreadspread() 是与 gather() 相对应的另一种函数。
如下例,创建weather数据集,包含三个变量,分别是 day ,rain 和 temp 。 weather <> dplyr::data_frame(
day = rep(1:3, 2),
obs = rep(c('temp', 'rain'), each = 3),
val = c(c(23, 22, 20), c(0, 0, 5))
)
输出如下“索引模式” > weather
# A tibble: 6 x 3
day obs val
1 1 temp 23.0
2 2 temp 22.0
3 3 temp 20.0
4 1 rain 0
5 2 rain 0
6 3 rain 5.00
通过 spread() 可以将繁琐的索引数据转变成简洁的笛卡尔数据形式。 参数和 gather() 类似,如下例: > spread(weather, key = obs, value = val)
# A tibble: 3 x 3
day rain temp
1 1 0 23.0
2 2 0 22.0
3 3 5.00 20.0
9.4 Separate and Unite当多个变量被放在了一列中,或者很多列中有一个变量时,我们使用 separate() 和 unite() 函数。 如下例: trt <> dplyr::data_frame(
var = paste0(rep(c('beg', 'end'), each = 3), '_', rep(c('a', 'b', 'c'))),
val = c(1, 4, 2, 10, 5, 11)
)
数据集中包含三个变量(time, treatment 和 value),但是time和treatment混在了同一列中: > trt
# A tibble: 6 x 2
var val
1 beg_a 1.00
2 beg_b 4.00
3 beg_c 2.00
4 end_a 10.0
5 end_b 5.00
6 end_c 11.0
separate() 函数包括:
data :要修改的数据框
col :要分隔的列
into :给新变量命名的字符向量
sep :描述如何分开这些变量
在上面的例子中: > separate(trt, var, c('time', 'treatment'), '_')
# A tibble: 6 x 3
time treatment val
1 beg a 1.00
2 beg b 4.00
3 beg c 2.00
4 end a 10.0
5 end b 5.00
6 end c 11.0
unite() 是 separate() 的反函数,但并不常用。
参考资料: Hadley Wickham(2016). ggplot2. Springer International Publishing. doi: 10.1007/978-3-319-24277-4 《R语言应用系列丛书·ggplot2:数据分析与图形艺术》 https://github.com/hadley/ggplot2-book/blob/master/tidy-data.rmd
-------------------我是求关注的分界线-------------- 欢迎大家跟我一起上车:
|