美文网首页R生物信息学与基因组学科研信息学
R语言中性价比最高的函数以及最贵的函数

R语言中性价比最高的函数以及最贵的函数

作者: 9d760c7ce737 | 来源:发表于2019-05-24 17:19 被阅读100次

    今天讲几个我喜欢的函数。

    1.性价比最高的函数t()

    中文名称转置,就是矩阵的行列转换
    先创建一个矩阵

    dd <- matrix(seq(1,18),nrow = 3)
    colnames(dd) <- paste0("gene",LETTERS[1:6])
    rownames(dd) <- paste0("sample",LETTERS[1:3])
    dd
    

    用t()转置一下,行列就互换了

    t(dd)
    

    就一个小小的字母t完成这么复杂的操作,在调整数据格式中必不可少,比如,大部分原始数据都是,行是基因,列是样本,而ggplot2绘图需要的是清洁数据,行是样本,列是基因,这个过程中许需要使用转置。

    我曾经想,如果没有t(), 我们该如何编程实现,以前我无能为力,但是自从我想通了R语言里面数据结构的本质上都是向量,我就想到了方法。
    我认为,向量,矩阵,数据框,列表本质上都是一个东西,是挂在晾衣绳上的小盒子:

    这样就好理解,对于data.frame而言,为什么names()和colnames()返回的结果一样,为什么获列的时候df[,1]和df[1]的结果也一样,还有,对于批量读入的数据如果存为列表,可以使用do.call(cbind,list)把列表变成数据框,因为本质上他们都是一个结构。
    这样一想,连字符串都可以看作是向量:


    如此,我先用lapply批量获取行,再用cbind把他们按照列合并就可以了

    myt <- function(dd){
      tt <- do.call(cbind,lapply(1:nrow(dd), function(x){dd[x,]}))
      colnames(tt) <- rownames(dd)
      return(tt)
    }
    myt(dd)
    

    既然sapply是lapply的简化版本,他默认返回的是向量,通常我们看到的是一维的向量,也可以是一列列组成的向量

    sapply(1:nrow(dd), function(x){dd[x,]})
    

    既然sapply可以,那么apply理论上也应该可以,只要我按照行去取出行,那么他会自动把得到的行按列合并,在R语言中"["也是函数,表示取出。

    apply(dd,1,"[")
    

    确实也实现了效果,目前开来apply的方案是除了t()之外书写最简单的。我们看看他们的速度呢?运行10万次比较一下



    t()当真是性价比最高的函数,书写最简单,速度十分快!

    2.最贵的函数是table()

    table用来统计元素出现的次数,举例如下
    从ABCD四个字母中可放回抽取20次,得到向量dd

    set.seed(522)
    dd <- sample(LETTERS[1:4],20,replace = T)
    dd
    

    使用table()统计一下,返回每个字母出现的次数


    为什么要说他最贵呢,情况是这样的,以前人们参加考试,比如托福,要背10000个以上的单词,但是在2003年李笑来先生分析历年的真题并制作词频后发现,去掉''a'',''the''等高频词,还有低频词,剩下的只有2100个单词,每天背诵100个,21天就可以背完,因此还写了一本畅销书,叫《TOEFL核心词汇21天突破》。

    这本书的稿费支持了他大部分生活开销,应该超过100万,当年他用了9个月的时间来完成,今天我们用R语言导入,用jieba来分词,一个table()就可以搞定了。

    这都是闲聊,我在机场的时候,也突发奇想,看看能不能写函数来实现,也不是很困难,先找到不重复的元素,然后计算他们的个数就可以

    mytable <- function(x){
      sapply(unique(x,fromLast = TRUE), function(x){sum(dd==x)})
    }
    mytable(dd)
    

    可以顺利实现,现在我来比较一下速度

    system.time(for (i in 1:100000) {
      table(dd)
    })
    system.time(for (i in 1:100000) {
      mytable(dd)
    })
    

    很惊喜,居然速度快三倍!

    3.大道至简的函数是unique()

    我在构建上一个table函数的时候,用到了unique函数,这个函数可以实现去重的功能。

    set.seed(522)
    dd <- sample(LETTERS[1:4],20,replace = T)
    dd
    unique(dd)
    

    因为在机场没事,就想着如何自己来实现去重的功能。
    我是这样想的

    先找到第一个元素,记录,然后去掉向量里所有这个元素,剩下的向量,再找到第一个元素,记录,去除这个元素,以此类推就实现了。

    无论是一个for循环还是函数,首先自己要能够清晰地定义每一步该做什么,本次中以此类推让我想到要使用递归功能,经过一番思考,我总结了递归函数的写法:

    1.要用if语句来判断
    2.要定义最极端的情况,比如最够一个元素带入函数的结果
    3.尝试保留每一次迭代的结果,每次都用定义的函数

    myunique <- function(dd){
     if(length(dd)==0){
       return(NULL)
     }else{
       return(c(dd[1],myunique(dd[dd !=dd[1]])))
     }
    }
    

    测试一下效果也是不错



    再测试一下速度

    system.time(for (i in 1:100000) {
      unique(dd)
    })
    ## 比较时间
    system.time(for (i in 1:100000) {
      myunique(dd)
    })
    

    还是速度赶不上,好在我现在会写递归函数了,比如,算一个数的阶乘。

    jiecheng <- function(x){
      if(x==0){
        return(1)
      }else{
        return(x*jiecheng(x-1))
      }
    }
    

    测试一下效果:


    实际上R语言里面有专门的函数实现这个功能是```factorial``



    没有比较速度,因为自带函数速度快到无边无界。

    相关文章

      网友评论

        本文标题:R语言中性价比最高的函数以及最贵的函数

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