列表转数据框-我的计算机还能救一救

2018-12-08  本文已影响32人  Stone_Stan4d

我曾经有一个表,它叫lncmiRcode,它这么大:

> dim(lncmiRcode)
[1] 208303      3

你没看错,它只有3列,但是有20.8万行
它来自于另一个更大的表miRcode, 128.6w行 * 12列:

# 只保留lncRNA
tmpIndex = miRcode$gene_class %in% 
  c('lncRNA, intergenic', 'lncRNA, overlapping', 'pseudogene')
lncmiRcode = miRcode[tmpIndex,c(2, 3, 4)]
lncmiRcode = dplyr::distinct(lncmiRcode)#去除重复的行
image.png
这些都不重要,重要的是,它的第三列是不规范的,用一个/就把两个不同的miRNA给打发了,是几个意思呢?
image.png
我要把这些miRNA分离出来,让它们各自占用一行,像这样:
 gene_symbol gene_class    microrna
1        MYH16 pseudogene       miR-7
2        MYH16 pseudogene     miR-7ab
3        MYH16 pseudogene  miR-133abc
4        MYH16 pseudogene      miR-96
5        MYH16 pseudogene     miR-507
6        MYH16 pseudogene    miR-1271
7        MYH16 pseudogene   miR-135ab
8        MYH16 pseudogene miR-135a-5p
9        MYH16 pseudogene     miR-138
10       MYH16 pseudogene   miR-138ab

其实这些小分子(miRNA)的前缀是不一样的,有let,有/miR

tmp = substr(lncmiRcode$microrna, 1, 3) 
> table(tmp)
tmp
   let    miR 
  1952 206351 

把冰箱装进大象一共有几步呢?


先打开冰箱,分开绑到一起的miRNAs:

  tmpmiR= strsplit(lncmiRcode$microrna, split = '/') 
#用'/'绑到一起,就用'/'分开
  for(i in 1:length(tmpmiR)){
    miRs = tmpmiR[i][[1]]
    if(length(miRs) > 1){
    # 如果有绑到一起的情况,就执行{}内代码,改变tmpmiR[[i]]的内容
      miRs[2:length(miRs)] = paste(tmp[i], miRs[2:length(miRs)],  sep = '-')
    #加上存在tmp里的前缀,当然用i来一一对应
      tmpmiR[i][[1]] = miRs}
    }
tmpmiR lncmiRcode

是不是一一对应?


接下来把大象塞进冰箱,让分开的miRNA去于lncRNA配对,且形成数据框:

#先构造一个函数,实现把绑一起的miRNA合成一组,
#因为它们靶向相同的lncRNA,然后组成数据框
  tmpfun = function(i){
    tmpRow = data.frame(gene_symbol = unlist(rep(lncmiRcode[i, 1], length(tmpmiR[[i]]))),
                        gene_class = unlist(rep(lncmiRcode[i, 2], length(tmpmiR[[i]]))),
                        microrna = tmpmiR[[i]])
    return(tmpRow)
    }

#再用神奇的lapply,对'lncmiRcode'中的每一个元素,实行该函数,#这样就把大象装进冰箱啦!
  tmpMat = lapply(1:length(tmpmiR), tmpfun)

如果事情到此就结束了,我还有必要写一个笔记记下来吗?问题在哪里?

返回的tmpMat,是一个list,而不是data.frame:

> tmpMat[1:3]
[[1]]
  gene_symbol gene_class microrna
1       MYH16 pseudogene    miR-7
2       MYH16 pseudogene  miR-7ab

[[2]]
            gene_symbol gene_class   microrna
gene_symbol       MYH16 pseudogene miR-133abc

[[3]]
  gene_symbol gene_class microrna
1       MYH16 pseudogene   miR-96
2       MYH16 pseudogene  miR-507
3       MYH16 pseudogene miR-1271

昨天,我用了一个for循环,这么长的list,循环了有15~20min吧,显然我是不愿意的:

  for(i in 1:length(tmpMat)){
    tmpMat0 = rbind(tmpMat0, tmpMat[[i]])
  }
  
  lncmiRcode = lncmiRcode[!grepl('/', lncmiRcode$microrna),]
  lncmiRcode = rbind(lncmiRcode, tmpMat0)
  save(lncmiRcode, file = 'lncRNA-miR-miRcode.rdata')

第三步,关上冰箱,把藏在list里的data.frame整理出来:
搜索如此:

image.png
第四条解释
image.png
image.png
image.png
image.png

看得出来,data.table::rbind.list()函数是最快的。我自己尝试一下看看:

data = tmpMat[1:5000]


library(rbenchmark)
benchmark(do.call(rbind, data), ldply(data, rbind), rbind.fill(data), 
          rbind_all(data), rbindlist(data))
> benchmark(do.call(rbind, data), ldply(data, rbind), rbind.fill(data), 
+           rbind_all(data), rbindlist(data))
                  test replications elapsed relative user.self sys.self user.child
1 do.call(rbind, data)          100    4.30   71.667      4.27     0.00         NA
2   ldply(data, rbind)          100   12.08  201.333     11.97     0.00         NA
3     rbind.fill(data)          100    6.50  108.333      5.97     0.03         NA
4      rbind_all(data)          100    0.31    5.167      0.30     0.00         NA
5      rbindlist(data)          100    0.06    1.000      0.06     0.00         NA
  sys.child
1        NA
2        NA
3        NA
4        NA
5        NA
There were 50 or more warnings (use warnings() to see the first 50)

我选择用这个data.table::rbindlist,运行很快,一秒不到:

tmpMat0 = data.table::rbindlist(tmpMat)
> head(tmpMat0)
   gene_symbol gene_class   microrna
1:       MYH16 pseudogene      miR-7
2:       MYH16 pseudogene    miR-7ab
3:       MYH16 pseudogene miR-133abc
4:       MYH16 pseudogene     miR-96
5:       MYH16 pseudogene    miR-507
6:       MYH16 pseudogene   miR-1271

关于benchmark:
Benchmark Experiments

上一篇下一篇

猜你喜欢

热点阅读