ggplot2笔记9:绘图需要的数据整理技术
本书的最后一个部分,Part III,Data Analysis。主要包括三个章节,今天先来看第九章:
ggplot2绘图基础系列:
Data Analysis
9.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`
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
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:从索引数据翻译成笛卡尔数据
Gather
gather()
函数包含以下四个参数:
data
:需要转换的数据集key
:将从列名创建出的变量名称value
:将从每个单元创建出的变量名...
:要收集哪些变量,可以一个一个列出来,也可以使用简写形式..:..
所以我们要整理上面的ec2数据集,就要把所有变量放在列中。其中只有 month
在列中, year
和 rate
还是“笛卡尔数据形式”,所以我们要把他们转换成“索引形式”,可生成以下数据集:
注意2006-2015不是R语言中标准的变量名称(不是以字母开头)所以我们需要用单括号括起来
> gather(ec2, key = year, value = unemp, `2006`:`2015`)
# A tibble: 120 x 3
month year unemp
<dbl> <chr> <dbl>
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()
Spread
spread()
是与 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
<int> <chr> <dbl>
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
<int> <dbl> <dbl>
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
<chr> <dbl>
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
<chr> <chr> <dbl>
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
-------------------我是求关注的分界线--------------
欢迎大家跟我一起上车:
猜你喜欢
10000+:肠道细菌 人体上的生命 宝宝与猫狗 梅毒狂想曲 提DNA发Nature 实验分析谁对结果影响大 Cell微生物专刊
文献阅读 热心肠 SemanticScholar Geenmedical
16S功能预测 PICRUSt FAPROTAX Bugbase Tax4Fun
写在后面
为鼓励读者交流、快速解决科研困难,我们建立了“宏基因组”专业讨论群,目前己有国内外150+ PI,1500+ 一线科研人员加入。参与讨论,获得专业解答,欢迎分享此文至朋友圈,并扫码加主编好友带你入群,务必备注“姓名-单位-研究方向-职称/年级”。技术问题寻求帮助,首先阅读《如何优雅的提问》学习解决问题思路,仍末解决群内讨论,问题不私聊,帮助同行。
学习16S扩增子、宏基因组科研思路和分析实战,关注“宏基因组”