列表转数据框-我的计算机还能救一救
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
看得出来,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