https://github.com/hbctraining/Intro-to-R
Tidyverse套件旨在共同努力,使通用数据科学的操作更加人性化。这些包具有数据规整,清洗,读/写,解析和可视化等功能。免费电子书R for Data Science详细描述了可用工具的实例以及它们如何协同工作。我们将探讨使用这些软件包的基本语法,以及使用'dplyr'软件包进行数据规整的特定函数,使用'tidyr'软件包清洗数据以及使用'ggplot2'软件包进行数据可视化。
这些包都使用相同的代码风格,即所有函数名和参数的格式均为snake_case
。详见http://style.tidyverse.org/。
1.下载示例数据
我们将引入一个包含差异表达式分析结果的新文件作为示例数据。下载地址:https://github.com/hbctraining/Training-modules/raw/master/Visualization_in_R/data/Mov10oe_DE_results.csv 将其下载到之前的data
文件夹中(选择Save Link As
或Download Linked File As
)。下载成功后可在RStudio“文件”选项卡的data
文件夹中看到它。
2.将示例数据读取进R
读取刚下载的新文件并加载tidyverse
:
res_tableOE <- read.csv(file = "data/Mov10oe_DE_results.csv", row.names = 1)
library(tidyverse)
Tidyverse基础知识
Tidyverse软件包套件向用户介绍了一组数据结构,函数和操作符,以便更直观地处理数据,但与R base的工作方式略有不同。管道和tibble是接下来要关注的两个重要的新概念。
(1) 管道
长串的R命令让人想退缩。此外,尝试理解具有许多嵌套函数的代码可能会令人困惑。
为了使R代码更具人性化,Tidyverse工具使用%>%
从magrittr
包中获取的管道,现在dplyr
是Tidyverse自动安装的软件包的一部分。管道允许将前一个命令的输出用作另一个命令的输入,而不是使用嵌套函数。
注意:写入管道的快捷方式是<kbd style="box-sizing: border-box; font-family: monospace, monospace; font-size: 1em;">shift</kbd>+ <kbd style="box-sizing: border-box; font-family: monospace, monospace; font-size: 1em;">command</kbd>+<kbd style="box-sizing: border-box; font-family: monospace, monospace; font-size: 1em;">M</kbd>
使用管道运行多个命令的示例:
## A single command
sqrt(83)
## Base R method of running more than one command
round(sqrt(83), digit = 2)
## Running more than one command with piping
sqrt(83) %>% round(digit = 2)
管道代表了一种更简单的编写和解密R代码的方式,因此我们将在可能的情况下利用它,因为我们将完成剩下的课程。
练习
replicate
从metadata
数据框中提取列(使用$
表示法)并将值保存到名为的向量中rep_number
。-
使用pipe(
%>%
)在一行中执行两个步骤:- 转
rep_number
进一个因素。 - 使用该
head()
函数返回rep_number
因子的前六个值。
- 转
(2)Tibbles
所述的核心组件tidyverse是tibble。Tibbles是标准的现代返工data.frame
,有一些内部改进使代码更可靠。它们是数据框,但不遵循所有相同的规则。例如,tibbles可以包含列名的数字/符号,这在基数R中通常不允许。
重要提示:tidyverse对行名称非常了解。这些软件包坚持要求所有列数据(例如data.frame
)被平等对待,并且rownames
应该弃用特殊的列名称。Tibble提供了简单的实用程序函数来处理rownames:rownames_to_column()
和column_to_rownames()
。可以找到更多有关处理元组中行名的帮助:
help("rownames", "tibble")
可以使用tibble()
函数直接创建Tibbles,也可以使用数据帧转换为数据帧as_tibble(name_of_df)
。
注意:该函数
as_tibble()
将忽略行名称,因此如果需要表示行名称的列,rownames_to_column(name_of_df)
则应在将data.frame转换为tibble之前运行该函数。此外,as_tibble()
默认情况下不会将字符向量强制转换为因子。
练习
df_tibble
使用tibble()
函数组合向量species
和创建一个tibbleglengths
。注意:您的glengths
向量可能与长度不同species
,因此您需要使用适当大小的子集。将
metadata
数据框更改为名为的tibblemeta_tibble
。使用该rownames_to_column()
函数保留与使用%>%
和as_tibble()
函数结合的rownames 。
tibble有个很好的特点,当一个变量打印到屏幕时,默认情况下它只会显示前10行和适合屏幕的列。这样很方便,不必用head()
查看数据集了。
# Default printing of data.frame
rpkm_data
# Default printing of tibble
rpkm_data %>%
rownames_to_column() %>%
as_tibble()
注意:如果需要查看更多行列,
print()
函数可以更改显示的行数或列数。# Printing of tibble with print() - change defaults rpkm_data %>% rownames_to_column() %>% as_tibble() %>% print(n = 20, width = Inf)
Tidyverse tools
虽然Tidyverse套件中的所有工具都值得进行更深入的探索,但本课程仅研究我们将最常用于数据规整和清洗的工具。
注意:大量的tidyverse函数将同时使用tibbles和dataframes,输出的数据结构将与输入相同。但是,有些函数会返回一个tibble(没有行名),无论是否提供了tibble或dataframe。
Tidyverse之Dplyr
tidyverse中最有用的工具是dplyr。它用于数据规整,堪比瑞士军刀。dplyr有许多方便的函数,非常建议将它用于数据分析:
-
select()
提取列并返回一个tibble。 -
arrange()
更改行的顺序。 -
filter()
根据其值选择行。 -
mutate()
添加作为现有变量函数的新变量。 -
rename()
轻松更改列的名称 -
summarise()
将多个值减少到单个摘要。 -
pull()
提取单个列作为向量。 -
_join()
的两个数据帧合并到一起的函数组,包括(inner_join()
,left_join()
,right_join()
,和full_join()
)。
注意:dplyr在2017年进行了大规模修订,将版本从0.5切换到0.7。如果在线查阅其他dplyr教程,请注意2017年之前的资料已过时。尤其是用dplyr编写函数的部分(请参阅下面的注释部分)。
select()
要从一个tibble中提取列,用select()
函数。
# Convert the res_tableOE data frame to a tibble
res_tableOE <- res_tableOE %>%
rownames_to_column(var="gene") %>%
as_tibble()
# extract selected columns from res_tableOE
res_tableOE %>%
select(gene, baseMean, log2FoldChange, padj)
相反,可以使用否定选择删除不需要的列。
res_tableOE %>%
select(-c(lfcSE, stat, pvalue))
## # A tibble: 23,368 x 4
## gene baseMean log2FoldChange padj
## <chr> <dbl> <dbl> <dbl>
## 1 1/2-SBSRNA4 45.6520399 0.266586547 2.708964e-01
## 2 A1BG 61.0931017 0.208057615 3.638671e-01
## 3 A1BG-AS1 175.6658069 -0.051825739 7.837586e-01
## 4 A1CF 0.2376919 0.012557390 NA
## 5 A2LD1 89.6179845 0.343006364 7.652553e-02
## 6 A2M 5.8600841 -0.270449534 2.318666e-01
## 7 A2ML1 2.4240553 0.236041349 NA
## 8 A2MP1 1.3203237 0.079525469 NA
## 9 A4GALT 64.5409534 0.795049160 2.875565e-05
## 10 A4GNT 0.1912781 0.009458374 NA
## # ... with 23,358 more rows
将这个tibble保存为一个名为sub_res
的新变量:
sub_res <- res_tableOE %>%
select(-c(lfcSE, stat, pvalue))
arrange()
请注意,现在行是按symbol排序。用arrange()
按照adjusted P value进行排序。
arrange(sub_res, padj)
## # A tibble: 23,368 x 4
## gene baseMean log2FoldChange padj
## <chr> <dbl> <dbl> <dbl>
## 1 MOV10 21681.7998 4.7695983 0.000000e+00
## 2 H1F0 7881.0811 1.5250811 2.007733e-162
## 3 HSPA6 168.2522 4.4993734 1.969313e-134
## 4 HIST1H1C 1741.3830 1.4868361 5.116720e-101
## 5 TXNIP 5133.7486 1.3868320 4.882246e-90
## 6 NEAT1 21973.7061 0.9087853 2.269464e-83
## 7 KLF10 1694.2109 1.2093969 9.257431e-78
## 8 INSIG1 11872.5106 1.2260848 8.853278e-70
## 9 NR1D1 969.9119 1.5236259 1.376753e-64
## 10 WDFY1 1422.7361 1.0629160 1.298076e-61
## # ... with 23,358 more rows
filter()
只保留表达的基因(baseMean
高于0),adjusted P value小于0.01。可以filter()
一个命令中放入多个条件筛选。
sub_res %>%
filter(baseMean > 0 & padj < 0.01)
## # A tibble: 4,959 x 4
## gene baseMean log2FoldChange padj
## <chr> <dbl> <dbl> <dbl>
## 1 A4GALT 64.5 0.798 2.40e- 5
## 2 AAGAB 2614\. -0.390 1.68e-11
## 3 AAMP 3157\. -0.380 9.11e-13
## 4 AARS 3690\. 0.167 2.10e- 3
## 5 AARS2 2255\. -0.204 3.77e- 4
## 6 AASDHPPT 3561\. -0.293 3.79e- 7
## 7 AASS 1018\. 0.347 7.94e- 5
## 8 AATF 2613\. -0.290 1.97e- 7
## 9 ABAT 384\. 0.384 1.99e- 4
## 10 ABCA1 108\. 0.833 4.19e- 7
## # ... with 4,949 more rows
mutate()
mutate()
使您可以从现有列创建新列。让我们为每个基因生成log10的baseMeans计算。
sub_res %>%
mutate(log10BaseMean = log10(baseMean)) %>%
select(gene, baseMean, log10BaseMean)
## # A tibble: 23,368 x 3
## gene baseMean log10BaseMean
## <chr> <dbl> <dbl>
## 1 1/2-SBSRNA4 45.7 1.66
## 2 A1BG 61.1 1.79
## 3 A1BG-AS1 176\. 2.24
## 4 A1CF 0.238 -0.624
## 5 A2LD1 89.6 1.95
## 6 A2M 5.86 0.768
## 7 A2ML1 2.42 0.385
## 8 A2MP1 1.32 0.121
## 9 A4GALT 64.5 1.81
## 10 A4GNT 0.191 -0.718
## # ... with 23,358 more rows
rename()
快速重命名现有列rename()
。语法是new_name
= old_name
。
sub_res %>%
rename(symbol = gene)
## # A tibble: 23,368 x 4
## symbol baseMean log2FoldChange padj
## <chr> <dbl> <dbl> <dbl>
## 1 1/2-SBSRNA4 45.7 0.268 0.264
## 2 A1BG 61.1 0.209 0.357
## 3 A1BG-AS1 176\. -0.0519 0.781
## 4 A1CF 0.238 0.0130 NA
## 5 A2LD1 89.6 0.345 0.0722
## 6 A2M 5.86 -0.274 0.226
## 7 A2ML1 2.42 0.240 NA
## 8 A2MP1 1.32 0.0811 NA
## 9 A4GALT 64.5 0.798 0.0000240
## 10 A4GNT 0.191 0.00952 NA
## # ... with 23,358 more rows
pull()
在最近的dplyr 0.7更新中,pull()
添加了作为向量访问列数据的快速方法。这在与管道操作符连用非常方便。
# Extract first 10 values from the gene column
pull(sub_res, gene) %>% head()
_join()
Dplyr具有一组强大的连接操作,它们基于两个数据框中存在的变量或变量集将一对数据框连接在一起,这些变量或变量集唯一地标识所有观察。这些变量称为键。
inner_join
:只有两个数据集中存在键的行将连接在一起。left_join
:保留第一个数据框中的所有行,连接第二个数据框中具有键的行。right_join
:保留第二个数据框中的所有行,连接第一个数据框中具有键的行。full_join
:保留两个数据集中的所有行,没有匹配键的行产生NA值。
为了练习连接功能,创建如下示例数据:
描述:对于一个研究项目,我们询问健康志愿者和癌症患者关于他们的饮食和锻炼的问题。我们还为每个人收集了血液工作,每个人都获得了一个独特的身份证。创建数据框
behavior
和blood
,复制/粘贴以下代码:-
数据:
# Creating behavior dataframe ID <- c(546, 983, 042, 952, 853, 061) diet <- c("veg", "pes", "omni", "omni", "omni", "omni") exercise <- c("high", "low", "low", "low", "med", "high") behavior <- data.frame(ID, diet, exercise) # Creating blood dataframe ID <- c(983, 952, 704, 555, 853, 061, 042, 237, 145, 581, 249, 467, 841, 546) blood_levels <- c(43543, 465, 4634, 94568, 134, 347, 2345, 5439, 850, 6840, 5483, 66452, 54371, 1347) blood <- data.frame(ID, blood_levels)
并非所有血液ID都有相关的behavior信息。使用_join
函数族,练习加入连接数据框的不同选项。
要仅连接两个数据框中都有的ID,可以使用inner_join()
函数:
# Inner join
inner_join(blood, behavior)
或者,如果想要返回所有血液ID,但只包括匹配的行为ID,我们可以使用以下left_join()
功能:
# Left join
left_join(blood, behavior)
使用 right_join()
也可以做同样的事,所有行为ID和匹配的血液ID:
# Right join
right_join(blood, behavior)
最后,无论是否存在匹配的键(ID),都可以两个数据框出现的所有ID:
# Full join
full_join(blood, behavior)
注意:如果两个数据框中的名称不具有相同的列名,则需要包含
by
参数。例如:inner_join(df1, df2, by = c("df1_colname" = "df2_colname"))
Tidyverse 之Tidyr
Tidyr的目的是拥有组织良好或整洁的数据,Tidyverse将tidydata其定义为:
- 每个变量作为一列
- 每个观测作为一行
- 每个值占一个单元格
Tidyr有两个主要函数,gather()
和spread()
。这些函数允许在长数据格式和宽数据格式之间进行转换。下游分析决定所需的数据格式。
gather()
该gather()
函数将宽数据格式更改为长数据格式。当使用'ggplot2'将所有值绘制到单个列中时,此函数特别有用。
要使用此函数,需要提供原数据框中需要聚合的多个列名。然后使用key
参数提供原数据框列名聚成的新列的名称,使用value
参数提供所有值聚合成的的列的名称。
rpkm_data_tb <- rpkm_data %>%
rownames_to_column() %>%
as_tibble()
gathered <- rpkm_data_tb %>%
gather(colnames(rpkm_data_tb)[2:13],
key = "samplename",
value = "rpkm")
spread()
spread()
函数与gather()
函数相反。key
列的类别将成为单独的新列,value
列中的值将根据关联的key
列进行拆分。
gathered %>%
spread(key = "samplename",
value = "rpkm")
Tidyverse之Stringr
Stringr是一个处理字符序列或字符串的强大工具。stringr中有许多函数可用于处理字符串,但我们会介绍一些最有用的函数:
-
str_c()
将字符串连接在一起 -
str_split()
通过指定分隔符来拆分字符串 -
str_sub()
从特定位置的字符串中提取字符 -
str_replace()
用另一个字符串替换现有字符串 -
str_to_()
组功能改变了的字符串的情况下的功能,包括str_to_upper()
,str_to_lower()
和str_to_title()
-
str_detect()
标识向量中的每个元素中是否存在模式 -
str_subset()
仅返回与模式匹配的元素
除了其他字符串函数之外,为了帮助使用这些函数,还有一个方便的字符串备忘单。
str_c()
str_c()
函数将值与指定的分隔符连接在一起。collapse
参数指定是否将多个对象合并为单个字符串。
metadata <- metadata %>%
mutate(sample = str_c(genotype, celltype, replicate, sep = "_"))
str_split()
与str_c()
相反,str_split()
将基于指定的分隔符分隔值。
metadata %>%
pull(sample) %>%
str_split("_")
str_sub()
为了从字符串中提取字符,str_sub()
函数可按照位置提取的字符串中:
metadata %>%
pull(sample) %>%
str_sub(start = 1, end = 8)
要用另一个字符串替换现有字符串,使用str_replace()
函数:
str_replace()
metadata %>%
pull(celltype) %>%
str_replace("typeA", "typeP")
默认情况下,str_replace()
只会替换每个元素/组件中的第一个匹配。如果你想替换所有匹配,那么就用str_replace_all()
函数。
str_to_()
在数据整理过程中,需要确保列的所有值都具有相同的大小写,因为R区分大小写。使用str_to_
函数族,包括str_to_upper()
,str_to_lower()
和str_to_title()
,可以很简单的修改任何值的大小写。
metadata %>%
pull(genotype) %>%
str_to_upper()
metadata %>%
pull(genotype) %>%
str_to_lower()
metadata %>%
pull(genotype) %>%
str_to_title()
最后两个函数,str_detect()
和str_subset()
需要一个模式来匹配。通常在字符串中指定模式时,使用正则表达式(regexps)来描述。使用正则表达式时,有一些有用的特殊字符,有关这些的详细信息可以在R for Data Science一书和Duke的材料(http://www2.stat.duke.edu/~cr173/Sta523_Fa16/regex.html)中找到,我们在这里列出了一些常用字符:
-
"."
:匹配每个字符(如果想匹配.
字符,就需要使用\\.
来转换) -
"^characters"
:匹配字符串的开头 -
"characters$"
:匹配字符串的结尾 -
"[characters]"
:匹配[]内的任何字符 -
"[ ^characters]"
:匹配不在[]内的任何字符 -
"[A-z0-9]"
:匹配任何字母或数字 -
"*"
:匹配零次或多次
str_detect()
str_detect()
函数标识向量的每个元素中是否存在模式。此函数返回一个逻辑值,表示每个元素是否与模式匹配。
idx <- str_detect(metadata$sample, "typeA_1")
# Allows for subsetting dataframes using the logical operators
metadata[idx, ]
str_subset()
要仅返回与模式匹配的值,用str_subset()
函数:
metadata %>%
pull(sample) %>%
str_subset("typeA_1")
编程说明
在处理过程中,tidyverse包用rlang在base R语言上构建,这是对函数如何处理变量名和评估参数的全盘重做。这是通过tidyeval
框架实现的,该框架使用tidy evaluation
与命令操作交互。这超出了本课程的范围,但在Programming with dplyr(http://dplyr.tidyverse.org/articles/programming.html)中有详细解释,可以了解这些新工具与基础base R的表现有何不同。
其他资源
- R for Data Science(http://r4ds.had.co.nz/)
- teach the tidyverse(http://varianceexplained.org/r/teach-tidyverse/)
- tidy style guide(http://style.tidyverse.org/)
微信公众号生信星球同步更新我的文章,欢迎大家扫码关注!
我们有为生信初学者准备的学习小组,点击查看◀️
想要参加我的线上线下课程,也可加好友咨询🔼
如果需要提问,请先看生信星球答疑公告