美文网首页
R语言_数据框排序与数据框连接

R语言_数据框排序与数据框连接

作者: Ashu | 来源:发表于2022-05-25 22:06 被阅读0次

    主要学习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/

    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输入数据是数据框,如果是矩阵如何处理等。

    相关文章

      网友评论

          本文标题:R语言_数据框排序与数据框连接

          本文链接:https://www.haomeiwen.com/subject/gcuyprtx.html