写一个自己的R函数

在实际的工作中,经常需要做大量相同的数据处理,重复而又冗长的操作很容易让人抓狂。因此,懒惰促使我学习了写一个自己的R函数,以及使用循环语句。


懒惰使人进步

(1)画一个火山图

以画差异表达基因的火山图为例,我们通过DESeq2获得了每个基因在每组比较中的log2 fold change和padj,并整理好如下:

> head(res.test)
      cMvscF.log2FC cMvscF.padj mFvscF.log2FC  mFvscF.padj mMvscM.log2FC  mMvscM.padj
gene1    -0.0776042  1.00000000     0.8235784 6.335025e-03   0.857999861 3.282493e-03
gene2    -0.3658063  0.00533996     0.7614857 1.594686e-11   0.832097420 7.320881e-14
gene3    -0.3389348  0.32209618     1.1255354 3.141754e-07   1.122211863 2.378666e-07

先画一个火山图试一试:

> #绘图数据
> volcanodata <- data.frame(LFC = res.test$cMvscF.log2FC,
+                           padj = res.test$cMvscF.padj,
+                           mean = res.test$baseMean)
> #上调下调
> volcanodata$Condition=ifelse(volcanodata$LFC>1 & volcanodata$padj<=0.1,"up",
+                              ifelse(volcanodata$LFC<(-1) & volcanodata$padj<=0.1,"down",
+                                     "normal"))
> volcanodata$Condition <- factor(volcanodata$Condition,levels=c("up","down","normal"))
> volcanodata <- volcanodata[order(volcanodata$padj,decreasing=T),]
> #数量统计
> print(table(volcanodata$Condition))
    up   down normal 
    96     19    284 
> #绘图
> #library(ggplot2)
> p <- ggplot(data=volcanodata, aes(x=LFC, y=-log10(padj), colour=Condition)) + 
+   geom_point(alpha=0.8,shape=16)  +
+   xlab("log2 fold change") + 
+   ylab("-log10 padj")+
+   geom_vline(xintercept=c(1,-1),color="black",linetype=2) +
+   geom_vline(xintercept=0,color="orangered",linetype=1) +
+   geom_hline(yintercept=-log10(0.1),color="black",linetype=2) +
+   scale_color_manual(values=c('up'='red','down'='green','normal'='gray50')) +
+   theme_bw()
> #保存
> ggsave(p,filename="test.plot1.png",width=6, height=3)

得到了一张图片:


test.plot1.png

(2)写一个自己的函数

每一个R函数都包括三个部分:函数名,程序主体以及参数集合。在编写自定义R函数时,使用function函数将这三个部分各自储存在一个R对象中,形如: my_function<-function(){}。函数将返回最后一行的运行输出结果,如果最后一行不输出结果,整个函数也将不会有返回值。function()的括号内可以填入参数名称。如果只填参数名称,调用函数时不写参数(如果需要用到这个参数)会报错,因此可以预先设置一个初始默认值给括号内的参数,即缺省值。...参数是一种特殊的参数,表明一些可以传递给另一个函数的参数。常用于需要扩展另一个函数,而又不想复制原函数的整个参数列表时。

我们把第一部分的操作写成一个函数。把代码复制粘贴到大括号里,然后把需要用到的变量替换成参数名称。

plot.volcano.v1 <- function(LFC,padj,pcut=0.1,LFCcut=0,filename){
  #绘图数据
  volcanodata <- data.frame(LFC = LFC, padj = padj)
  #上调下调
  volcanodata$Condition=ifelse(volcanodata$LFC>LFCcut & volcanodata$padj<=pcut,"up",
                               ifelse(volcanodata$LFC<(-LFCcut) & volcanodata$padj<=pcut,"down",
                                      "normal"))
  volcanodata$Condition <- factor(volcanodata$Condition,levels=c("up","down","normal"))
  volcanodata <- volcanodata[order(volcanodata$padj,decreasing=T),]
  #数量统计
  print(table(volcanodata$Condition))
  #绘图
  p <- ggplot(data=volcanodata, aes(x=LFC, y=-log10(padj), colour=Condition)) + 
    geom_point(alpha=0.8,shape=16)  +
    xlab("log2 fold change") + 
    ylab("-log10 padj")+
    geom_vline(xintercept=c(LFCcut,-LFCcut),color="black",linetype=2) +
    geom_vline(xintercept=0,color="orangered",linetype=1) +
    geom_hline(yintercept=-log10(pcut),color="black",linetype=2) +
    scale_color_manual(values=c('up'='red','down'='green','normal'='gray50')) +
    theme_bw()
  #保存图片
  ggsave(p,filename=filename,width=6, height=3)
}

测试一下自定义函数:

> plot.volcano.v1(res.test$mFvscF.log2FC,res.test$mFvscF.padj,
+                 pcut=0.1,LFCcut=1,
+                 filename="test.plot2.png")
    up   down normal 
    80      8    311
test.plot2.png

把这个函数的代码复制到一个新的R Script,保存到当前工作路径下,命名为plot.volcano.v1.R。然后一键清空,source重新调用这个函数:

> rm(list=ls())
> source("plot.volcano.v1.R")
> load("res.test.RData")
> plot.volcano.v1(res.test$mMvscM.log2FC,res.test$mMvscM.padj,
+                 pcut=0.1,LFCcut=1,
+                 filename="test.plot3.png")
    up   down normal 
    93     12    294
test.plot3.png

(3)写一个循环

编程中减少代码重复的两个工具,一是循环,一是函数。有了上面那个高度个性化的自定义函数,R代码就变的简洁多了。如果想进一步解决重复操作的问题,就需要写一个循环。

for循环重复地执行一个语句,直到某个变量的值不再包含在序列seq中为止。

> for (i in 1:5) print("hello")
[1] "hello"
[1] "hello"
[1] "hello"
[1] "hello"
[1] "hello"

while循环重复地执行一个语句,直到条件不为真为止。

> i <- 5
> while (i>0) {print("hello"); i <- i-1}
[1] "hello"
[1] "hello"
[1] "hello"
[1] "hello"
[1] "hello"

if语句用来进行条件控制,以执行不同的语句。if (conditon) {expr1} else {expr2}。若condition条件为真,则执行expr1,否则执行expr2。else要紧跟着第一个语句的大括号},不能另起一行,否则会认为if (conditon) {expr1}已经运行完了。ifelse会更加高效。

> if (i==5) {
+   print("is 5")
+ } else {
+   print("isn't 5")}
[1] "isn't 5"
> ifelse(i==1,"is 5","isn't 5")
[1] "isn't 5"

现在我们写一个for循环,把上面三个图一次性都画出来:

> for (i in 1:3) {
+   plot.volcano.v1(res.test[,(2*i-1)],res.test[,(2*i)],
+                   pcut=0.1,LFCcut=1,
+                   filename=paste0("test.plot.",i,".png"))
+ }
    up   down normal 
    96     19    284 
    up   down normal 
    80      8    311 
    up   down normal 
    93     12    294

变的简洁的代码看上去真是让一个强迫症患者感到开心呢。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352