2012-07-06 42 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