首页 > 解决方案 > 缓存函数中生成的计算量大的对象的正确方法

问题描述

背景

在以下场景中,我正在查看以下工作流程:

  1. 顶级运行器函数,在下面的示例中running_function,调用了许多较小的函数。
  2. 其中一些函数在计算上是可扩展的,并且将在同一组参数上重复调用,因为顶级脚本据称调用了运行器函数

例子

在不尝试缓存对象的情况下,情况可以总结如下:

工作职能

painful_function <- function(n = 100) {
  matrix(1:n * n, nrow = n)
}

running_function <-
  function(stat_to_do = c("min", "max", "mean", "sum"),
           painful_size = 1e4) {
    stat_to_do <- match.arg(stat_to_do)

    M_pain <- painful_function(n = painful_size)
    do.call(stat_to_do, list(M_pain))

  }

实际工作

# Object M_pain is created inside running_function
running_function(stat_to_do = "min", painful_size = 100)
# I would like to re-use the M_pain object from the previous function
running_function(stat_to_do = "max", painful_size = 100)
# Re-using M_pain again...
running_function(stat_to_do = "mean", painful_size = 100)
# And again ...
running_function(stat_to_do = "sum", painful_size = 100)

期望的结果

这个想法是不要painful_function多次调用它,因为它生成的对象在每个场景中都是相同的。running_function应该使用提供的参数进行评估。

方法

我正在考虑使用mustashe包:

library("mustashe")
running_function_mstash <-
  function(stat_to_do = c("min", "max", "mean", "sum"),
           painful_size = 1e4) {
    stat_to_do <- match.arg(stat_to_do)

    stash(var = "M_pain",
          code = {
            painful_function(n = painful_size)
          },
          depends_on = "painful_size")
    do.call(stat_to_do, list(M_pain))
}

这将返回以下错误:

running_function_mstash(stat_to_do = "min", painful_size = 1e6)

make_hash(depends_on, .TargetEnv) 中的错误:环境中缺少一些依赖项。

问题

我有兴趣学习以下内容:

  1. 如何使这项工作,即只有在传递的参数之一发生变化running_function时才会执行painful_function,如果不是,则结果对象是从文件中存储的
  2. 有什么更好的方法来使用它。一个微不足道的“蛮力”方法是创建一个具有时髦名称的临时 RDS,并且仅painful_function在文件不存在时执行。这种蹩脚的方法并且有明显的缺点。我想找到一个涵盖类似、可行场景的强大解决方案。

标签: rcachingscoping

解决方案


可能是没有检测到对象。根据中的例子?stash,我们需要使用<<-

running_function_mstash <-
  function(stat_to_do = c("min", "max", "mean", "sum"),
           painful_size = 1e4) {
    stat_to_do <- match.arg(stat_to_do)
    painful_size <<- painful_size
    stash(var = "M_pain",
          code = {
            painful_function(n = painful_size)
          },
          depends_on = "painful_size")
    do.call(stat_to_do, list(M_pain))
}

running_function_mstash(stat_to_do = "min", painful_size = 1e6)
#Stashing object.
#[1] 1e+06

推荐阅读