2012-07-06 76 views
4

nI想使用memoization来缓存某些昂贵操作的结果,以免它们一遍又一遍地被重复计算。R:缓存/环境备份

memoise和​​3210符合我的需求。但是,我发现缓存在呼叫中不稳健。

下面是一个说明我看到了问题的一个例子:基于答案

library(memoise) 

# Memoisation works: b() is called only once 
a <- function(x) runif(1) 
replicate(5, a()) 
b <- memoise(a) 
replicate(5, b()) 

# Memoisation fails: mfn() is called every single time 
ProtoTester <- proto(
    calc = function(.) { 
    fn <- function() print(runif(1)) 
    mfn <- memoise(fn) 
    invisible(mfn()) 
    }  
) 
replicate(5, ProtoTester$calc()) 

更新

这个问题可以基于持久或非持久的缓存是否有不同的答案用过的。非永久性缓存(例如memoise可能需要单独分配,然后下面的答案是一个不错的方法。持久性缓存(例如R.cache)适用于多个分配,应该是对于多个分配的健壮性。上述方法适用于R.cache。尽管有多个作业,fn只能用R.cache调用一次。它将被调用memoise两次。

> ProtoTester <- proto(
+  calc = function(.) { 
+   fn <- function() print(runif(1)) 
+   invisible(memoizedCall(fn)) 
+  }  
+) 
> replicate(5, ProtoTester$calc()) 
[1] 0.977563 
[1] 0.1279641 
[1] 0.01358866 
[1] 0.9993092 
[1] 0.3114813 
[1] 0.97756303 0.12796408 0.01358866 0.99930922 0.31148128 
> ProtoTester <- proto(
+  calc = function(.) { 
+   fn <- function() print(runif(1)) 
+   invisible(memoizedCall(fn)) 
+  }  
+) 
> replicate(5, ProtoTester$calc()) 
[1] 0.97756303 0.12796408 0.01358866 0.99930922 0.31148128 

为什么我认为我有一个问题,R.cache的原因是,我传递一个proto方法的功能memoizedCallproto方法被绑定到环境的方式,R.cache很难。在这种情况下你必须做的是取消绑定函数(从实例化的方法获得一个简单的函数),然后手动传递该对象作为第一个参数。下面的示例演示如何工作(包括ReportReport$loaderproto对象:

# This will not memoize the call 
memoizedCall(Report$loader$download_report) 

# This works as intended 
memoizedCall(with(Report$loader, download_report), Report$loader) 

我很想知道为什么R.cache作品绑定到环境中的正常功能,但无法与proto实例化的方法

回答

4

在你的代码,函数每次被调用时都会被重新记忆 以下内容应该工作:定义时只记忆一次

ProtoTester <- proto(
    calc = { 
    fn <- function() print(runif(1)) 
    mfn <- memoise(fn) 
    function(.) mfn() 
    } 
) 
replicate(5, ProtoTester$calc()) 
+0

我误解了memoise实现使用的对象标识机制。因为'R.缓存'具有与记忆相关的持久性我认为它的设计基于功能的内容/代码而不是其内部的R ID,否则它不会跨会话工作。以memoization作为副作用创建表达式是一个很好的模式。你的代码甚至可以在任务分配(多次执行多次分配'fn'的ProtoTester分配)时使用'R.cache'工作。我想知道为什么它以前不适合我... – Sim 2012-07-06 16:18:39

+0

我再次检查并发现'R.cache'与我的旧代码一起工作。我一定忽略了一件简单的事情。 – Sim 2012-07-06 16:20:58

+0

我更新了问题并澄清了涉及持久性时的行为差异。 – Sim 2012-07-06 16:33:52

3

另一种解决办法是使用evals评价从(我)pander package其具有内部(临时在当前R对话持久与磁盘存储的环境中)缓存引擎。短例如基于代码:

library(pander) 
ProtoTester <- proto(
    calc = function(.) { 
    fn <- function() runif(1) 
    mfn <- evals('fn()')[[1]]$result 
    invisible(mfn) 
    }  
) 

而且具有高速缓存运行evals和关闭会导致:

> evals.option('cache', FALSE) 
> replicate(5, ProtoTester$calc()) 
[1] 0.7152186 0.4529955 0.4160411 0.1166872 0.8776698 

> evals.option('cache', TRUE) 
> evals.option('cache.time', 0) 
> replicate(5, ProtoTester$calc()) 
[1] 0.7716874 0.7716874 0.7716874 0.7716874 0.7716874 

请注意,evals.option功能SI重命名为evalsOption很快缓解R CMD check警告关于S3方法。

+0

谢谢,我会检查出来。 – Sim 2012-07-06 16:22:01