主要学习R语言的专题为以下几个内容:
- 数据框排序
- 表达矩阵画箱线图
- 花里胡哨的连接
需要重点掌握:
R语言里的管道符号:%>%
str_detect()
Ifelse()
apply()
先安装R包:
options("repos" = c(CRAN="http://mirrors.tuna.tsinghua.edu.cn/CRAN/"))
if(!require(tidyr))install.packages("tidyr",update = F,ask = F)
if(!require(dplyr))install.packages("dplyr",update = F,ask = F)
if(!require(stringr))install.packages('stringr',update = F,ask = F)
if(!require(tibble))install.packages('tibble',update = F,ask = F)
library(tidyr)
library(dplyr)
library(stringr)
library(tibble)
tidyverse:Hadley Wickham-《R for Data Science》
https://r4ds.had.co.nz/introduction.html
大佬研发了一套不需要写中括号,引号,$
等符号,颠覆的R语言体系,让代码变得更简单,对初学者比较友好,但是要学习原始的基础包,tidyverse当做扩展学习,基础包里有几个函数,而tidyverse为一整套的包,包里有20多个小包,可以把这些小包分别安装,或只要安装几个核心包。
《R for Data Science》的大概介绍:
readr和data.table:数据导入
ggplot2:数据可视化。
有些包不基于ggplot2,如pheatmap包画的热图比ggplot2画得要好,给pheatmap包一个矩阵就可以,而不能给ggplot2一个矩阵,要数据框。
dplyr:专门用来处理数据框。
stringr:专门用来处理字符串。
Rmarkdown:有多余的时间可以去研究,可以做笔记,导出代码运行结果等。
专题1:数据框排序
order与sort复习:只对数据框的某一列(向量)操作
sort(iris$Sepal.Length)
iris$Sepal.Length[order(iris$Sepal.Length)]
##以上的两句代码运行的结果相同。Sepal.Length为iris的一列,也是一个向量。
#order(iris$Sepal.Length)是对Sepal.Length的下标进行排序
现在要进行整个数据框的排序,对某一列排序,它所对应的关系(其它列)也跟着动。数据框一列的下标,其实就是行号。
1.1 升序(默认)
##新建数据框:
test <- iris[c(1:2,51:52,101:102),]
rownames(test) =NULL
test
# order 可以给向量排序,也可以给数据框排序
sort(test$Sepal.Length)
test$Sepal.Length[order(test$Sepal.Length)]
##数据框一列的下标,其实就是行号,order(test$Sepal.Length)是下标打乱得到的东西,其实就是行号打乱得到的东西
##数据框升序
test[order(test$Sepal.Length),]
##test[行,列],在数据框行到的位置放行号,实现对整个数据框的排序,也就是把某一列的下标(行号)放在数据框行的位置,实现整个数据框的排序。order默认参数为升序
#整数据框按照第一列(Sepal.Length)大小来排序,对应的整行都动
##order()既可以对本列,又可以对其它的进行列排序,还可以给整个数据框使用
1.2 降序
test[order(test$Sepal.Length,decreasing = T),]
##decreasing = T,降序,
数据框整体升序和降序,对列操作,按行号排序,整体一起排,练习,不对第一列,对其它列操作试试,数据框[行,列],只操作数据框[order(...),]
1.3 tidyverse让代码更易读
arrange()排序
- 数据框升序
arrange(test,Sepal.Length),注意不加引号。
arrange(数据框名,第一列),实现整个数据框的每一行按第一列从小到大排列起来
library(dplyr)
arrange(test, Sepal.Length)
#该函数唯一的写法,从大到小排列,没有decreasing=T
- 数据框降序
使用函数:desc(),把要降序的列写在括号里,desc()函数不能单独用,它只能和dplyr里的一些函数结合使用
arrange(test, desc(Sepal.Length))
还有强大的功能:按照多列来排序
- 双排序
先按照A列排,如果A列相同,按照B列排
arrange(test, desc(Sepal.Width),Sepal.Length)
##desc(Sepal.Width)是A列为降序,Sepal.Length是B列没有套上desc()是升序。谁在前面优先排序,Sepal.Width在前面优先排序,如果Sepal.Width没有重复值,Sepal.Length写和没写,没有区别。
##先按Sepal.Width先排,该列有两个重复的值3.2,再对重复值对应的Sepal.Length列的值进行排序,谁小谁在前
1.4 补充3个出自dplyr的函数
mutate():数据框新增列
select():筛选数据框的列
filter():筛选数据框的行
1.4.1 mutate:新增列
###使用mutate给数据框新增一列
mutate(test,new=Sepal.Width*Sepal.Length)
##新增的一列的名字为new,内容为Sepal.Width与Sepal.Length的乘积:*
##在R语言里,没有赋值,就没有变化,还是原来的test
test=mutate(test,new=Sepal.Width*Sepal.Length)
###原来给数据框test新加一列的用法:
test$新的列名<-c():
#基础包里的数据框新增列,
test$new=test$Sepal.Width*Sepal.Length
##还是tidyverse的方法好用:tidyverse里的mutate函数会减少$符号的使用
1.4.2 select(),filter()筛选数据框列,行
select()是筛选数据框的列:select(数据框名,列名),注意不用$
,引号之类的。
library(dplyr)
select(iris,Species)
#筛选出数据框的Species,只显示一列,只对某一列或是几列操作。
filter()是筛选数据框的行:filter(数据框名,逻辑值),x==y,x!=y,x%in%y,x>y等
library(dplyr)
filter(iris,Sepal.Length>6)
##筛选出Sepal.Length大于6,把其它对应关系也显示出来,是对数据框操作。
用中括号[行,列]
可以筛选数据框的行与列。
优秀的管道符号%>%
把前一句的输出作为后一句的输入。
##select(),filter()筛选数据框列,行
x1=filter(iris,Sepal.Width>3)
##filter()筛选行,筛选第二列数字大于3的行,把行提取出来还是一个表格。
x2=select(x1,c("Sepal.Width","Sepal.Length"))
##在x1的结果上筛选列,筛选第一列和第二列
x3=arrange(x2,Sepal.Length)
##排序
##以上3句代码完成的作用,从iris出发,筛选行,筛选列,排序之后得到一个新数据,并赋值给x3.
##从iris得到x3,那么x1,x2是中间产物,并不想用。
##优秀的管道符号是用来克服以上出现的x1,x2等多余的东西,让代码变得丝滑些。
##使用管道符%>%的前提是加载tidyverse里的任何一个R包,管道符号会被调出来。
x=iris %>%
filter(Sepal.Width>3)%>%
select(c("Sepal.Width","Sepal.Length"))%>%
arrange(Sepal.Length)
##从iris出发,经历筛选行,筛选列,排序得到一个新数据并且赋了值x。
##使用管道符号,没有生成中间变量,管道符号可以理解为向后传递。
##对比分析:
##filter(iris,Sepal.Width>3)与iris %>% filter(Sepal.Width>3)的意思一样
##x2=select(x1,c("Sepal.Width","Sepal.Length")) 与iris %>% filter(Sepal.Width>3)%>%select(c("Sepal.Width","Sepal.Length"))的意思一样
专题2:表达矩阵画箱线图
这里的箱线图,是指用ggplot画出来的。
一个矩阵是不可以作为ggplot画图的输入数据。
ggplot画图潜在的规律,输入数据是数据框不能是矩阵,aes(x=数值,y=数值)。
需要进行数据整理,与iris示例数据一样,怎么处理数据:
2.1 转置t
表达矩阵不能直接画图,首先进行调整,如下面的表达矩阵需要整理成数据框,gene在一列,所有的count在一列上,分组在一列上。
###新建表达矩阵
set.seed(10086)
##set.seed是保证运行生成的随机数据一样。set.seed是设置生成随机数一样
exp = matrix(rnorm(18),ncol = 6)
exp = round(exp,2)
##round函数是取小数点后几位小数,这里保持两位小数
rownames(exp) = paste0("gene",1:3)
##加行名
colnames(exp) = paste0("test",1:6)
##加列名
##画ggplot图的时候,横坐标是基因,纵坐标是count具体的数字。
exp[,1:3] = exp[,1:3]+1
##+1所有的数值加1
##前3列+1,为了让两组数据有差别,前3列为一个组,后三列为一个组,看看分组的差异,所以前3列加1
exp
转置之后,行变列,列变行,之后转换为数据框。
library(tidyr)
library(tibble)
library(dplyr)
dat = t(exp) %>% ###转置后的exp此时还是矩阵,作图都用数据框
as.data.frame() %>% ##把行名变为数据框的一列
rownames_to_column() %>% ##把原来的行名转换成列名
mutate(group = rep(c("control","treat"),each = 3))##mutate是新增一列,group 为分组,给数据框新增一列。
ggplot2语法不认行名,所以把test1..test6变为一列。
把原来的行名变成第一列
一个样本在多个基因的表达量,但是不能作图
2.2 宽变长
要把gene1..gene3变为一列,把具体的数值作为一列,test1..test6各自重复了3次。(6行3列,变成18行3列)。好处是,有横纵坐标,可传递给ggplot2,进行作图了。
pdat = dat%>%
pivot_longer(cols = starts_with("gene"),###宽变长的函数pivot_longer()三个参数,cols=合并的列
names_to = "gene",
values_to = "count")##新生的数据框新生的两个列名
## pivot_longer()为宽变长的函数,比mute()函数好用。
##宽变长需要三个参数:cols=要把那几列宽变长,就是说哪几列的列名成为新的一列,内容成为新的一列; names_to = 那一列的名字叫什么,叫gene。values_to =那些数字组成的一列且名字叫什么,为count。总结,把几列变为一列且起名字,把那几列对应的数字组成一列且取名字。
##作为初学者,不需要知道rownames_to_column()和 pivot_longer()出自哪个包。
宽边长的理解:原来是3列,现在变成1列。长变宽(同样可以实现),但是很少用。
2.3 画图
library(ggplot2)
p = ggplot(pdat,aes(gene,count))+
geom_boxplot(aes(fill = group))+
geom_jitter()+
theme_bw()
##画图,x=gene,y=count,把x=和y=都省略,fill = group,映射,theme_bw()去除背景。
2.4 图分面
p
p + facet_wrap(~gene,scales = "free")###
##facet_wrap分面函数,把gene1,gene2,gene3各自分到一张图里。
专题3:花里花哨的连接
inner_join():交集 left_join:左连接 right_join:右连接 full_join:全连接 semi_join:半连接 anti_join:反连接
test1 <- data.frame(name = c('jimmy','nicker','Damon','Sophie'),
blood_type = c("A","B","O","AB"))
test1
test2 <- data.frame(name = c('Damon','jimmy','nicker','tony'),
group = c("group1","group1","group2","group2"),
vision = c(4.2,4.3,4.9,4.5))
test2
library(dplyr)
##连接函数需要加载的dplyr包。
3.1 inner_join:交集
合并在一起,共同的留下,不共同的都去掉。
library(dplyr)
inner_join(test1,test2,by="name")
去掉Sophie 和 tony
注意:
以下各种连接中,代码里两个test的前后顺序,写在前的为左边,写在后面的为右边:
3.2 left_join:左连接
以左边的表test1为准,连接完之后,保留左边表的所有信息,右边表的行数和左边表的行数一样多,tony在左边表没有就直接被踢掉,Sophie在左边表有,但是在右边表没有对应的信息,存在却未知,以NA值填充。
library(dplyr)
left_join(test1,test2,by="name")
3.3 right_join:右连接
以右边的表为标准,右边有的人都留下,左边表没有的就去掉,在左边的表没有值,以NA值填充。
library(dplyr)
right_join(test1,test2,by="name")
##其实与left_join(test2,test1,by="name")一样,左右连接这两个函数用一个就可以,只是把两个表的顺序调一下,以后根据自己的分析来定顺序
左右连接这两个函数用一个就可以,只是把两个表的顺序调一下,以后根据自己的分析来定表格顺序。
3.4 full_join:全连接
取全集,但凡两个表有的信息都保留下来,没有的信息,填上NA。
library(dplyr)
full_join(test1,test2,by="name")
取交集和全集的比较,取交集没有的就掉,不会有NA,取全集时,都留下,没有对应信息的用NA填充。交集没有NA,全集有NA。
以下semi_join和anti_join基本用不上:
3.5 semi_join:半连接
应用全景不广泛。虽然叫连接,其实并没有连接。意思是,把左边的表取子集,取在右边表里存在的子集,有的人才被留下,没有的去掉,其实就是%in%。
library(dplyr)
semi_join(test1,test2,by="name")
3.6 anti_join:反连接
意思是,把左边的表取子集,取在右边表里没有的子集,没有的人才被留下,有的去掉。
library(dplyr)
anti_join(test1,test2,by="name")
以上的几个连接函数相当于一个merge函数,merge函数实现交集连接,全连接等靠参数来实现的,找参数时比较麻烦。
说明
以上内容是听生信技能树小洁老师的R语言线上课,根据自己的理解记录下来,小洁老师授课非常细心,对不同水平的同学都照顾到,并且补充很多技巧,如数据框多种排序方法,还有一些注意事项,如ggplot输入数据是数据框,如果是矩阵如何处理等。