6

n我想使用记忆来缓存某些昂贵操作的结果,这样它们就不会被一遍又一遍地计算。

memoise和R.cache符合我的需要。但是,我发现缓存在调用之间并不可靠。

这是一个演示我看到的问题的示例:

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方法作为函数传递给memoizedCall. proto方法以难以适应的方式绑定到环境R.cache。在这种情况下,您需要做的是取消绑定函数(从实例化方法获取简单函数),然后手动将对象作为第一个参数传递。以下示例显示了它是如何工作的(两者Report都是Report$loader对象proto

# 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

2 回答 2

5

在您的代码中,每次调用该函数时都会重新对其进行记忆。以下应该有效:它只在定义时被记忆一次。

ProtoTester <- proto(
  calc = {
    fn <- function() print(runif(1))
    mfn <- memoise(fn)
    function(.) mfn()
  }
)
replicate(5, ProtoTester$calc())
于 2012-07-06T07:45:02.540 回答
3

另一种解决方案是使用(我的) pander 包evals进行评估,该包具有内部(在当前 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 方法的警告。

于 2012-07-06T08:01:44.990 回答