在R中缓存昂贵的操作

时间:2010-07-27 19:51:10

标签: r caching

一个非常简单的问题:

我正在使用文本编辑器编写和运行我的R脚本,以使它们可以重现,正如SO的几位成员所建议的那样。

这种方法对我来说非常有效,但我有时必须执行昂贵的操作(例如,在2M行数据库上的read.csvreshape),我最好在R环境中缓存而不是每次运行脚本时重新运行(这通常是我进步和测试新代码行的次数)。

有没有办法缓存脚本在某一点上的作用,所以每次我只运行增量代码行(就像我通过交互式运行R一样)?

感谢。

7 个答案:

答案 0 :(得分:9)

## load the file from disk only if it 
## hasn't already been read into a variable
if(!(exists("mytable")){
  mytable=read.csv(...)
}

编辑:修正错字 - 谢谢Dirk。

答案 1 :(得分:8)

的某些组合可以使用一些简单的方法
  • exists("foo")测试变量是否存在,否则重新加载或重新计算
  • file.info("foo.Rd")$ctime您可以将其与Sys.time()进行比较,看看它是否比您可以加载的给定时间更新,否则重新计算。

CRAN上还有一些缓存包可能很有用。

答案 2 :(得分:4)

执行某些操作后,您发现成本很高,请将这个代价高昂的步骤的结果保存在R数据文件中。

例如,如果您将csv加载到名为myVeryLargeDataFrame的数据框中,然后将该数据框中的摘要统计信息创建为名为VLDFSummary的df,那么您可以执行此操作:

save(c(myVeryLargeDataFrame, VLDFSummary), 
  file="~/myProject/cachedData/VLDF.RData", 
  compress="bzip2")

压缩选项是可选的,如果要压缩正在写入磁盘的文件,则使用该选项。有关详细信息,请参阅?save

保存RData文件后,您可以注释掉缓慢的数据加载和汇总步骤以及保存步骤,只需加载如下数据:

load("~/myProject/cachedData/VLDF.RData")

这个答案不依赖编辑器。对于Emacs,TextMate等,它的工作方式相同。您可以保存到计算机上的任何位置。我建议将慢速代码保存在R脚本文件中,这样您就可以随时知道RData文件的来源,并且可以根据需要从源数据中重新创建它。

答案 3 :(得分:4)

(迟来的答案,但我在这个问题发布后的一年开始使用SO。)

这是记忆化(或记忆化)背后的基本思想。我有很多建议,特别是memoiseR.cache个包,in this query

您还可以利用检查点,也可以作为同一列表的一部分进行处理。

我认为你的用例反映了我的第二个:“怪异计算的记忆”。 :)

我使用的另一个技巧是做很多内存映射文件,我用它来存储数据。关于这一点的好处是多个R实例可以访问共享数据,因此我可以让很多实例破解同样的问题。

答案 4 :(得分:3)

当我使用Sweave时,我也想这样做。我建议将所有昂贵的函数(加载和重塑数据)放在代码的开头。运行该代码,然后保存工作区。然后,注释掉昂贵的函数,并使用load()加载工作区文件。当然,如果您对工作区文件进行了不必要的更改,那么风险更大,但在这种情况下,如果您想从头开始重新开始,则仍然会在注释中包含代码。

答案 5 :(得分:3)

如果不详细说明,我通常会采用以下三种方法之一:

  1. 在整个执行过程中,使用assign为每个重要对象指定唯一名称。然后在每个函数的顶部包含一个if(exists(...)) get(...)以获取值,或者重新计算它。 (与Dirk的建议相同)
  2. cacheSweaveSweave文件一起使用。这为您提供缓存计算的所有工作并自动检索它们。使用它真的很简单:只需使用cacheSweave驱动程序并将此标志添加到每个块:<<..., cache=true>>=
  3. 使用saveload在关键时刻保存环境,再次确保所有名称都是唯一的。

答案 6 :(得分:-1)

'mustashe'软件包非常适合此类问题。除了缓存结果之外,它还可以包含指向依赖项的链接,以便在依赖项发生更改时重新运行代码。

披露:我写了这个工具('mustashe'),尽管我并没有从使用它的其他人那里获得任何经济利益。我正是出于自己的工作而制作的,并希望与他人分享。

下面是一个简单的示例。 foo变量已创建并“隐藏”以备后用。如果重新运行相同的代码,则会从磁盘加载foo变量并将其添加到全局环境。

library(mustashe)

stash("foo", {
    foo <- some_long_running_opperation(1e3)
}
#> Stashing object.

该文档还提供了更多有关更复杂用例的示例,并详细说明了其幕后工作方式。