3

在 RI 中工作时,通常会创建许多中间数据帧,这些数据帧会在代码执行期间被保存下来。如果我需要重新启动脚本或它崩溃,这允许我避免重新计算中间数据帧。我的代码通常以大量这些丑陋的 if/else 检查结束,以查看中间数据帧是否已经存在。

data <- NULL
pathToData <- "work/data.rds"
if(file.exists(pathToData)) {
   # load the previously calculated data
   data <- readRDS(pathToData)

} else { 
   # calculate the data
   data <- ...  
   saveRDS(data, pathToData)
}

有没有更好/更简单的方法来做到这一点?理想情况下,这可以以在代码中透明的方式完成。

4

3 回答 3

4

一种选择是将丑陋的代码包装在一个函数中,并将中间步骤包装在其他函数中。这具有使您的测试更容易的优点,并且在脚本上使用函数被认为是可重现数据分析的最佳实践。

calcData <- function(...) {
  #calculate the data
}

lazyCalc <- function(fn, ...) {
  if(file.exists(fn)) {
    data <- readRDS(fn)
  } else {
     calcData(...)
  return(data)
}
于 2013-08-12T20:04:14.367 回答
1

一种选择是使用带有缓存的 knitr 包。

您可以创建一个完整的 knitr 模板文件,其中包含您的脚本和其他内容,并将您不想重新运行的块设置为缓存,然后如果该块中的代码发生更改,它们只会第二次运行。

您也可以spin在脚本文件上使用来自 knitr 的函数,然后 knitr 将查看特殊格式的注释以设置 knitr 选项(其他所有内容基本上都将被视为常规脚本文件)。我没有尝试设置缓存信息,spin但它可能对你有用。

于 2013-08-12T22:51:29.097 回答
0

Drew Steen 的回答非常接近。我将他的函数定义与他建议的 eval() 使用配对。这正是我一直在寻找的。

cache <- function(cacheName, expr, cacheDir="work", clearCache=F) {
    result <- NULL

    # create the cache directory, if necessary
    dir.create(path=cacheDir, showWarnings=FALSE)
    cacheFile <- sprintf("%s/%s.rds", cacheDir, cacheName)

    # has the result already been cached?
    if(file.exists(cacheFile) && clearCache==F) {
        result <- readRDS(cacheFile)

    # eval the expression and cache its result
    } else {
        result <- eval(expr)
        saveRDS(result, cacheFile)
    }

    return(result)
}

这使我可以缓存单个函数调用...

result <- cache("foo", foo())

或更复杂的表达式/代码块...

results <- cache("foo", {
   f <- foo()
   r <- f + 2
   return(r)
})
于 2013-08-14T13:45:50.620 回答