051-对R的一些新认识

刘小泽写于18.11.2 豆豆偷偷回来一天

这几天都是花花在写教程,我在旁边看着,被论文拖住了,我今天忍不住又学了点东西。唉,这年头,不学点知识充实充实,都感觉对不住自己的十几个小时

今天突然有兴趣学起了dplyr,确实很给力,看花花一直使用十分眼馋啊🤒 另外还学习了Rmd新技能,十分提高效率。全文均由Rmd导出

激动人心的时刻

第一次用Rmarkdown编辑,这个确实很效率,借此机会利用生物数据学习一下强大的dplyr、tydir:

  • 第一部分 dplyr
  • 第二部分 tidyr
  • 第三部分 Rmd

第一部分 dplyr

其中的四个数据messy、tidy、dose、name2go.csv公众号后台回复rmd获得哦。另外附送Rmd官方小抄

加载包

library(dplyr)
library(readr)

读取数据

ydat <- read_csv("tidy.csv")
#> Parsed with column specification:
#> cols(
#>   symbol = col_character(),
#>   systematic_name = col_character(),
#>   nutrient = col_character(),
#>   rate = col_double(),
#>   expression = col_double(),
#>   bp = col_character(),
#>   mf = col_character()
#> )

先简单看下ydat数据

head(ydat$symbol)
#> [1] "SFB2" NA     "QRI7" "CFT2" "SSO2" "PSP2"
mean(ydat$expression)
#> [1] 0.003367182
sd(ydat$expression)
#> [1] 0.6675023
range(ydat$rate)
#> [1] 0.05 0.30

看一下dplyr能干啥

#能看到包含的几个主要函数
ydat %>% 
    filter(bp == "leucine biosynthesis") %>% 
    group_by(nutrient,symbol) %>% 
    summarize(mean=mean(expression),
              sd=sd(expression),
              r=cor(rate,expression))
#> # A tibble: 24 x 5
#> # Groups:   nutrient [?]
#>    nutrient symbol   mean    sd      r
#>    <chr>    <chr>   <dbl> <dbl>  <dbl>
#>  1 Ammonia  LEU1   -0.818 0.387  0.659
#>  2 Ammonia  LEU2   -0.535 0.379 -0.193
#>  3 Ammonia  LEU4   -0.368 0.561 -0.670
#>  4 Ammonia  LEU9   -1.01  0.641  0.870
#>  5 Glucose  LEU1   -0.553 0.412  0.979
#>  6 Glucose  LEU2   -0.393 0.327  0.899
#>  7 Glucose  LEU4    1.09  1.01  -0.972
#>  8 Glucose  LEU9   -0.165 0.346  0.354
#>  9 Leucine  LEU1    2.70  1.08  -0.951
#> 10 Leucine  LEU2    0.285 1.16  -0.974
#> # ... with 14 more rows

分步开始学习

1. filter()

1.1 找某个基因

filter(ydat, symbol == "LEU1") %>% head
#> # A tibble: 6 x 7
#>   symbol systematic_name nutrient  rate expression bp        mf           
#>   <chr>  <chr>           <chr>    <dbl>      <dbl> <chr>     <chr>        
#> 1 LEU1   YGL009C         Glucose   0.05      -1.12 leucine … 3-isopropylm…
#> 2 LEU1   YGL009C         Glucose   0.1       -0.77 leucine … 3-isopropylm…
#> 3 LEU1   YGL009C         Glucose   0.15      -0.67 leucine … 3-isopropylm…
#> 4 LEU1   YGL009C         Glucose   0.2       -0.59 leucine … 3-isopropylm…
#> 5 LEU1   YGL009C         Glucose   0.25      -0.2  leucine … 3-isopropylm…
#> 6 LEU1   YGL009C         Glucose   0.3        0.03 leucine … 3-isopropylm…

1.2 找多个基因

filter(ydat, symbol == "LEU1" | symbol == "ADH2") %>% head
#> # A tibble: 6 x 7
#>   symbol systematic_name nutrient  rate expression bp        mf           
#>   <chr>  <chr>           <chr>    <dbl>      <dbl> <chr>     <chr>        
#> 1 LEU1   YGL009C         Glucose   0.05      -1.12 leucine … 3-isopropylm…
#> 2 ADH2   YMR303C         Glucose   0.05       6.28 fermenta… alcohol dehy…
#> 3 LEU1   YGL009C         Glucose   0.1       -0.77 leucine … 3-isopropylm…
#> 4 ADH2   YMR303C         Glucose   0.1        5.81 fermenta… alcohol dehy…
#> 5 LEU1   YGL009C         Glucose   0.15      -0.67 leucine … 3-isopropylm…
#> 6 ADH2   YMR303C         Glucose   0.15       5.64 fermenta… alcohol dehy…

1.3 看下生长率最低时(0.05)LEU1基因表达量

# 注意LEU1和leucine的相关性
filter(ydat, symbol == "LEU1" & rate == .05)
#> # A tibble: 6 x 7
#>   symbol systematic_name nutrient   rate expression bp       mf           
#>   <chr>  <chr>           <chr>     <dbl>      <dbl> <chr>    <chr>        
#> 1 LEU1   YGL009C         Glucose    0.05      -1.12 leucine… 3-isopropylm…
#> 2 LEU1   YGL009C         Ammonia    0.05      -0.76 leucine… 3-isopropylm…
#> 3 LEU1   YGL009C         Phosphate  0.05      -0.81 leucine… 3-isopropylm…
#> 4 LEU1   YGL009C         Sulfate    0.05      -1.57 leucine… 3-isopropylm…
#> 5 LEU1   YGL009C         Leucine    0.05       3.84 leucine… 3-isopropylm…
#> 6 LEU1   YGL009C         Uracil     0.05      -2.07 leucine… 3-isopropylm…

1.4 只显示 LEU1和Leucine的数据

filter(ydat, ydat$symbol == "LEU1" & ydat$nutrient == "Leucine")
#> # A tibble: 6 x 7
#>   symbol systematic_name nutrient  rate expression bp        mf           
#>   <chr>  <chr>           <chr>    <dbl>      <dbl> <chr>     <chr>        
#> 1 LEU1   YGL009C         Leucine   0.05       3.84 leucine … 3-isopropylm…
#> 2 LEU1   YGL009C         Leucine   0.1        3.36 leucine … 3-isopropylm…
#> 3 LEU1   YGL009C         Leucine   0.15       3.24 leucine … 3-isopropylm…
#> 4 LEU1   YGL009C         Leucine   0.2        2.84 leucine … 3-isopropylm…
#> 5 LEU1   YGL009C         Leucine   0.25       2.04 leucine … 3-isopropylm…
#> 6 LEU1   YGL009C         Leucine   0.3        0.87 leucine … 3-isopropylm…

1.5 filter + ggplot2

# NOTE LEU1 is highly expressed when starved of leucine!
library(ggplot2)
#> Need help getting started? Try the cookbook for R:
#> http://www.cookbook-r.com/Graphs/
filter(ydat, ydat$symbol == "LEU1") %>% 
    ggplot(aes(rate, expression, colour = nutrient))+
           geom_line(lwd=1.5)

1.6 小练习

# display bp variable is "leucine biosynthesis" and nutrient was Leucine, then decide genes number
filter(ydat, ydat$bp == "leucine biosynthesis" & ydat$nutrient == "Leucine") %>% select(symbol) %>% unique()

# show expression value which is >99%
filter(ydat,
       ydat$expression >quantile(ydat$expression, probs = .99))
2. select()
# just type colname is fine
select(ydat, symbol, systematic_name)

# remove columns
nogo <- select(ydat, -bp, -mf)
nogo
filter(nogo, symbol == "LEU1" & rate == .05)
3.mutate()
mutate(nogo, signal = 2^expression) %>% head
#> # A tibble: 6 x 6
#>   symbol systematic_name nutrient  rate expression signal
#>   <chr>  <chr>           <chr>    <dbl>      <dbl>  <dbl>
#> 1 SFB2   YNL049C         Glucose   0.05      -0.24  0.847
#> 2 <NA>   YNL095C         Glucose   0.05       0.28  1.21 
#> 3 QRI7   YDL104C         Glucose   0.05      -0.02  0.986
#> 4 CFT2   YLR115W         Glucose   0.05      -0.33  0.796
#> 5 SSO2   YMR183C         Glucose   0.05       0.05  1.04 
#> 6 PSP2   YML017W         Glucose   0.05      -0.69  0.620
# mutate(nogo, signal = 2^expression, sigsr = sqrt(signal)) %>% head
# 看看tidydata长什么样
library(tidyr)
mutate(nogo, signal=2^expression, sigsr=sqrt(signal)) %>% 
    gather(unit, value, expression:sigsr) %>% 
    ggplot(aes(value))+geom_histogram(bins = 100)+facet_wrap(~unit, scales = "free")

4.arrange()
arrange(ydat, symbol)
arrange(ydat, expression)
arrange(ydat, desc(expression)) # arrange by decending 

4.1 exercise

filter(ydat, bp == "leucine biosynthesis" & nutrient == "Leucine") %>% arrange(symbol)
#> # A tibble: 24 x 7
#>    symbol systematic_name nutrient  rate expression bp        mf          
#>    <chr>  <chr>           <chr>    <dbl>      <dbl> <chr>     <chr>       
#>  1 LEU1   YGL009C         Leucine   0.05       3.84 leucine … 3-isopropyl…
#>  2 LEU1   YGL009C         Leucine   0.1        3.36 leucine … 3-isopropyl…
#>  3 LEU1   YGL009C         Leucine   0.15       3.24 leucine … 3-isopropyl…
#>  4 LEU1   YGL009C         Leucine   0.2        2.84 leucine … 3-isopropyl…
#>  5 LEU1   YGL009C         Leucine   0.25       2.04 leucine … 3-isopropyl…
#>  6 LEU1   YGL009C         Leucine   0.3        0.87 leucine … 3-isopropyl…
#>  7 LEU2   YCL018W         Leucine   0.05       1.54 leucine … 3-isopropyl…
#>  8 LEU2   YCL018W         Leucine   0.1        1.23 leucine … 3-isopropyl…
#>  9 LEU2   YCL018W         Leucine   0.15       0.69 leucine … 3-isopropyl…
#> 10 LEU2   YCL018W         Leucine   0.2        0.39 leucine … 3-isopropyl…
#> # ... with 14 more rows
5.summarize()
# get mean value
summarize(ydat, meanexp=mean(expression))
#> # A tibble: 1 x 1
#>   meanexp
#>     <dbl>
#> 1 0.00337

# measure correlation
summarize(ydat, r=cor(rate, expression))
#> # A tibble: 1 x 1
#>         r
#>     <dbl>
#> 1 -0.0220

# total num of observation
summarize(ydat,total=n())
#> # A tibble: 1 x 1
#>    total
#>    <int>
#> 1 198430

# total distinct num
summarize(ydat, distinct=n_distinct(symbol))
#> # A tibble: 1 x 1
#>   distinct
#>      <int>
#> 1     4211
6.group_by()
ydat
group_by(ydat, nutrient)
group_by(ydat, nutrient, expression)
# real power comes with summarize
summarize(group_by(ydat, symbol), meanexp=mean(expression))
#> # A tibble: 4,211 x 2
#>    symbol  meanexp
#>    <chr>     <dbl>
#>  1 AAC1    0.529  
#>  2 AAC3   -0.216  
#>  3 AAD10   0.438  
#>  4 AAD14  -0.0717 
#>  5 AAD16   0.242  
#>  6 AAD4   -0.792  
#>  7 AAD6    0.290  
#>  8 AAH1    0.0461 
#>  9 AAP1   -0.00361
#> 10 AAP1'  -0.421  
#> # ... with 4,201 more rows

summarize(group_by(ydat, nutrient), r=cor(rate, expression))
#> # A tibble: 6 x 2
#>   nutrient        r
#>   <chr>       <dbl>
#> 1 Ammonia   -0.0175
#> 2 Glucose   -0.0112
#> 3 Leucine   -0.0384
#> 4 Phosphate -0.0194
#> 5 Sulfate   -0.0166
#> 6 Uracil    -0.0353

6.1 exercise

filter(ydat, rate ==.05 & symbol == "ADH2") %>% 
    select(nutrient, expression) 
#> # A tibble: 6 x 2
#>   nutrient  expression
#>   <chr>          <dbl>
#> 1 Glucose         6.28
#> 2 Ammonia         0.55
#> 3 Phosphate      -4.6 
#> 4 Sulfate        -1.18
#> 5 Leucine         4.15
#> 6 Uracil          0.63

filter(ydat, rate == .05 & nutrient == "Leucine") %>% 
    arrange(desc(expression)) %>% head %>% 
    select(symbol, expression, bp)
#> # A tibble: 6 x 3
#>   symbol expression bp                        
#>   <chr>       <dbl> <chr>                     
#> 1 HXT3         5.16 hexose transport          
#> 2 HXT5         4.9  hexose transport          
#> 3 HSP26        4.86 response to stress*       
#> 4 QDR2         4.61 multidrug transport       
#> 5 YRO2         4.4  biological process unknown
#> 6 BAP3         4.29 amino acid transport

filter(ydat, rate == .05 & bp == "response to stress") %>% 
    group_by(nutrient)%>% summarize( meanexp=mean(expression) )
#> # A tibble: 6 x 2
#>   nutrient  meanexp
#>   <chr>       <dbl>
#> 1 Ammonia     0.943
#> 2 Glucose     0.743
#> 3 Leucine     0.811
#> 4 Phosphate   0.981
#> 5 Sulfate     0.743
#> 6 Uracil      0.731

第二部分 tidyr

加载包和数据

library(readr)
library(dplyr)
library(tidyr)
hr <- read_csv("dose.csv")
#> Parsed with column specification:
#> cols(
#>   name = col_character(),
#>   a_10 = col_integer(),
#>   a_20 = col_integer(),
#>   b_10 = col_integer(),
#>   b_20 = col_integer(),
#>   c_10 = col_integer(),
#>   c_20 = col_integer()
#> )

分步来认识一下

1. gather()
hr %>% gather(key = drugdose, value = hr, a_10:c_20) %>% head
#> # A tibble: 6 x 3
#>   name  drugdose    hr
#>   <chr> <chr>    <int>
#> 1 jon   a_10        60
#> 2 ann   a_10        65
#> 3 bill  a_10        70
#> 4 kate  a_10        75
#> 5 joe   a_10        80
#> 6 jon   a_20        55
hr %>% gather(key = drugdose, value = hr, -name) %>% head
#> # A tibble: 6 x 3
#>   name  drugdose    hr
#>   <chr> <chr>    <int>
#> 1 jon   a_10        60
#> 2 ann   a_10        65
#> 3 bill  a_10        70
#> 4 kate  a_10        75
#> 5 joe   a_10        80
#> 6 jon   a_20        55
2.seperate()
hr %>% gather(key = drugdose, value = hr, -name) %>% 
    separate(drugdose, into=c("drug", "dose"), sep="_") %>% head 
3.gather %>% separate %>% filter %>% group_by %>% summerize

3.1 create a new date.frame

hrtidy <- hr %>% 
    gather(key = drugdose, value = hr,-name) %>% 
    separate(drugdose, into=c("drug", "dose"), sep = "_") 
# View(hrtidy)

3.2 filter

hrtidy %>% filter(drug == "a")
hrtidy %>% filter(dose == 20)
hrtidy %>% filter(hr>=80)

3.3 analyze

hrtidy %>% 
    filter(name!="joe") %>% 
    group_by(drug, dose) %>% 
    summarize(meanhr=mean(hr))

那么如何将messy data变tidy呢?

先看看什么叫messy data

yorig <- read_csv("messy.csv")
#> Parsed with column specification:
#> cols(
#>   .default = col_double(),
#>   GID = col_character(),
#>   YORF = col_character(),
#>   NAME = col_character(),
#>   GWEIGHT = col_integer()
#> )
#> See spec(...) for full column specifications.
yorig[1:6,1:10] %>% knitr::kable()
GIDYORFNAMEGWEIGHTG0.05G0.1G0.15G0.2G0.25G0.3
GENE1331XA_06_P5820SFB2::YNL049C::10821291-0.24-0.13-0.21-0.15-0.05-0.05
GENE4924XA_06_P5866NA::YNL095C::108622210.280.13-0.40-0.48-0.110.17
GENE4690XA_06_P1834QRI7::YDL104C::10859551-0.02-0.27-0.27-0.020.240.25
GENE1177XA_06_P4928CFT2::YLR115W::10819581-0.33-0.41-0.24-0.03-0.030.00
GENE511XA_06_P5620SSO2::YMR183C::108121410.050.020.400.34-0.13-0.14
GENE2133XA_06_P5307PSP2::YML017W::10830361-0.69-0.030.230.200.00-0.27
step1: seperate the NAME and remove unwanted stuff
yorig %>% 
    separate(NAME, into = c("symbol", "systematic_name", "somenum"),
             sep = "::") %>% 
    select(-GID, -YORF, -somenum, -GWEIGHT) %>% head 

step2: gather the data then separate

ynogo <- yorig %>% 
    separate(NAME, into = c("symbol", "systematic_name", "somenum"),
             sep = "::") %>% 
    select(-GID, -YORF, -somenum, -GWEIGHT) %>% 
    gather(key = nutrientrate, value = expression, G0.05:U0.3) %>% 
    separate(nutrientrate, into = c("nutrient", "rate"),sep = 1)

step3: inner_join to GO

# import the data
sn2go <- read_csv("name2go.csv")
#> Parsed with column specification:
#> cols(
#>   systematic_name = col_character(),
#>   bp = col_character(),
#>   mf = col_character()
#> )
head(sn2go)
# inner join
yjoined <- inner_join(ynogo, sn2go, by="systematic_name")
yjoined
# left join (use NA to replace no corresponding entry)
yljoined <- left_join(ynogo, sn2go, by="systematic_name")
yljoined
# see a little bit
glimpse(yjoined)
glimpse(yljoined)

step4: change nutrient

nutrientlookup <-
    data_frame(nutrient = c("G", "L", "N", "P", "S", "U"), nutrientname = c("Glucose", "Leucine", "Ammonia","Phosphate", "Sulfate","Uracil"))

yjoined<- yjoined %>% 
    mutate(rate = as.numeric(rate)) %>% 
    mutate(symbol = ifelse(symbol == "NA", NA, symbol)) %>% 
    left_join(nutrientlookup) %>% 
    select(-nutrient) %>% 
    select(symbol:systematic_name, nutrient = nutrientname, rate:mf)
#> Joining, by = "nutrient"
yjoined %>% head %>% knitr::kable()

最后的tidy data,可以和一开始的那个对比一下

symbolsystematic_namenutrientrateexpressionbpmf
SFB2YNL049CGlucose0.05-0.24ER to Golgi transportmolecular function unknown
NAYNL095CGlucose0.050.28biological process unknownmolecular function unknown
QRI7YDL104CGlucose0.05-0.02proteolysis and peptidolysismetalloendopeptidase activity
CFT2YLR115WGlucose0.05-0.33mRNA polyadenylylation*RNA binding
SSO2YMR183CGlucose0.050.05vesicle fusion*t-SNARE activity
PSP2YML017WGlucose0.05-0.69biological process unknownmolecular function unknown

第三部分 Rmd的学习

还是非常偶然的,之前一直用typora编辑,效率也比较高,但存在一个问题,就是当笔记中代码比较多时,就需要不断从R和typpora切换,十分麻烦。今天本来只是想看看dplyr和tidyr,然后想到为什么不能把所学的代码直接用r里的代码块导出呢?于是看了下Rmd,很简单,三五分钟就可以学会,豆豆和花花都已经体验过了,你也可以的!

介绍一下Rmd

它的应用主要是方便人们重复代码、教程。一般来说,好的重复流程有10个亮点:

  • 代码写在一个一个小块中 【code in small chunks】
  • 有版本迭代 【make incrementla changes (version control)】
  • 代码中要有实例数据【add tests in code】
  • 不要重复造轮子,多搜索别人已经写好的函数【don’t reinvent wheel】
  • 不要在原始数据上修改【make data read-only rather than modifying original data】
  • 创建project,数据放在一个文件夹下【use project into one dir】
  • 代码开源,毕竟是共享社会嘛,自己的代码需要流转【release code (GitHub, RPubs, Figshare)】
  • 使用相对路径,不要用绝对路径【(e.g. data/huahua.csv NOT /Users/Download/Data/huahua.csv)】
  • 有随机数需要设置seed【set.seed() 】
  • 注释信息要详细【when and how to download data; data version;software version】

如何使用Rmd【四步走】

其实就是加强版的markdown

  • 第一步:新建project=》file=》R Markdown =》 From template=》选HTML
  • 第二步:进入Rmd的模版,熟悉md的小伙伴一定对其中的代码很熟悉了,包括标题大小、加粗、引用、代码块等
  • 第三步:在模版基础上修改,另外记住两个快捷键

第一个:插入代码块 ctrl/cmd + alt/option + i 第二个:快速knit,修饰成html格式 ctrl/cmd + shift + k

  • 第四步:导出为md
library(knitr)
knit("Rmd-homework.Rmd")
Yunze Liu
Yunze Liu
Bioinformatics Sharer

Co-founder of Bioinfoplanet(生信星球)

Next
Previous

Related