【问题标题】:lapply slower than for-loop when used for a BiomaRt query. Is that expected?lapply 用于 BiomaRt 查询时比 for-loop 慢。这是预期的吗?
【发布时间】:2012-09-05 19:49:47
【问题描述】:

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

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

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

这是一个可重现的例子。

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 

【问题讨论】:

  • This 您可能感兴趣的问题。
  • @joran,但在这里它只是调用一个需要很长时间的函数,for 循环和 lapply 循环的次数相同。我不希望有什么不同。
  • @ptcoquin,如果您重复该过程 10 次,结果是否可重现?只是为了排除数据库的连接速度和业务是否起作用。一般来说,这类问题很难回答,因为您的示例涉及我们没有的数据库。
  • 不仅仅是数据库访问,查询是基于网络的资源,因此人们会期望非常大的变化独立于任何 R 编码差异。此外,biomaRt 查询通常是矢量化的;此getBM("description", "tair_locus", loci, athaliana) 为您的 10 个基因座向量返回一个包含 10 个描述的向量。
  • @ptocquin 而不是使用 for 循环或 lapply,只需执行一个查询,loci 包含您想要的所有值。这会很快,因为只有一次通过 Internet 访问 biomaRt 服务器。

标签: r for-loop lapply


【解决方案1】:

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

归根结底,差异在 R 之外的可能性非常大,并且与循环、lapply 或 for 循环的样式无关。

【讨论】:

    【解决方案2】:

    apply 系列函数虽然是惯用的,但只是 for 循环的语法糖。他们通常比较慢。正如 joran 所指出的,this has been asked 之前在 SO 上。

    如果您想了解在 R 中加速循环的技巧,请参阅 this volume of R News(pdf)的第 46 页,称为“R 帮助台——如何避免此循环或使其更快?”

    【讨论】:

    • 但是当大部分时间都花在函数内部,只有少量的函数调用时,我不认为会有这么大的差异。
    • 这是一个公平的断言。就像您说的那样,数据库访问可能是一个因素。 lapply 不需要您为数据指定结构(因此必须猜测)这一事实也可能是减速的一部分。见r-bloggers.com/…。总而言之,我认为 OP 的最佳选择是在我提供的链接中阅读一些关于矢量化的内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-12
    • 2018-11-29
    • 2015-07-26
    • 1970-01-01
    • 2015-05-22
    • 1970-01-01
    相关资源
    最近更新 更多