2

我想使用BiomaRt包查询数据库。我有loci并且想要检索一些相关信息,比如说description

我第一次尝试使用lapply,但对执行任务所需的时间感到惊讶。因此,我尝试了更基本for-loop的并获得更快的结果。

这是预期的还是我的代码或我的理解有问题apply?我阅读了其他有关*applyvsfor-loop性能的帖子(例如,这里),我知道不应该期望提高性能,但我不明白为什么这里的性能实际上较低

这是一个可重现的例子。

1)加载库并选择数据库:

library("biomaRt")
athaliana <- useMart("plants_mart_14")
athaliana <- useDataset("athaliana_eg_gene",mart=athaliana)

2)查询数据库:

loci <- c("at1g01300", "at1g01800", "at1g01900", "at1g02335", "at1g02790", 
"at1g03220", "at1g03230", "at1g04040", "at1g04110", "at1g05240"
)

我创建了一个函数用于lapply

foo <- function(loci) {
  getBM("description","tair_locus",loci,athaliana)
}

当我在第一个元素上使用此功能时:

> system.time(foo(cwp_loci[1]))
utilisateur     système      écoulé 
      0.020       0.004       1.599

当我lapply用来检索所有值的数据时:

> system.time(lapply(loci, foo))
utilisateur     système      écoulé 
      0.220       0.000      16.376

然后我创建了一个新函数,添加了一个for-loop

foo2 <- function(loci) {
  for (i in loci) {
    getBM("description","tair_locus",loci[i],athaliana)
  }
}

这是结果:

> system.time(foo2(loci))
utilisateur     système      écoulé 
      0.204       0.004      10.919

当然,这将应用于 的大列表loci,因此需要性能最佳的选项。我感谢你的帮助。

编辑根据@MartinMorgan 的推荐

简单地把向量loci传给getBM就大大提高了查询效率。越简单越好。

> system.time(lapply(loci, foo))
utilisateur     système      écoulé 
      0.236       0.024     110.512 

> system.time(foo2(loci))
utilisateur     système      écoulé 
      0.208       0.040     116.099 

> system.time(foo(loci))
utilisateur     système      écoulé 
      0.028       0.000       6.193 
4

2 回答 2

4

我觉得这与 lapply 与 for 循环无关。调用数据库需要 1.6 秒,lapply 执行 10 次,即总共 16 秒。for 循环没有什么不同,它调用数据库 10 次。但是,它执行与应用循环相同的查询,可能导致数据库返回缓存结果而不是查询数据库。这可以通过颠倒调用的顺序来检查时间是否有利于 lapply。感谢@JoshuaUlrich 在聊天中建议数据库缓存。除了数据库缓存(或由网络服务器缓存)之外,@MartinMorgan 的建议还为花费的时间增加了相当多的随机性getBM

底线,差异很大的可能性在 R 之外并且与循环、lapply 或 for 循环的样式无关。

于 2012-09-05T21:24:15.973 回答
2

函数家族虽然是惯用的apply,但只是for循环的语法糖。他们通常比较慢。正如 joran 所指出的,这已经在 SO 上被问过了。

如果您想要在 R 中加速循环的提示,请参阅本卷 R 新闻(pdf)的第 46 页,称为“R 帮助台——如何避免此循环或使其更快?”

于 2012-09-05T21:02:07.580 回答